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
357 changed files with 31343 additions and 45210 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,12 +1,12 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(PIP) project(pip)
set(PIP_MAJOR 3) set(pip_MAJOR 2)
set(PIP_MINOR 15) set(pip_MINOR 39)
set(PIP_REVISION 2) set(pip_REVISION 0)
set(PIP_SUFFIX ) set(pip_SUFFIX )
set(PIP_COMPANY SHS) set(pip_COMPANY SHS)
set(PIP_DOMAIN org.SHS) set(pip_DOMAIN org.SHS)
set(GIT_CMAKE_DIR) set(GIT_CMAKE_DIR)
if (NOT DEFINED SHSTKPROJECT) if (NOT DEFINED SHSTKPROJECT)
@@ -17,7 +17,7 @@ cmake_minimum_required(VERSION 2.8.2)
project(cmake-download NONE) project(cmake-download NONE)
include(ExternalProject) include(ExternalProject)
ExternalProject_Add(cmake 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_TAG \"origin/master\"
GIT_CONFIG \"advice.detachedHead=false\" GIT_CONFIG \"advice.detachedHead=false\"
SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\" SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\"
@@ -53,7 +53,7 @@ include(CheckFunctionExists)
include(PIPMacros) include(PIPMacros)
include(SHSTKMacros) include(SHSTKMacros)
shstk_begin_project(PIP) shstk_begin_project(pip PIP)
set(_ICU_DEFAULT OFF) set(_ICU_DEFAULT OFF)
if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE)) if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE))
@@ -61,21 +61,14 @@ if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE
endif() endif()
set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "") 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 # Options
option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT}) option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT})
option(STD_IOSTREAM "Building with std iostream operators support" OFF) option(STD_IOSTREAM "Building with std iostream operators support" OFF)
option(INTROSPECTION "Build with introspection" 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) option(COVERAGE "Build project with coverage info" OFF)
set(PIP_UTILS 1) set(PIP_UTILS 1)
set(BUILDING_pip 1 PARENT_SCOPE)
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE) set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
@@ -103,7 +96,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
set(CRES) set(CRES)
file(GLOB_RECURSE CPPS "libs/${NAME}/*.cpp" "libs/${NAME}/*.c") file(GLOB_RECURSE CPPS "libs/${NAME}/*.cpp" "libs/${NAME}/*.c")
file(GLOB_RECURSE HS "libs/${NAME}/*.h") 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") file(GLOB_RECURSE RES "libs/${NAME}/*.conf")
if (NOT "x${PHS}" STREQUAL "x") if (NOT "x${PHS}" STREQUAL "x")
list(REMOVE_ITEM HS ${PHS}) list(REMOVE_ITEM HS ${PHS})
@@ -112,14 +105,9 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
file(GLOB_RECURSE ASRC "${SOURCES}/*.cpp" "${SOURCES}/*.c") file(GLOB_RECURSE ASRC "${SOURCES}/*.cpp" "${SOURCES}/*.c")
list(APPEND CPPS ${ASRC}) list(APPEND CPPS ${ASRC})
endif() endif()
#message("${NAME} HS = ${HS}")
list(APPEND HDRS ${HS}) list(APPEND HDRS ${HS})
list(APPEND PHDRS ${PHS}) 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(_target "pip_${NAME}")
set(_libs "${LIBS}") set(_libs "${LIBS}")
if ("${NAME}" STREQUAL "main") if ("${NAME}" STREQUAL "main")
@@ -130,11 +118,11 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
string(TOUPPER "${_target}" DEF_NAME) string(TOUPPER "${_target}" DEF_NAME)
set(PIP_MSG_${NAME} "yes${MSG}") set(PIP_MSG_${NAME} "yes${MSG}")
import_version(${_target} PIP) import_version(${_target} pip)
set_deploy_property(${_target} ${PIP_LIB_TYPE} set_deploy_property(${_target} ${pip_LIB_TYPE}
LABEL "${LABEL}" LABEL "${LABEL}"
FULLNAME "${PIP_DOMAIN}.${_target}" FULLNAME "${pip_DOMAIN}.${_target}"
COMPANY "${PIP_COMPANY}" COMPANY "${pip_COMPANY}"
INFO "Platform-Independent Primitives") INFO "Platform-Independent Primitives")
make_rc(${_target} _RC) make_rc(${_target} _RC)
@@ -151,7 +139,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
pip_resources(CRES "${RES}") pip_resources(CRES "${RES}")
endif() endif()
add_definitions(-D${DEF_NAME}) 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}) target_include_directories(${_target} PUBLIC ${PIP_INCLUDES})
if (NOT "x${RES}" STREQUAL "x") if (NOT "x${RES}" STREQUAL "x")
add_dependencies(${_target} pip_rc) add_dependencies(${_target} pip_rc)
@@ -260,10 +248,12 @@ CHECK_FUNCTION_EXISTS(timer_delete PIP_TIMER_RT_2)
# Check if build debug version # 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") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
add_definitions(-DPIP_DEBUG) add_definitions(-DPIP_DEBUG)
else() else()
set(PIP_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall")
endif() endif()
@@ -458,16 +448,17 @@ if (NOT CROSSTOOLS)
endif() endif()
if (NOT "x${MINGW_INCLUDE}" STREQUAL "x")
list(APPEND CMAKE_INCLUDE_PATH "${MINGW_INCLUDE}")
endif()
find_package(OpenCL QUIET) #OpenCL_VERSION_STRING find_package(OpenCL QUIET) #OpenCL_VERSION_STRING
if(OpenCL_FOUND) 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}") set(_opencl_inc "${OpenCL_INCLUDE_DIRS}")
if(APPLE) if(APPLE)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers") set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
endif() 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() endif()
@@ -490,18 +481,14 @@ if (NOT CROSSTOOLS)
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge") list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
list(APPEND HDRS ${_lua_src_hdr}) list(APPEND HDRS ${_lua_src_hdr})
# Test program # Test program
if(PIP_UTILS) if(PIP_UTILS)
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp")
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp" "ccm.h" "ccm.cpp")
#target_link_libraries(pip_plugin pip) #target_link_libraries(pip_plugin pip)
add_executable(pip_test "main.cpp") add_executable(pip_test "main.cpp")
target_link_libraries(pip_test pip) target_link_libraries(pip_test pip)
if(sodium_FOUND)
add_executable(pip_cloud_test "main_picloud_test.cpp")
target_link_libraries(pip_cloud_test pip_cloud)
endif()
endif() endif()
else() else()
@@ -575,7 +562,6 @@ if(NOT PIP_FREERTOS)
add_subdirectory("utils/code_model_generator") add_subdirectory("utils/code_model_generator")
add_subdirectory("utils/resources_compiler") add_subdirectory("utils/resources_compiler")
add_subdirectory("utils/deploy_tool") add_subdirectory("utils/deploy_tool")
add_subdirectory("utils/value_tree_translator")
if(PIP_UTILS AND (NOT CROSSTOOLS)) if(PIP_UTILS AND (NOT CROSSTOOLS))
add_subdirectory("utils/system_test") add_subdirectory("utils/system_test")
add_subdirectory("utils/udp_file_transfer") add_subdirectory("utils/udp_file_transfer")
@@ -606,14 +592,14 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
string(TOUPPER "${_m}" _mdef) string(TOUPPER "${_m}" _mdef)
list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT") list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
endforeach() endforeach()
set(DOXY_PROJECT_NUMBER "${PIP_VERSION}") set(DOXY_PROJECT_NUMBER "${pip_VERSION}")
set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"") set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${pip_VERSION}\"")
set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"") set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${pip_VERSION}\"")
set(DOXY_EXAMPLE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"") set(DOXY_EXAMPLE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"")
set(DOXY_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"") set(DOXY_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"")
set(DOXY_LOGO_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"") set(DOXY_LOGO_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"")
set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"") 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") if ("x${DOC_LANG}" STREQUAL "x")
set(DOXY_OUTPUT_LANGUAGE English) set(DOXY_OUTPUT_LANGUAGE English)
set(DOXY_OUTPUT_DIR en) set(DOXY_OUTPUT_DIR en)
@@ -659,9 +645,9 @@ endmacro()
list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES}) list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES})
message("----------PIP----------") message("----------PIP----------")
message(" Version: ${PIP_VERSION} ") message(" Version: ${pip_VERSION} ")
message(" Linkage: ${PIP_LIB_TYPE_MSG}") message(" Linkage: ${pip_LIB_TYPE_MSG}")
message(" Type : ${CMAKE_BUILD_TYPE}") message(" Type : ${pip_BUILD_TYPE}")
if (NOT LOCAL) if (NOT LOCAL)
message(" Install: \"${CMAKE_INSTALL_PREFIX}\"") message(" Install: \"${CMAKE_INSTALL_PREFIX}\"")
else() else()

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

@@ -18,9 +18,8 @@
*/ */
#include "picloudtcp.h" #include "picloudtcp.h"
#include "pichunkstream.h"
#include "picrypt.h" #include "picrypt.h"
#include "pichunkstream.h"
#include "piethernet.h" #include "piethernet.h"
#include "pistreampacker.h" #include "pistreampacker.h"
@@ -44,8 +43,7 @@ void PICloud::TCP::setRole(PICloud::TCP::Role r) {
void PICloud::TCP::setServerName(const PIString & server_name_) { void PICloud::TCP::setServerName(const PIString & server_name_) {
server_name = server_name_; server_name = server_name_;
suuid = suuid = PICrypt::hash(PIByteArray(server_name_.data(), server_name_.size()), (const unsigned char *)hash_cloud_key, sizeof(hash_cloud_key));
PICrypt::hash(PIByteArray(server_name_.data(), server_name_.size()), (const unsigned char *)hash_cloud_key, sizeof(hash_cloud_key));
} }
@@ -134,8 +132,7 @@ PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteA
PICloud::TCP::Header hdr; PICloud::TCP::Header hdr;
ba >> hdr; ba >> hdr;
if (hdr.version != header.version) { if (hdr.version != header.version) {
piCout << "[PICloud]" piCout << "[PICloud]" << "invalid PICloud::TCP version!";
<< "invalid PICloud::TCP version!";
return ret; return ret;
} }
ret.first = (Type)hdr.type; ret.first = (Type)hdr.type;
@@ -171,14 +168,14 @@ PIByteArray PICloud::TCP::parseConnect_d(PIByteArray & ba) {
uint PICloud::TCP::parseConnect(PIByteArray & ba) { uint PICloud::TCP::parseConnect(PIByteArray & ba) {
uint ret = 0; uint ret;
ba >> ret; ba >> ret;
return ret; return ret;
} }
uint PICloud::TCP::parseDisconnect(PIByteArray & ba) { uint PICloud::TCP::parseDisconnect(PIByteArray & ba) {
uint ret = 0; uint ret;
ba >> ret; ba >> ret;
return ret; return ret;
} }

View File

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

View File

@@ -17,15 +17,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreen.h" #include "piscreen.h"
#include "piincludes_p.h" #include "piincludes_p.h"
#ifndef WINDOWS #ifndef WINDOWS
# include <fcntl.h>
# include <sys/ioctl.h> # include <sys/ioctl.h>
# include <fcntl.h>
# include <termios.h> # include <termios.h>
#else #else
# include <wincon.h>
# include <wingdi.h> # include <wingdi.h>
# include <wincon.h>
# ifndef COMMON_LVB_UNDERSCORE # ifndef COMMON_LVB_UNDERSCORE
# define COMMON_LVB_UNDERSCORE 0x8000 # define COMMON_LVB_UNDERSCORE 0x8000
# endif # endif
@@ -52,18 +51,6 @@ PRIVATE_DEFINITION_END(PIScreen::SystemConsole)
PIScreen::SystemConsole::SystemConsole() { PIScreen::SystemConsole::SystemConsole() {
width = height = pwidth = pheight = 0; width = height = pwidth = pheight = 0;
mouse_x = mouse_y = -1; mouse_x = mouse_y = -1;
}
PIScreen::SystemConsole::~SystemConsole() {
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
#endif
}
void PIScreen::SystemConsole::begin() {
int w, h; int w, h;
#ifdef WINDOWS #ifdef WINDOWS
PRIVATE->ulcoord.X = 0; PRIVATE->ulcoord.X = 0;
@@ -87,6 +74,18 @@ void PIScreen::SystemConsole::begin() {
# endif # endif
#endif #endif
resize(w, h); 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 #ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT); SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
@@ -94,7 +93,6 @@ void PIScreen::SystemConsole::begin() {
PRIVATE->bc.Y = 0; PRIVATE->bc.Y = 0;
#endif #endif
clear(); clear();
clearScreen();
hideCursor(); hideCursor();
} }
@@ -245,14 +243,10 @@ void PIScreen::SystemConsole::print() {
#define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) #define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) { ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
WORD attr = PRIVATE->dattr; WORD attr = PRIVATE->dattr;
if (c.format.flags & Bold) if (c.format.flags & Bold) attr |= FOREGROUND_INTENSITY;
attr |= FOREGROUND_INTENSITY; else attr &= ~FOREGROUND_INTENSITY;
else if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE;
attr &= ~FOREGROUND_INTENSITY; else attr &= ~COMMON_LVB_UNDERSCORE;
if (c.format.flags & Underline)
attr |= COMMON_LVB_UNDERSCORE;
else
attr &= ~COMMON_LVB_UNDERSCORE;
switch (c.format.color_char) { switch (c.format.color_char) {
case Black: attr = (attr & ~FOREGROUND_MASK); break; case Black: attr = (attr & ~FOREGROUND_MASK); break;
case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break; case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break;
@@ -297,8 +291,7 @@ void PIScreen::SystemConsole::clearLine() {
void PIScreen::SystemConsole::newLine() { void PIScreen::SystemConsole::newLine() {
getWinCurCoord(); getWinCurCoord();
PRIVATE->ccoord.X = 0; PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++;
PRIVATE->ccoord.Y++;
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
} }
#else // WINDOWS #else // WINDOWS
@@ -364,16 +357,8 @@ void PIScreen::SystemConsole::clearScreen() {
void PIScreen::SystemConsole::clearScreenLower() { void PIScreen::SystemConsole::clearScreenLower() {
#ifdef WINDOWS #ifdef WINDOWS
getWinCurCoord(); getWinCurCoord();
FillConsoleOutputAttribute(PRIVATE->hOut, FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
PRIVATE->dattr, FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
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 #else
printf("\e[0m\e[J"); printf("\e[0m\e[J");
#endif #endif
@@ -398,7 +383,7 @@ void PIScreen::SystemConsole::showCursor() {
} }
// PIScreen
PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") { PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") {
setName("screen"); setName("screen");
@@ -406,17 +391,18 @@ PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawe
needLockRun(true); needLockRun(true);
mouse_ = false; mouse_ = false;
ret_func = slot; ret_func = slot;
tile_focus = tile_dialog = nullptr; tile_focus = tile_dialog = 0;
root.screen = this; root.screen = this;
listener = new PIKbdListener(key_eventS, this, startNow); listener = new PIKbdListener(key_eventS, this, startNow);
CONNECT1(void, PIKbdListener::MouseEvent, listener, mouseEvent, this, mouse_event); CONNECTU(listener, mouseEvent, this, mouse_event);
CONNECT1(void, PIKbdListener::WheelEvent, listener, wheelEvent, this, wheel_event); CONNECTU(listener, wheelEvent, this, wheel_event);
if (startNow) start(); if (startNow) start();
} }
PIScreen::~PIScreen() { PIScreen::~PIScreen() {
if (isRunning()) stop(); if (isRunning())
stop();
PIThread::waitForFinish(10); PIThread::waitForFinish(10);
listener->waitForFinish(10); listener->waitForFinish(10);
delete listener; delete listener;
@@ -436,12 +422,14 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
return; return;
*/ */
PIScreenTile * rtile = rootTile(); PIScreenTile * rtile = rootTile();
if (tile_dialog) rtile = tile_dialog; if (tile_dialog)
rtile = tile_dialog;
bool used = nextFocus(rtile, key); bool used = nextFocus(rtile, key);
if (used) return; if (used) return;
if (!used && tile_focus) { if (!used && tile_focus) {
if (tile_focus->visible) { if (tile_focus->visible) {
if (tile_focus->keyEvent(key)) return; if (tile_focus->keyEvent(key))
return;
} }
} }
if (ret_func != 0) ret_func(key, data_); if (ret_func != 0) ret_func(key, data_);
@@ -467,6 +455,7 @@ PIVector<PIScreenTile *> PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
ff = true; ff = true;
} }
} }
} }
return tl; return tl;
} }
@@ -499,13 +488,15 @@ void PIScreen::wheel_event(PIKbdListener::WheelEvent we) {
if (tl.isEmpty()) return; if (tl.isEmpty()) return;
piForeachR (PIScreenTile * t, tl) piForeachR (PIScreenTile * t, tl)
if (t->wheelEvent(we)) break; if (t->wheelEvent(we)) break;
} }
bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) { bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
PIVector<PIScreenTile*> vtl = rt->children(true), ftl; PIVector<PIScreenTile*> vtl = rt->children(true), ftl;
piForeach (PIScreenTile * t, vtl) { piForeach (PIScreenTile * t, vtl) {
if (t->focus_flags[CanHasFocus]) ftl << t; if (t->focus_flags[CanHasFocus])
ftl << t;
} }
int ind = -1; int ind = -1;
for (int i = 0; i < ftl.size_s(); ++i) for (int i = 0; i < ftl.size_s(); ++i)
@@ -513,15 +504,18 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
ind = i; ind = i;
break; break;
} }
if (ind < 0) tile_focus = 0; if (ind < 0)
tile_focus = 0;
if (ftl.isEmpty()) if (ftl.isEmpty())
tile_focus = 0; tile_focus = 0;
else { else {
if (tile_focus) if (tile_focus)
if (!tile_focus->visible) tile_focus = 0; if (!tile_focus->visible)
tile_focus = 0;
int next = tile_focus ? 0 : 1; int next = tile_focus ? 0 : 1;
if (tile_focus) { 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 (tile_focus->focus_flags[NextByArrowsHorizontal]) {
if (key.key == PIKbdListener::LeftArrow) next = -1; if (key.key == PIKbdListener::LeftArrow) next = -1;
if (key.key == PIKbdListener::RightArrow) next = 1; if (key.key == PIKbdListener::RightArrow) next = 1;
@@ -556,19 +550,22 @@ void PIScreen::tileEventInternal(PIScreenTile * t, TileEvent e) {
void PIScreen::tileRemovedInternal(PIScreenTile * t) { void PIScreen::tileRemovedInternal(PIScreenTile * t) {
if (tile_dialog == t) tile_dialog = 0; if (tile_dialog == t)
tile_dialog = 0;
} }
void PIScreen::tileSetFocusInternal(PIScreenTile * t) { void PIScreen::tileSetFocusInternal(PIScreenTile * t) {
PIScreenTile * rt = rootTile(); PIScreenTile * rt = rootTile();
if (tile_dialog) rt = tile_dialog; if (tile_dialog)
rt = tile_dialog;
PIVector<PIScreenTile*> tl = rt->children(), ftl; PIVector<PIScreenTile*> tl = rt->children(), ftl;
piForeach (PIScreenTile * i, tl) piForeach (PIScreenTile * i, tl)
i->has_focus = false; i->has_focus = false;
tile_focus = t; tile_focus = t;
if (!tile_focus) return; 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,7 +588,7 @@ void PIScreen::waitForFinish() {
void PIScreen::stop(bool clear) { void PIScreen::stop(bool clear) {
PIThread::stopAndWait(); PIThread::stop(true);
if (clear) console.clearScreen(); if (clear) console.clearScreen();
#ifndef WINDOWS #ifndef WINDOWS
fflush(0); fflush(0);
@@ -623,13 +620,8 @@ void PIScreen::run() {
tile_dialog->height_ = sh; tile_dialog->height_ = sh;
tile_dialog->layout(); tile_dialog->layout();
int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_; int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_;
drawer_.drawFrame(dx, drawer_.drawFrame(dx, dy, dx + dw + 1, dy + dh + 1, (Color)tile_dialog->back_format.color_char,
dy, (Color)tile_dialog->back_format.color_back, (CharFlags)tile_dialog->back_format.flags);
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_); tile_dialog->drawEventInternal(&drawer_);
} }
console.print(); console.print();
@@ -645,6 +637,8 @@ void PIScreen::end() {
PIScreenTile * PIScreen::tileByName(const PIString & name) { PIScreenTile * PIScreen::tileByName(const PIString & name) {
PIVector<PIScreenTile*> tl(tiles()); PIVector<PIScreenTile*> tl(tiles());
piForeach (PIScreenTile * t, tl) piForeach (PIScreenTile * t, tl)
if (t->name() == name) return t; if (t->name() == name)
return t;
return 0; return 0;
} }

View File

@@ -27,9 +27,16 @@ TileVars::TileVars(const PIString & n): PIScreenTile(n) {
} }
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

@@ -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; float dy = (y1 - y0) / float(piAbsi(x1 - x0)), cy = y0;
int dx = x0 < x1 ? 1 : -1; int dx = x0 < x1 ? 1 : -1;
for (int i = x0; i != x1; i += dx) { for (int i = x0; i != x1; i += dx) {
x = i; x = i; y = piRound(cy);
y = piRound(cy); if (x >= 0 && x < width && y >= 0 && y < height)
if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc; cells[y][x] = cc;
cy += dy; cy += dy;
} }
y = piRound(cy); 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 { } else {
float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0; float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0;
int dy = y0 < y1 ? 1 : -1; int dy = y0 < y1 ? 1 : -1;
for (int i = y0; i != y1; i += dy) { for (int i = y0; i != y1; i += dy) {
x = piRound(cx); x = piRound(cx); y = i;
y = i; if (x >= 0 && x < width && y >= 0 && y < height)
if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc; cells[y][x] = cc;
cx += dx; cx += dx;
} }
x = piRound(cx); 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) { if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]); PIVector<Cell> & cv(cells[j]);
for (int i = x0; i != x1; i += dx) 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]; j = xs[k];
if (j >= 0 && j < width) { if (j >= 0 && j < width) {
for (int i = y0; i != y1; i += dy) 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; 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]); PIVector<Cell> & cv(cells[j]);
cc.symbol = artChar(LineHorizontal); cc.symbol = artChar(LineHorizontal);
for (int i = x0 + 1; i != x1; i += dx) 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]; j = xs[k];
if (j >= 0 && j < width) { if (j >= 0 && j < width) {
cc.symbol = artChar(LineVertical); cc.symbol = artChar(LineVertical);
for (int i = y0 + 1; i != y1; i += dy) 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; int i = x0, j = y0; cc.symbol = artChar(CornerTopLeft);
cc.symbol = artChar(CornerTopLeft);
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;
i = x1, j = y0; i = x1, j = y0; cc.symbol = artChar(CornerTopRight);
cc.symbol = artChar(CornerTopRight);
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;
i = x0, j = y1; i = x0, j = y1; cc.symbol = artChar(CornerBottomLeft);
cc.symbol = artChar(CornerBottomLeft);
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;
i = x1, j = y1; i = x1, j = y1; cc.symbol = artChar(CornerBottomRight);
cc.symbol = artChar(CornerBottomRight);
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;
} }
@@ -221,7 +224,8 @@ void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, const PIChar & c,
if (j >= 0 && j < height) { if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]); PIVector<Cell> & cv(cells[j]);
for (int i = x0; i != x1; i += dx) for (int i = x0; i != x1; i += dx)
if (i >= 0 && i < width) cv[i] = cc; if (i >= 0 && i < width)
cv[i] = cc;
} }
} }
@@ -237,7 +241,8 @@ void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<
PIVector<Cell> & cv(cells[y0 + j]); PIVector<Cell> & cv(cells[y0 + j]);
PIVector<Cell> & contv(content[j]); PIVector<Cell> & contv(content[j]);
for (int i = 0; i < piMini(w, contv.size_s()); ++i) 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];
} }
} }
} }

View File

@@ -18,7 +18,6 @@
*/ */
#include "piscreentile.h" #include "piscreentile.h"
#include "piscreendrawer.h" #include "piscreendrawer.h"
@@ -42,7 +41,8 @@ PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObj
PIScreenTile::~PIScreenTile() { PIScreenTile::~PIScreenTile() {
//piCout << this << "~"; //piCout << this << "~";
if (screen) screen->tileRemovedInternal(this); if (screen)
screen->tileRemovedInternal(this);
setScreen(0); setScreen(0);
deleteChildren(); deleteChildren();
if (!parent) return; if (!parent) return;
@@ -79,7 +79,8 @@ void PIScreenTile::removeTile(PIScreenTile * t) {
PIVector<PIScreenTile * > PIScreenTile::children(bool only_visible) { PIVector<PIScreenTile * > PIScreenTile::children(bool only_visible) {
PIVector<PIScreenTile * > ret; PIVector<PIScreenTile * > ret;
piForeach (PIScreenTile * t, tiles) piForeach (PIScreenTile * t, tiles)
if (t->visible || !only_visible) ret << t << t->children(only_visible); if (t->visible || !only_visible)
ret << t << t->children(only_visible);
return ret; return ret;
} }
@@ -87,7 +88,8 @@ PIVector<PIScreenTile *> PIScreenTile::children(bool only_visible) {
PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) { PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) {
piForeach (PIScreenTile * t, tiles) { piForeach (PIScreenTile * t, tiles) {
if (!t->visible) continue; 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; return t;
} }
} }
@@ -127,14 +129,7 @@ void PIScreenTile::drawEventInternal(PIScreenDrawer * d) {
if (!visible) { if (!visible) {
return; return;
} }
d->fillRect(x_, d->fillRect(x_, y_, x_ + width_, y_ + height_, back_symbol, (Color)back_format.color_char, (Color)back_format.color_back, back_format.flags);
y_,
x_ + width_,
y_ + height_,
back_symbol,
(Color)back_format.color_char,
(Color)back_format.color_back,
back_format.flags);
drawEvent(d); drawEvent(d);
piForeach (PIScreenTile * t, tiles) piForeach (PIScreenTile * t, tiles)
t->drawEventInternal(d); t->drawEventInternal(d);
@@ -146,10 +141,8 @@ void PIScreenTile::sizeHint(int & w, int & h) const {
h = 0; h = 0;
if (tiles.isEmpty()) return; if (tiles.isEmpty()) return;
int sl = spacing * (tiles.size_s() - 1); int sl = spacing * (tiles.size_s() - 1);
if (direction == Horizontal) if (direction == Horizontal) w += sl;
w += sl; else h += sl;
else
h += sl;
piForeachC (PIScreenTile * t, tiles) { piForeachC (PIScreenTile * t, tiles) {
if (!t->visible) continue; if (!t->visible) continue;
int cw(0), ch(0); int cw(0), ch(0);
@@ -157,11 +150,9 @@ void PIScreenTile::sizeHint(int & w, int & h) const {
cw = piClampi(cw, t->minimumWidth, t->maximumWidth); cw = piClampi(cw, t->minimumWidth, t->maximumWidth);
ch = piClampi(ch, t->minimumHeight, t->maximumHeight); ch = piClampi(ch, t->minimumHeight, t->maximumHeight);
if (direction == Horizontal) { if (direction == Horizontal) {
w += cw; w += cw; h = piMaxi(h, ch);
h = piMaxi(h, ch);
} else { } else {
h += ch; h += ch; w = piMaxi(w, cw);
w = piMaxi(w, cw);
} }
} }
w += marginLeft + marginRight; w += marginLeft + marginRight;
@@ -219,7 +210,8 @@ void PIScreenTile::layout() {
for (int j = 0; j < tiles.size_s(); ++j) { for (int j = 0; j < tiles.size_s(); ++j) {
if (i == j) continue; if (i == j) continue;
if (max_tl[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]; t->height_ = hints[i];
cy += hints[i] + spacing; 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->pw = t->width_;
t->ph = t->height_; t->ph = t->height_;
t->layout(); t->layout();

View File

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

View File

@@ -16,19 +16,17 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piterminal.h"
#include "piincludes_p.h" #include "piincludes_p.h"
#include "piterminal.h"
#include "pisharedmemory.h" #include "pisharedmemory.h"
#ifndef MICRO_PIP #ifndef MICRO_PIP
#ifdef WINDOWS #ifdef WINDOWS
# include <wincon.h>
# include <windows.h> # include <windows.h>
# include <wingdi.h> # include <wingdi.h>
# include <wincon.h>
# include <winuser.h> # include <winuser.h>
#else #else
# include "piprocess.h" # include "piprocess.h"
# include <csignal> # include <csignal>
# include <fcntl.h> # include <fcntl.h>
# include <sys/ioctl.h> # include <sys/ioctl.h>
@@ -125,7 +123,8 @@ PITerminal::PITerminal(): PIThread() {
PITerminal::~PITerminal() { PITerminal::~PITerminal() {
if (isRunning()) stop(); if (isRunning())
stop();
PIThread::waitForFinish(10); PIThread::waitForFinish(10);
destroy(); destroy();
#ifdef WINDOWS #ifdef WINDOWS
@@ -166,8 +165,7 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
default: break; default: break;
} }
//piCout << "write" << ba.size(); //piCout << "write" << ba.size();
if (!ba.isEmpty()) if (!ba.isEmpty()) write(ba);
write(ba);
else { else {
PIByteArray msg; PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke; PIVector<PIKbdListener::KeyEvent> ke;
@@ -187,8 +185,7 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
case PIKbdListener::UpArrow: case PIKbdListener::UpArrow:
case PIKbdListener::DownArrow: case PIKbdListener::DownArrow:
case PIKbdListener::RightArrow: case PIKbdListener::RightArrow:
case PIKbdListener::LeftArrow: case PIKbdListener::LeftArrow: if (PRIVATE->DEC.value(CKM, false)) flags = 1;
if (PRIVATE->DEC.value(CKM, false)) flags = 1;
/*case PIKbdListener::Home: //break; /*case PIKbdListener::Home: //break;
case PIKbdListener::End: //break; case PIKbdListener::End: //break;
case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break; case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break;
@@ -238,8 +235,7 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
void PITerminal::write(PIKbdListener::KeyEvent ke) { void PITerminal::write(PIKbdListener::KeyEvent ke) {
if (isSpecialKey(ke.key)) if (isSpecialKey(ke.key)) write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
else { else {
PIByteArray ba; PIByteArray ba;
#ifdef WINDOWS #ifdef WINDOWS
@@ -257,7 +253,8 @@ PIVector<PIVector<PIScreenTypes::Cell>> PITerminal::content() {
PIVector<PIVector<PIScreenTypes::Cell> > ret = cells; PIVector<PIVector<PIScreenTypes::Cell> > ret = cells;
if (cursor_blink && cursor_visible) if (cursor_blink && cursor_visible)
if (cursor_x >= 0 && cursor_x < size_x) 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; return ret;
} }
@@ -398,15 +395,16 @@ void PITerminal::run() {
} }
bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE; bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE;
if (PRIVATE->read_buf.size_s() == 1) 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) { if (parse) {
parseInput(PIString::fromUTF8(PRIVATE->read_buf)); parseInput(PIString(PRIVATE->read_buf));
PRIVATE->read_buf.clear(); 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()) { 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->read_buf.clear();
} }
PRIVATE->last_read = false; PRIVATE->last_read = false;
@@ -447,8 +445,7 @@ void PITerminal::parseInput(const PIString & s) {
if (s[i] == '\r') continue; if (s[i] == '\r') continue;
if (s[i] == '\n') { if (s[i] == '\n') {
//piCoutObj << "new line"; //piCoutObj << "new line";
for (int i = PRIVATE->cur_x; i < size_x; ++i) for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
moveCursor(0, 1); moveCursor(0, 1);
@@ -501,8 +498,7 @@ void PITerminal::applyEscSeq(PIString es) {
case 1047: case 1047:
if (val) { if (val) {
PRIVATE->cells_save = cells; PRIVATE->cells_save = cells;
for (int i = 0; i < size_y; ++i) for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
cells[i].fill(def_cell);
} else { } else {
cells = PRIVATE->cells_save; cells = PRIVATE->cells_save;
} }
@@ -528,14 +524,8 @@ void PITerminal::applyEscSeq(PIString es) {
default: { default: {
bool col = false, target = false; bool col = false, target = false;
int cid = av % 10; int cid = av % 10;
if (av >= 30 && av <= 37) { if (av >= 30 && av <= 37) {col = true; target = false;}
col = true; if (av >= 40 && av <= 47) {col = true; target = true;}
target = false;
}
if (av >= 40 && av <= 47) {
col = true;
target = true;
}
if (col) { if (col) {
int cfl = 0; int cfl = 0;
switch (cid) { switch (cid) {
@@ -596,29 +586,25 @@ void PITerminal::applyEscSeq(PIString es) {
} }
if (es.back() == 'A') { // cursor up if (es.back() == 'A') { // cursor up
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1); PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'B') { // cursor down if (es.back() == 'B') { // cursor down
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1); PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1); PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'D') { // cursor back if (es.back() == 'D') { // cursor back
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1); PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
@@ -630,91 +616,65 @@ void PITerminal::applyEscSeq(PIString es) {
} }
if (es.back() == 'd') { // goto line if (es.back() == 'd') { // goto line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1); PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'E' || es.back() == 'e') { // next line if (es.back() == 'E' || es.back() == 'e') { // next line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1); PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'F') { // previous line if (es.back() == 'F') { // previous line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1); PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'L') { // insert lines if (es.back() == 'L') { // insert lines
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
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 i = piClamp(size_y - 1, PRIVATE->win_y0, PRIVATE->win_y1); 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)
i >= piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell;
--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 if (es.back() == 'M') { // delete lines
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
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 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 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) for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell;
cells[j][i] = def_cell;
} }
if (es.back() == 'P') { // delete characters if (es.back() == 'P') { // delete characters
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
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 = PRIVATE->cur_x; i < size_x - v; ++i) for (int i = size_x - v; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
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 if (es.back() == '@') { // delete characters
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
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 = size_x - 1; i >= PRIVATE->cur_x + v; --i) for (int i = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i) cells[PRIVATE->cur_y][i] = def_cell;
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 if (es.back() == 'J') { // erase data
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt();
switch (v) { switch (v) {
case 0: case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i) for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
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_y + 1; i < size_y; ++i)
cells[i].fill(def_cell);
break; break;
case 1: case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i) for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
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_y; ++i)
cells[i].fill(def_cell);
break; break;
case 2: case 2:
for (int i = 0; i < size_y; ++i) for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
cells[i].fill(def_cell);
//PRIVATE->cur_x = PRIVATE->cur_y = 0; //PRIVATE->cur_x = PRIVATE->cur_y = 0;
break; break;
} }
@@ -724,14 +684,14 @@ void PITerminal::applyEscSeq(PIString es) {
int v = es.toInt(); int v = es.toInt();
switch (v) { switch (v) {
case 0: case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i) for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = def_cell;
break; break;
case 1: case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i) for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = def_cell; break;
case 2:
cells[PRIVATE->cur_y].fill(def_cell);
break; break;
case 2: cells[PRIVATE->cur_y].fill(def_cell); break;
} }
} }
} }
@@ -761,10 +721,8 @@ void PITerminal::moveCursor(int dx, int dy) {
int PITerminal::termType(const PIString & t) { int PITerminal::termType(const PIString & t) {
if (t == "xterm") if (t == "xterm") return PIKbdListener::vt_xterm;
return PIKbdListener::vt_xterm; else if (t == "linux") return PIKbdListener::vt_linux;
else if (t == "linux")
return PIKbdListener::vt_linux;
return PIKbdListener::vt_none; return PIKbdListener::vt_none;
} }
#endif #endif
@@ -809,28 +767,12 @@ bool PITerminal::initialize() {
PIString shmh = PIString::fromNumber(randomi() % 10000); PIString shmh = PIString::fromNumber(randomi() % 10000);
PIString pname = "\\\\.\\pipe\\piterm" + shmh; PIString pname = "\\\\.\\pipe\\piterm" + shmh;
PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\""; PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\"";
if (!CreateProcessA(0, if(!CreateProcessA(0, (LPSTR)cmd.dataAscii(), 0, 0, false, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, 0, 0, &PRIVATE->si, &PRIVATE->pi)) {
(LPSTR)cmd.dataAscii(),
0,
0,
false,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
0,
0,
&PRIVATE->si,
&PRIVATE->pi)) {
piCoutObj << "CreateProcess error," << errorString(); piCoutObj << "CreateProcess error," << errorString();
destroy(); destroy();
return false; return false;
} }
PRIVATE->pipe = CreateNamedPipeA((LPSTR)pname.dataAscii(), 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);
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) { if (PRIVATE->pipe == INVALID_HANDLE_VALUE) {
piCoutObj << "CreateNamedPipe error," << errorString(); piCoutObj << "CreateNamedPipe error," << errorString();
destroy(); destroy();
@@ -855,8 +797,7 @@ bool PITerminal::initialize() {
resize(dsize_x, dsize_y); resize(dsize_x, dsize_y);
#else #else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
char pty[256]; char pty[256]; memset(pty, 0, 256);
memset(pty, 0, 256);
winsize ws; winsize ws;
ws.ws_col = dsize_x; ws.ws_col = dsize_x;
ws.ws_row = dsize_y; ws.ws_row = dsize_y;
@@ -936,8 +877,10 @@ void PITerminal::destroy() {
//piCout << "destroy" << size_y; //piCout << "destroy" << size_y;
#else #else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
if (PRIVATE->pid != 0) kill(PRIVATE->pid, SIGKILL); if (PRIVATE->pid != 0)
if (PRIVATE->fd != 0) ::close(PRIVATE->fd); kill(PRIVATE->pid, SIGKILL);
if (PRIVATE->fd != 0)
::close(PRIVATE->fd);
# endif # endif
#endif #endif
initPrivate(); initPrivate();

View File

@@ -238,7 +238,7 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
rinfo = crypt.decrypt(rinfo, secret_key, &ok); rinfo = crypt.decrypt(rinfo, secret_key, &ok);
if (!ok) return disconnect(ba, "Error while exchange keys"); if (!ok) return disconnect(ba, "Error while exchange keys");
state = Connected; state = Connected;
connected(PIString::fromUTF8(rinfo)); connected(rinfo);
ba << (int)state << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE); ba << (int)state << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state; return state;
} }

View File

@@ -22,9 +22,7 @@
# include <sodium.h> # include <sodium.h>
#endif #endif
#define PICRYPT_DISABLED_WARNING \ #define PICRYPT_DISABLED_WARNING piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and rebuild pip";
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 char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0";
const int hash_def_key_size = 9; const int hash_def_key_size = 9;
@@ -32,9 +30,7 @@ const int hash_def_key_size = 9;
PICrypt::PICrypt() { PICrypt::PICrypt() {
#ifdef PIP_CRYPT #ifdef PIP_CRYPT
if (!init()) if (!init()) piCout << "[PICrypt]" << "Error while initialize sodium!";
piCout << "[PICrypt]"
<< "Error while initialize sodium!";
nonce_.resize(crypto_secretbox_NONCEBYTES); nonce_.resize(crypto_secretbox_NONCEBYTES);
key_.resize(crypto_secretbox_KEYBYTES); key_.resize(crypto_secretbox_KEYBYTES);
randombytes_buf(key_.data(), key_.size()); randombytes_buf(key_.data(), key_.size());
@@ -80,7 +76,8 @@ PIByteArray PICrypt::crypt(const PIByteArray & data) {
PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) { PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
PIByteArray ret; PIByteArray ret;
#ifdef PIP_CRYPT #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, ' ');
//return PIByteArray(); //return PIByteArray();
if (!init()) return ret; if (!init()) return ret;
PIByteArray n; PIByteArray n;
@@ -119,7 +116,8 @@ 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; PIByteArray ret;
#ifdef PIP_CRYPT #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; /*if (ok) *ok = false;
return PIByteArray(); return PIByteArray();
}*/ }*/
@@ -136,8 +134,7 @@ PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bo
if (ok) *ok = false; if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_"; // piCout << "[PICrypt]" << "bad key_";
return PIByteArray(); return PIByteArray();
} else if (ok) } else if (ok) *ok = true;
*ok = true;
#else #else
PICRYPT_DISABLED_WARNING PICRYPT_DISABLED_WARNING
#endif #endif
@@ -198,13 +195,10 @@ size_t PICrypt::sizeHash() {
ullong PICrypt::shorthash(const PIString& s, PIByteArray key) { ullong PICrypt::shorthash(const PIString& s, PIByteArray key) {
ullong hash = 0; ullong hash = 0;
#ifdef PIP_CRYPT #ifdef PIP_CRYPT
if (crypto_shorthash_BYTES != sizeof(hash)) if (crypto_shorthash_BYTES != sizeof(hash)) piCout << "[PICrypt]" << "internal error: bad hash size";
piCout << "[PICrypt]"
<< "internal error: bad hash size";
if (!init()) return hash; if (!init()) return hash;
if (key.size() != crypto_shorthash_KEYBYTES) { if (key.size() != crypto_shorthash_KEYBYTES) {
piCout << "[PICrypt]" piCout << "[PICrypt]" << "invalid key size" << key.size() << ", shoud be" << crypto_shorthash_KEYBYTES << ", filled zeros";
<< "invalid key size" << key.size() << ", shoud be" << crypto_shorthash_KEYBYTES << ", filled zeros";
key.resize(crypto_shorthash_KEYBYTES, 0); key.resize(crypto_shorthash_KEYBYTES, 0);
} }
PIByteArray in(s.data(), s.size()); PIByteArray in(s.data(), s.size());
@@ -351,13 +345,16 @@ PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_
PIByteArray ret; PIByteArray ret;
#ifdef PIP_CRYPT #ifdef PIP_CRYPT
if (!init()) return ret; if (!init()) return ret;
if (public_key.size() != crypto_box_PUBLICKEYBYTES) return ret; if (public_key.size() != crypto_box_PUBLICKEYBYTES)
if (secret_key.size() != crypto_box_SECRETKEYBYTES) return ret; return ret;
if (secret_key.size() != crypto_box_SECRETKEYBYTES)
return ret;
PIByteArray n; PIByteArray n;
ret.resize(data.size() + crypto_box_MACBYTES); ret.resize(data.size() + crypto_box_MACBYTES);
n.resize(crypto_box_NONCEBYTES); n.resize(crypto_box_NONCEBYTES);
randombytes_buf(n.data(), n.size()); 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); ret.append(n);
#else #else
PICRYPT_DISABLED_WARNING PICRYPT_DISABLED_WARNING
@@ -386,13 +383,11 @@ PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray &
n.resize(crypto_secretbox_NONCEBYTES); n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES); ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size()); 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()) != if (crypto_box_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), public_key.data(), secret_key.data()) != 0) {
0) {
if (ok) *ok = false; if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_"; // piCout << "[PICrypt]" << "bad key_";
return PIByteArray(); return PIByteArray();
} else if (ok) } else if (ok) *ok = true;
*ok = true;
#else #else
PICRYPT_DISABLED_WARNING PICRYPT_DISABLED_WARNING
#endif #endif
@@ -410,16 +405,8 @@ PIByteArray PICrypt::passwordHash(const PIString & password, const PIByteArray &
n.resize(crypto_pwhash_SALTBYTES); n.resize(crypto_pwhash_SALTBYTES);
// randombytes_buf(n.data(), n.size()); // randombytes_buf(n.data(), n.size());
// crypto_shorthash(n.data(), seed.data(), seed.size(), PIByteArray(crypto_shorthash_KEYBYTES).data()); // crypto_shorthash(n.data(), seed.data(), seed.size(), PIByteArray(crypto_shorthash_KEYBYTES).data());
int r = crypto_pwhash(ph.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);
ph.size(), //crypto_pwhash_str(out, (const char*)pass.data(), pass.size(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate());
(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); pass.fill(0);
if (r != 0) return PIByteArray(); if (r != 0) return PIByteArray();
return ph; return ph;
@@ -447,7 +434,8 @@ bool PICrypt::init() {
if (inited) return true; if (inited) return true;
//piCout << "[PICrypt]" << "init ..."; //piCout << "[PICrypt]" << "init ...";
inited = sodium_init(); inited = sodium_init();
if (!inited) inited = sodium_init(); if (!inited)
inited = sodium_init();
//piCout << "[PICrypt]" << "init" << inited; //piCout << "[PICrypt]" << "init" << inited;
return inited; return inited;
#else #else
@@ -455,3 +443,6 @@ bool PICrypt::init() {
#endif #endif
return false; return false;
} }

View File

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

View File

@@ -23,8 +23,8 @@
#ifndef PIFFT_P_H #ifndef PIFFT_P_H
#define PIFFT_P_H #define PIFFT_P_H
#include "picout.h"
#include "pivector.h" #include "pivector.h"
#include "picout.h"
#if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq) #if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq)
# include "fftw3.h" # include "fftw3.h"
#else #else
@@ -36,7 +36,8 @@
template <typename T> template <typename T>
class PIFFTW_Private { class PIFFTW_Private
{
public: public:
explicit PIFFTW_Private() { explicit PIFFTW_Private() {
plan = 0; plan = 0;
@@ -50,7 +51,7 @@ public:
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)) { if (prepare != PlanParams(in.size(), fo_complex)) {
p_out.resize(in.size()); 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); p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_complex); prepare = PlanParams(in.size(), fo_complex);
} }
@@ -60,7 +61,7 @@ public:
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)) { if (prepare != PlanParams(in.size(), fo_real)) {
p_out.resize(in.size()); 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); p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_real); prepare = PlanParams(in.size(), fo_real);
} }
@@ -70,7 +71,7 @@ public:
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)) { if (prepare != PlanParams(in.size(), fo_inverse)) {
p_out.resize(in.size()); 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); p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_inverse); prepare = PlanParams(in.size(), fo_inverse);
} }
@@ -78,11 +79,7 @@ public:
return p_out; return p_out;
} }
enum FFT_Operation { enum FFT_Operation {fo_real, fo_complex, fo_inverse};
fo_real,
fo_complex,
fo_inverse
};
void preparePlan(int size, int op) { void preparePlan(int size, int op) {
p_inr.clear(); p_inr.clear();
@@ -104,7 +101,9 @@ public:
p_out.resize(size); p_out.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED); p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED);
break; break;
default: size = 0; break; default:
size = 0;
break;
} }
prepare = PlanParams(size, (FFT_Operation)op); prepare = PlanParams(size, (FFT_Operation)op);
} }
@@ -118,14 +117,8 @@ public:
inline void p_makeThreadSafe() {} inline void p_makeThreadSafe() {}
struct PlanParams { struct PlanParams {
PlanParams() { PlanParams() {size = 0; op = fo_complex;}
size = 0; PlanParams(int size_, FFT_Operation op_) {size = size_; op = op_;}
op = fo_complex;
}
PlanParams(int size_, FFT_Operation op_) {
size = size_;
op = op_;
}
bool isValid() {return size > 0;} 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 (v.size == size) && (v.op == op);}
bool operator !=(const PlanParams & v) const {return !(*this == v);} bool operator !=(const PlanParams & v) const {return !(*this == v);}
@@ -142,104 +135,44 @@ public:
#ifdef PIP_FFTWf #ifdef PIP_FFTWf
template<> template<> inline void PIFFTW_Private<float>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
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);}
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<> template<> inline void PIFFTW_Private<float>::p_executePlan(void * plan) {fftwf_execute((fftwf_plan)plan);}
inline void PIFFTW_Private<float>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) { 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);}
plan = fftwf_plan_dft_r2c_1d(size, (float *)in, (fftwf_complex *)out, flags); 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_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 # ifdef PIP_FFTWf_THREADSAFE
template<> template<> inline void PIFFTW_Private<float>::p_makeThreadSafe() {fftwf_make_planner_thread_safe();}
inline void PIFFTW_Private<float>::p_makeThreadSafe() {
fftwf_make_planner_thread_safe();
}
# endif # endif
#endif // PIP_FFTWf #endif // PIP_FFTWf
#ifdef PIP_FFTW #ifdef PIP_FFTW
template<> template<> inline void PIFFTW_Private<double>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
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);}
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<> template<> inline void PIFFTW_Private<double>::p_executePlan(void * plan) {fftw_execute((fftw_plan)plan);}
inline void PIFFTW_Private<double>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) { 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);}
plan = fftw_plan_dft_r2c_1d(size, (double *)in, (fftw_complex *)out, flags); 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_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 # ifdef PIP_FFTW_THREADSAFE
template<> template<> inline void PIFFTW_Private<double>::p_makeThreadSafe() {fftw_make_planner_thread_safe();}
inline void PIFFTW_Private<double>::p_makeThreadSafe() {
fftw_make_planner_thread_safe();
}
# endif # endif
#endif // PIP_FFTW #endif // PIP_FFTW
#ifdef PIP_FFTWl #ifdef PIP_FFTWl
template<> template<> inline void PIFFTW_Private<ldouble>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
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);}
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<> template<> inline void PIFFTW_Private<ldouble>::p_executePlan(void * plan) {fftwl_execute((fftwl_plan)plan);}
inline void PIFFTW_Private<ldouble>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) { 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);}
plan = fftwl_plan_dft_r2c_1d(size, (ldouble *)in, (fftwl_complex *)out, flags); 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_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 # ifdef PIP_FFTWl_THREADSAFE
template<> template<> inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {fftwl_make_planner_thread_safe();}
inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {
fftwl_make_planner_thread_safe();
}
# endif # endif
#endif // PIP_FFTWl #endif // PIP_FFTWl

View File

@@ -84,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); PIMutexLocker ml(mcast_mutex);
mcast_address = addr; mcast_address = addr;
_reinit = true; _reinit = true;
@@ -126,16 +126,16 @@ void PIBroadcast::destroyAll() {
} }
void PIBroadcast::initAll(PIVector<PINetworkAddress> al) { void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
destroyAll(); destroyAll();
_reinit = false; _reinit = false;
prev_al = al; prev_al = al;
al.removeAll(PINetworkAddress("127.0.0.1")); al.removeAll(PIEthernet::Address("127.0.0.1"));
al << mcast_address; al << mcast_address;
eth_mcast.clear(); eth_mcast.clear();
PIEthernet::InterfaceList ifaces = PIEthernet::interfaces(); PIEthernet::InterfaceList ifaces = PIEthernet::interfaces();
piForeachC(PINetworkAddress & a, al) { piForeachC (PIEthernet::Address & a, al) {
PIEthernet * ce = 0; PIEthernet * ce = 0;
//piCout << "mcast try" << a; //piCout << "mcast try" << a;
if (_channels[Multicast]) { if (_channels[Multicast]) {
@@ -151,7 +151,7 @@ void PIBroadcast::initAll(PIVector<PINetworkAddress> al) {
//piCout << "mcast " << ce->readAddress() << ce->sendAddress(); //piCout << "mcast " << ce->readAddress() << ce->sendAddress();
if (ce->open()) { if (ce->open()) {
eth_mcast << ce; eth_mcast << ce;
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead); CONNECTU(ce, threadedReadEvent, this, mcastRead);
} else { } else {
delete ce; delete ce;
} }
@@ -166,14 +166,14 @@ void PIBroadcast::initAll(PIVector<PINetworkAddress> al) {
ce->setName("PIMulticast_" + a.toString()); ce->setName("PIMulticast_" + a.toString());
ce->setParameters(PIEthernet::Broadcast); ce->setParameters(PIEthernet::Broadcast);
const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString()); 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); ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port);
if (!_send_only) { if (!_send_only) {
ce->setReadAddress(PINetworkAddress(a.ip(), bcast_port)); ce->setReadAddress(PIEthernet::Address(a.ip(), bcast_port));
//piCout << "bcast " << ce->readAddress() << ce->sendAddress(); //piCout << "bcast " << ce->readAddress() << ce->sendAddress();
if (ce->open()) { if (ce->open()) {
eth_mcast << ce; eth_mcast << ce;
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead); CONNECTU(ce, threadedReadEvent, this, mcastRead);
} else { } else {
delete ce; delete ce;
} }
@@ -189,7 +189,7 @@ void PIBroadcast::initAll(PIVector<PINetworkAddress> al) {
eth_lo->setName("PIMulticast_loopback"); eth_lo->setName("PIMulticast_loopback");
if (!_send_only) { if (!_send_only) {
eth_lo->setParameter(PIEthernet::ReuseAddress, false); eth_lo->setParameter(PIEthernet::ReuseAddress, false);
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) { for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->setReadAddress("127.0.0.1", lo_port + i); eth_lo->setReadAddress("127.0.0.1", lo_port + i);
if (eth_lo->open()) { if (eth_lo->open()) {
@@ -210,8 +210,7 @@ void PIBroadcast::send(const PIByteArray & data) {
PIByteArray cd = cryptData(data); PIByteArray cd = cryptData(data);
if (cd.isEmpty()) return; if (cd.isEmpty()) return;
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
piForeach(PIEthernet * e, eth_mcast) piForeach (PIEthernet * e, eth_mcast) e->send(cd);
e->send(cd);
if (eth_lo) { if (eth_lo) {
for (int i = 0; i < lo_pcnt; ++i) { for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->send("127.0.0.1", lo_port + i, cd); eth_lo->send("127.0.0.1", lo_port + i, cd);
@@ -228,8 +227,7 @@ void PIBroadcast::startRead() {
} }
if (_send_only) return; if (_send_only) return;
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
piForeach(PIEthernet * e, eth_mcast) piForeach (PIEthernet * e, eth_mcast) e->startThreadedRead();
e->startThreadedRead();
if (eth_lo) eth_lo->startThreadedRead(); if (eth_lo) eth_lo->startThreadedRead();
_started = true; _started = true;
} }
@@ -238,8 +236,7 @@ void PIBroadcast::startRead() {
void PIBroadcast::stopRead() { void PIBroadcast::stopRead() {
if (isRunning()) stop(); if (isRunning()) stop();
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
piForeach(PIEthernet * e, eth_mcast) piForeach (PIEthernet * e, eth_mcast) e->stopThreadedRead();
e->stopThreadedRead();
if (eth_lo) eth_lo->stopThreadedRead(); if (eth_lo) eth_lo->stopThreadedRead();
_started = false; _started = false;
} }
@@ -251,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)); PIByteArray cd = decryptData(PIByteArray(data, size));
if (cd.isEmpty()) return; if (cd.isEmpty()) return;
received(cd); received(cd);
@@ -260,7 +257,7 @@ void PIBroadcast::mcastRead(const uchar * data, ssize_t size) {
void PIBroadcast::run() { void PIBroadcast::run() {
PIVector<PINetworkAddress> al = PIEthernet::allAddresses(); PIVector<PIEthernet::Address> al = PIEthernet::allAddresses();
mcast_mutex.lock(); mcast_mutex.lock();
bool r = _reinit, ac = (al != prev_al); bool r = _reinit, ac = (al != prev_al);
mcast_mutex.unlock(); mcast_mutex.unlock();

View File

@@ -51,7 +51,8 @@ PIEthUtilBase::PIEthUtilBase() {
} }
PIEthUtilBase::~PIEthUtilBase() {} PIEthUtilBase::~PIEthUtilBase() {
}
void PIEthUtilBase::setCryptEnabled(bool on) { void PIEthUtilBase::setCryptEnabled(bool on) {

View File

@@ -22,7 +22,6 @@
# pragma GCC diagnostic ignored "-Wnonnull" # pragma GCC diagnostic ignored "-Wnonnull"
#endif #endif
#include "pistreampacker.h" #include "pistreampacker.h"
#include "piiodevice.h" #include "piiodevice.h"
#ifdef __GNUC__ #ifdef __GNUC__
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
@@ -62,8 +61,7 @@ PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
void PIStreamPacker::setCryptSizeEnabled(bool on) { void PIStreamPacker::setCryptSizeEnabled(bool on) {
crypt_size = on; crypt_size = on;
if (crypt_size) { if (crypt_size) {
PIByteArray ba; PIByteArray ba; ba << int(0);
ba << int(0);
size_crypted_size = cryptData(ba).size_s(); size_crypted_size = cryptData(ba).size_s();
} else } else
size_crypted_size = sizeof(int); size_crypted_size = sizeof(int);
@@ -85,10 +83,8 @@ void PIStreamPacker::send(const PIByteArray & data) {
//piCout << "crypt_frag send" << fcnt << "frags"; //piCout << "crypt_frag send" << fcnt << "frags";
PIByteArray frag; PIByteArray frag;
for (int i = 0; i < fcnt; ++i) { for (int i = 0; i < fcnt; ++i) {
if (i == fcnt - 1) if (i == fcnt - 1) frag = PIByteArray(data.data(fst), data.size_s() - fst);
frag = PIByteArray(data.data(fst), data.size_s() - fst); else frag = PIByteArray(data.data(fst), crypt_frag_size);
else
frag = PIByteArray(data.data(fst), crypt_frag_size);
fst += crypt_frag_size; fst += crypt_frag_size;
cd << cryptData(frag); cd << cryptData(frag);
} }
@@ -99,18 +95,15 @@ void PIStreamPacker::send(const PIByteArray & data) {
PIByteArray hdr, part; PIByteArray hdr, part;
hdr << packet_sign; hdr << packet_sign;
if (crypt_size) { if (crypt_size) {
PIByteArray crsz; PIByteArray crsz; crsz << int(cd.size_s());
crsz << int(cd.size_s());
hdr.append(cryptData(crsz)); hdr.append(cryptData(crsz));
} else } else
hdr << int(cd.size_s()); hdr << int(cd.size_s());
cd.insert(0, hdr); cd.insert(0, hdr);
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0; int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
for (int i = 0; i < pcnt; ++i) { for (int i = 0; i < pcnt; ++i) {
if (i == pcnt - 1) if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
part = PIByteArray(cd.data(pst), cd.size_s() - pst); else part = PIByteArray(cd.data(pst), max_packet_size);
else
part = PIByteArray(cd.data(pst), max_packet_size);
//piCout << "send" << part.size(); //piCout << "send" << part.size();
sendRequest(part); sendRequest(part);
pst += max_packet_size; pst += max_packet_size;
@@ -118,7 +111,7 @@ void PIStreamPacker::send(const PIByteArray & data) {
} }
void PIStreamPacker::received(const uchar * readed, ssize_t size) { void PIStreamPacker::received(uchar * readed, int size) {
received(PIByteArray(readed, size)); received(PIByteArray(readed, size));
} }
@@ -133,10 +126,8 @@ void PIStreamPacker::received(const PIByteArray & data) {
ushort sign(0); ushort sign(0);
memcpy(&sign, stream.data(), 2); memcpy(&sign, stream.data(), 2);
if (sign != packet_sign) { if (sign != packet_sign) {
if (aggressive_optimization) if (aggressive_optimization) stream.clear();
stream.clear(); else stream.pop_front();
else
stream.pop_front();
continue; continue;
} }
int sz = -1; int sz = -1;
@@ -145,10 +136,8 @@ void PIStreamPacker::received(const PIByteArray & data) {
memcpy(crsz.data(), stream.data(2), size_crypted_size); memcpy(crsz.data(), stream.data(2), size_crypted_size);
crsz = decryptData(crsz); crsz = decryptData(crsz);
if (crsz.size() < sizeof(sz)) { if (crsz.size() < sizeof(sz)) {
if (aggressive_optimization) if (aggressive_optimization) stream.clear();
stream.clear(); else stream.pop_front();
else
stream.pop_front();
continue; continue;
} }
crsz >> sz; crsz >> sz;
@@ -156,16 +145,15 @@ void PIStreamPacker::received(const PIByteArray & data) {
memcpy(&sz, stream.data(2), size_crypted_size); memcpy(&sz, stream.data(2), size_crypted_size);
} }
if (sz < 0) { if (sz < 0) {
if (aggressive_optimization) if (aggressive_optimization) stream.clear();
stream.clear(); else stream.pop_front();
else
stream.pop_front();
continue; continue;
} }
stream.remove(0, hdr_size); stream.remove(0, hdr_size);
packet.clear(); packet.clear();
packet_size = sz; packet_size = sz;
if (packet_size == 0) packet_size = -1; if (packet_size == 0)
packet_size = -1;
continue; continue;
} else { } else {
int ps = piMini(stream.size_s(), packet_size - packet.size_s()); int ps = piMini(stream.size_s(), packet_size - packet.size_s());
@@ -207,9 +195,8 @@ void PIStreamPacker::received(const PIByteArray & data) {
void PIStreamPacker::assignDevice(PIIODevice * dev) { void PIStreamPacker::assignDevice(PIIODevice * dev) {
if (!dev) return; if (!dev) return;
if (!dev->infoFlags()[PIIODevice::Reliable]) { if (!dev->infoFlags()[PIIODevice::Reliable])
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev; piCoutObj << "Warning! Not recommended to use with non-reliable" << dev;
} CONNECTU(dev, threadedReadEvent, this, received);
CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received); CONNECTU(this, sendRequest, dev, write);
CONNECT1(void, PIByteArray, this, sendRequest, dev, write);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,9 +26,9 @@
#ifndef PICLOUDTCP_H #ifndef PICLOUDTCP_H
#define PICLOUDTCP_H #define PICLOUDTCP_H
#include "pimutex.h"
#include "pip_cloud_export.h" #include "pip_cloud_export.h"
#include "pistring.h" #include "pistring.h"
#include "pimutex.h"
class PIEthernet; class PIEthernet;
@@ -37,6 +37,7 @@ class PIStreamPacker;
namespace PICloud { namespace PICloud {
class PIP_CLOUD_EXPORT TCP { class PIP_CLOUD_EXPORT TCP {
public: public:
enum Version { enum Version {
@@ -90,8 +91,9 @@ private:
PIString server_name; PIString server_name;
PIStreamPacker * streampacker; PIStreamPacker * streampacker;
PIMutex mutex_send; PIMutex mutex_send;
}; };
} // namespace PICloud }
#endif // PICLOUDTCP_H #endif // PICLOUDTCP_H

View File

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

View File

@@ -35,11 +35,9 @@
//! //!
//! \~english //! \~english
//! These files provides parsing C++ code and storage to use results of \a pip_cmg utility. //! These files provides parsing C++ code and storage to use results of \a pip_cmg utility.
//! See \ref code_model.
//! //!
//! \~russian //! \~russian
//! Эти файлы обеспечивают разбор C++ кода и хранение результатов работы утилиты \a pip_cmg. //! Эти файлы обеспечивают разбор C++ кода и хранение результатов работы утилиты \a pip_cmg.
//! Подробнее \ref code_model.
//! //!
//! \~\authors //! \~\authors
//! \~english //! \~english

View File

@@ -20,6 +20,7 @@
#include "picodeparser.h" #include "picodeparser.h"
PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const { PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
PIStringList arg_vals; PIStringList arg_vals;
while (!args_.isEmpty()) { while (!args_.isEmpty()) {
@@ -31,20 +32,17 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
PIString ca; PIString ca;
if (bi >= 0 && bi < ci) { if (bi >= 0 && bi < ci) {
ca = args_.left(args_.takeLeft(bi).toInt()); ca = args_.left(args_.takeLeft(bi).toInt());
ci -= ca.size_s(); ci -= ca.size_s(); bi -= ca.size_s();
bi -= ca.size_s();
ca += '(' + args_.takeRange('(', ')') + ')'; ca += '(' + args_.takeRange('(', ')') + ')';
} else { } else {
ca = args_.takeLeft(ci); ca = args_.takeLeft(ci);
} }
arg_vals << ca; arg_vals << ca;
args_.trim(); args_.trim(); args_.takeLeft(1); args_.trim();
args_.takeLeft(1);
args_.trim();
} }
if (args.size() != arg_vals.size()) { if (args.size() != arg_vals.size()) {
piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect") << args.size() << "arguments but takes" piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect")
<< arg_vals.size() << "!"; << args.size() << "arguments but takes" << arg_vals.size() << "!";
if (ok != 0) *ok = false; if (ok != 0) *ok = false;
return PIString(); return PIString();
} }
@@ -74,6 +72,7 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
} }
PICodeParser::PICodeParser() { PICodeParser::PICodeParser() {
macros_iter = 32; macros_iter = 32;
with_includes = true; with_includes = true;
@@ -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) { bool PICodeParser::isEnum(const PIString & name) {
piForeachC (Enum & e, enums) piForeachC (Enum & e, enums)
if (e.name == name) return true; if (e.name == name)
return true;
return false; return false;
} }
@@ -179,8 +174,7 @@ bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes
void PICodeParser::clear() { void PICodeParser::clear() {
piForeach(Entity * i, entities) piForeach (Entity * i, entities) delete i;
delete i;
defines.clear(); defines.clear();
macros.clear(); macros.clear();
enums.clear(); enums.clear();
@@ -198,137 +192,32 @@ void PICodeParser::clear() {
defines << Define(PIStringAscii("PICODE"), "") << custom_defines; defines << Define(PIStringAscii("PICODE"), "") << custom_defines;
macros << Macro(PIStringAscii("PIOBJECT"), "", PIStringList() << "name") macros << Macro(PIStringAscii("PIOBJECT"), "", PIStringList() << "name")
<< Macro(PIStringAscii("PIOBJECT_PARENT"), "", PIStringList() << "parent") << Macro(PIStringAscii("PIOBJECT_PARENT"), "", PIStringList() << "parent")
<< Macro(PIStringAscii("PIOBJECT_SUBCLASS"), << Macro(PIStringAscii("PIOBJECT_SUBCLASS"), "", PIStringList() << "name" << "parent")
"",
PIStringList() << "name"
<< "parent")
<< Macro(PIStringAscii("PIIODEVICE"), "", PIStringList() << "name") << 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("EVENT0"), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("EVENT1"), << Macro(PIStringAscii("EVENT1"), "void name(a0 n0);", PIStringList() << "name" << "a0" << "n0")
"void name(a0 n0);", << Macro(PIStringAscii("EVENT2"), "void name(a0 n0, a1 n1);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1")
PIStringList() << "name" << Macro(PIStringAscii("EVENT3"), "void name(a0 n0, a1 n1, a2 n2);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
<< "a0" << Macro(PIStringAscii("EVENT4"), "void name(a0 n0, a1 n1, a2 n2, a3 n3);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3")
<< "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"), << Macro(PIStringAscii("EVENT_HANDLER" ), "ret name()", PIStringList() << "ret" << "name")
"ret name()", << Macro(PIStringAscii("EVENT_HANDLER0"), "ret name()", PIStringList() << "ret" << "name")
PIStringList() << "ret" << Macro(PIStringAscii("EVENT_HANDLER1"), "ret name(a0 n0)", PIStringList() << "ret" << "name" << "a0" << "n0")
<< "name") << Macro(PIStringAscii("EVENT_HANDLER2"), "ret name(a0 n0, a1 n1)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1")
<< Macro(PIStringAscii("EVENT_HANDLER0"), << Macro(PIStringAscii("EVENT_HANDLER3"), "ret name(a0 n0, a1 n1, a2 n2)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
"ret name()", << 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")
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"), << Macro(PIStringAscii("EVENT_VHANDLER" ), "virtual ret name()", PIStringList() << "ret" << "name")
"virtual ret name()", << Macro(PIStringAscii("EVENT_VHANDLER0"), "virtual ret name()", PIStringList() << "ret" << "name")
PIStringList() << "ret" << Macro(PIStringAscii("EVENT_VHANDLER1"), "virtual ret name(a0 n0)", PIStringList() << "ret" << "name" << "a0" << "n0")
<< "name") << Macro(PIStringAscii("EVENT_VHANDLER2"), "virtual ret name(a0 n0, a1 n1)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1")
<< Macro(PIStringAscii("EVENT_VHANDLER0"), << Macro(PIStringAscii("EVENT_VHANDLER3"), "virtual ret name(a0 n0, a1 n1, a2 n2)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
"virtual ret name()", << 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")
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; if (i > 0) pc = c;
c = fc[i].toAscii(); c = fc[i].toAscii();
if (c == '"' && !mlc && pc != '\'') { if (c == '"' && !mlc && pc != '\'') {
if (i > 0) if (i > 0) if (fc[i - 1] == '\\') continue;
if (fc[i - 1] == '\\') continue;
cc = !cc; cc = !cc;
continue; continue;
} }
@@ -370,24 +258,9 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
continue; continue;
} }
if (cc) continue; if (cc) continue;
if (fc.mid(i, 2) == "/*") { if (fc.mid(i, 2) == "/*") {mlc = true; mls = i; ++i; continue;}
mlc = true; if (fc.mid(i, 2) == "*/" && mlc) {mlc = false; fc.cutMid(mls, i - mls + 2); i = mls - 1; continue;}
mls = i; if (fc.mid(i, 2) == "//" && !mlc) {ole = fc.find('\n', i); fc.cutMid(i, ole < 0 ? -1 : ole - i); --i; continue;}
++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); pfc = procMacros(fc);
@@ -422,8 +295,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (ind > 0) pc = pfc[ind - 1]; if (ind > 0) pc = pfc[ind - 1];
if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(),1)[0]; if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(),1)[0];
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue; if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
PIString ret, range; PIString ret, range; bool ok(false);
bool ok(false);
range = pfc.mid(ind + m.name.size_s()).takeRange('(', ')'); range = pfc.mid(ind + m.name.size_s()).takeRange('(', ')');
ret = m.expand(range, &ok); ret = m.expand(range, &ok);
if (!ok) return false; if (!ok) return false;
@@ -439,7 +311,6 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
//piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc; //piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc;
int pl = -1; int pl = -1;
cur_def_vis = Global;
while (!pfc.isEmpty()) { while (!pfc.isEmpty()) {
pfc.trim(); pfc.trim();
int nl = pfc.size_s(); int nl = pfc.size_s();
@@ -450,7 +321,6 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
PIString prev_namespace = cur_namespace, ccmn; PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += pfc.takeCWord() + s_ns; cur_namespace += pfc.takeCWord() + s_ns;
ccmn = pfc.takeRange('{', '}'); ccmn = pfc.takeRange('{', '}');
// piCout << "namespace" << cur_namespace;
parseClass(0, ccmn, true); parseClass(0, ccmn, true);
cur_namespace = prev_namespace; cur_namespace = prev_namespace;
continue; continue;
@@ -460,25 +330,14 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
pfc.takeRange('<', '>'); pfc.takeRange('<', '>');
bool def = !isDeclaration(pfc, 0, &end); bool def = !isDeclaration(pfc, 0, &end);
pfc.cutLeft(end); pfc.cutLeft(end);
if (def) if (def) pfc.takeRange('{', '}');
pfc.takeRange('{', '}'); else pfc.takeSymbol();
else
pfc.takeSymbol();
continue; continue;
} }
if (pfc.left(5) == s_class || pfc.left(6) == s_struct || pfc.left(5) == s_union) { 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); 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 < 0) { if (dind < 0 || find < dind) {pfc.cutLeft(6); continue;}
pfc.cutLeft(6);
continue;
}
if (dind < 0 || find < dind) {
// piCout << "skip FC" << (find + 1) << pfc.left(find + 1);
pfc.cutLeft(find + 1);
// pfc.cutLeft(6);
continue;
}
ccmn = pfc.left(dind) + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc; ccmn = pfc.left(dind) + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc;
pfc.remove(0, ccmn.size()); pfc.remove(0, ccmn.size());
parseClass(0, ccmn, false); parseClass(0, ccmn, false);
@@ -489,12 +348,6 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
tmp = pfc.takeCWord(); tmp = pfc.takeCWord();
pfc.trim(); pfc.trim();
MetaMap meta = maybeMeta(pfc); 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); parseEnum(0, cur_namespace + tmp, pfc.takeRange('{', '}'), meta);
pfc.takeSymbol(); pfc.takeSymbol();
continue; continue;
@@ -502,10 +355,8 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (pfc.left(7) == s_typedef) { if (pfc.left(7) == s_typedef) {
pfc.cutLeft(7); pfc.cutLeft(7);
typedefs << parseTypedef(pfc.takeLeft(pfc.find(';'))); typedefs << parseTypedef(pfc.takeLeft(pfc.find(';')));
if (typedefs.back().first.isEmpty()) if (typedefs.back().first.isEmpty()) typedefs.pop_back();
typedefs.pop_back(); else root_.typedefs << typedefs.back();
else
root_.typedefs << typedefs.back();
pfc.takeSymbol(); pfc.takeSymbol();
continue; continue;
} }
@@ -547,33 +398,27 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
cd.cutRight(1); cd.cutRight(1);
Entity * pe = 0; Entity * pe = 0;
piForeachC (PIString & p, pl) { piForeachC (PIString & p, pl) {
if (p.contains(' ')) if (p.contains(' ')) pn = p.mid(p.find(' ') + 1);
pn = p.mid(p.find(' ') + 1); else pn = p;
else
pn = p;
pe = findEntityByName(pn); pe = findEntityByName(pn);
if (pe == 0) if (pe == 0) ;//{piCout << "Error: can`t find" << pn;}
; //{piCout << "Error: can`t find" << pn;} else parents << pe;
else
parents << pe;
} }
} }
PIString typename_ = cd.left(6).trim(); PIString typename_ = cd.left(6).trim();
bool is_class = typename_ == s_class; bool is_class = typename_ == s_class;
Visibility vis = cur_def_vis;
cur_def_vis = (is_class ? Private : Public); cur_def_vis = (is_class ? Private : Public);
PIString cn = cd.mid(6).trim(); PIString cn = cd.mid(6).trim();
bool has_name = !cn.isEmpty(); bool has_name = !cn.isEmpty();
if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>'; if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>';
//piCout << "found " << typename_ << cn; //piCout << "found " << typename_ << cn;
if (cn.isEmpty()) return nullptr; if (cn.isEmpty()) return 0;
Entity * e = new Entity(); Entity * e = new Entity();
e->meta = meta; e->meta = meta;
e->name = cur_namespace + cn; e->name = cur_namespace + cn;
e->type = typename_; e->type = typename_;
e->has_name = has_name; e->has_name = has_name;
e->parents = parents; e->parents = parents;
e->visibility = vis;
e->file = cur_file; e->file = cur_file;
entities << e; entities << e;
return e; return e;
@@ -596,6 +441,10 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
Visibility prev_vis = cur_def_vis; Visibility prev_vis = cur_def_vis;
int dind = fc.find('{'), find = fc.find(';'), end = 0; int dind = fc.find('{'), find = fc.find(';'), end = 0;
if (dind < 0 && find < 0) return; if (dind < 0 && find < 0) return;
if (dind < 0 || find < dind) {
fc.left(find);
return;
}
//piCout << "parse class <****\n" << fc << "\n****>"; //piCout << "parse class <****\n" << fc << "\n****>";
Entity * ce = parent; Entity * ce = parent;
if (!is_namespace) { if (!is_namespace) {
@@ -603,6 +452,7 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
fc.trim().cutLeft(1).cutRight(1).trim(); 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 (ce) {
if (parent) parent->children << ce; if (parent) parent->children << ce;
ce->parent_scope = parent; ce->parent_scope = parent;
@@ -616,21 +466,9 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
while (!fc.isEmpty()) { while (!fc.isEmpty()) {
PIString cw = fc.takeCWord(), tmp; PIString cw = fc.takeCWord(), tmp;
//piCout << "\ntaked word" << cw; //piCout << "\ntaked word" << cw;
if (cw == s_public) { if (cw == s_public ) {cur_def_vis = Public; fc.cutLeft(1); continue;}
cur_def_vis = Public; if (cw == s_protected) {cur_def_vis = Protected; fc.cutLeft(1); continue;}
fc.cutLeft(1); if (cw == s_private ) {cur_def_vis = Private; fc.cutLeft(1); continue;}
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) { if (cw == s_namespace) {
PIString prev_namespace = cur_namespace, ccmn; PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += fc.takeCWord() + s_ns; cur_namespace += fc.takeCWord() + s_ns;
@@ -640,7 +478,6 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
continue; continue;
} }
if (cw == s_class || cw == s_struct || cw == s_union) { if (cw == s_class || cw == s_struct || cw == s_union) {
// piCout << cw << isDeclaration(fc, 0, &end);
if (isDeclaration(fc, 0, &end)) { if (isDeclaration(fc, 0, &end)) {
fc.cutLeft(end); fc.cutLeft(end);
fc.takeSymbol(); fc.takeSymbol();
@@ -657,26 +494,18 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
tmp = fc.takeCWord(); tmp = fc.takeCWord();
fc.trim(); fc.trim();
MetaMap meta = maybeMeta(fc); 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); parseEnum(ce, cur_namespace + tmp, fc.takeRange('{', '}'), meta);
fc.takeSymbol(); fc.takeSymbol();
continue; continue;
} }
if (cw == s_friend) { if (cw == s_friend) {fc.cutLeft(fc.find(';') + 1); continue;}
fc.cutLeft(fc.find(';') + 1);
continue;
}
if (cw == s_typedef) { if (cw == s_typedef) {
if (ce) { if (ce) {
ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';'))); ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';')));
typedefs << ce->typedefs.back(); typedefs << ce->typedefs.back();
typedefs.back().first.insert(0, cur_namespace); 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(); fc.takeSymbol();
continue; continue;
@@ -685,22 +514,17 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
fc.takeRange('<', '>'); fc.takeRange('<', '>');
def = !isDeclaration(fc, 0, &end); def = !isDeclaration(fc, 0, &end);
fc.cutLeft(end); fc.cutLeft(end);
if (def) if (def) fc.takeRange('{', '}');
fc.takeRange('{', '}'); else fc.takeSymbol();
else
fc.takeSymbol();
continue; continue;
} }
def = !isDeclaration(fc, 0, &end); def = !isDeclaration(fc, 0, &end);
tmp = (cw + fc.takeLeft(end)).trim(); tmp = (cw + fc.takeLeft(end)).trim();
if (!tmp.isEmpty() && ce) parseMember(ce, tmp); if (!tmp.isEmpty() && ce)
if (def) parseMember(ce, tmp);
fc.takeRange('{', '}'); if (def) fc.takeRange('{', '}');
else else fc.takeSymbol();
fc.takeSymbol(); if (ps == fc.size_s()) {fc.cutLeft(1);}
if (ps == fc.size_s()) {
fc.cutLeft(1);
}
ps = fc.size_s(); ps = fc.size_s();
} }
cur_def_vis = prev_vis; cur_def_vis = prev_vis;
@@ -744,17 +568,14 @@ bool PICodeParser::parseEnum(Entity * parent, const PIString & name, PIString fc
meta = tmp_meta.value(v.takeMid(mi, 5)); meta = tmp_meta.value(v.takeMid(mi, 5));
v.replaceAll(s_ss, ' '); v.replaceAll(s_ss, ' ');
} }
vn = v; vn = v; ind = v.find('=');
ind = v.find('='); if (ind > 0) {cv = v.right(v.size_s() - ind - 1).toInt(); vn = v.left(ind);}
if (ind > 0) {
cv = v.right(v.size_s() - ind - 1).toInt();
vn = v.left(ind);
}
if (ind < 0) ++cv; if (ind < 0) ++cv;
e.members << EnumeratorInfo(vn.trim(), cv, meta); e.members << EnumeratorInfo(vn.trim(), cv, meta);
} }
if (!e.members.isEmpty()) 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; enums << e;
return true; return true;
} }
@@ -768,10 +589,7 @@ PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) {
if (fc.contains('(')) { if (fc.contains('(')) {
int start = fc.find('('), end = fc.find(')'); int start = fc.find('('), end = fc.find(')');
td.first = fc.takeMid(start + 1, end - start - 1).trim(); td.first = fc.takeMid(start + 1, end - start - 1).trim();
if (td.first.left(1) == PIChar('*')) { if (td.first.left(1) == PIChar('*')) {td.first.cutLeft(1).trim(); fc.insert(start + 1, '*');}
td.first.cutLeft(1).trim();
fc.insert(start + 1, '*');
}
td.second = fc.trim(); td.second = fc.trim();
} else { } else {
td.first = fc.takeMid(fc.findLast(' ')).trim(); td.first = fc.takeMid(fc.findLast(' ')).trim();
@@ -818,11 +636,7 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
PIString ctemp, crepl; PIString ctemp, crepl;
while (ts >= 0) { while (ts >= 0) {
ctemp = fc.mid(ts).takeRange('<', '>'); ctemp = fc.mid(ts).takeRange('<', '>');
if (ctemp.isEmpty()) { if (ctemp.isEmpty()) {te = ts + 1; ts = fc.find('<', te); continue;}
te = ts + 1;
ts = fc.find('<', te);
continue;
}
crepl = s_T + PIString::fromNumber(tmp_temp.size_s()).expandLeftTo(3, '0'); crepl = s_T + PIString::fromNumber(tmp_temp.size_s()).expandLeftTo(3, '0');
fc.replace(ts, ctemp.size_s() + 2, crepl); fc.replace(ts, ctemp.size_s() + 2, crepl);
tmp_temp[crepl] = '<' + ctemp + '>'; tmp_temp[crepl] = '<' + ctemp + '>';
@@ -868,7 +682,8 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
int i = 0; int i = 0;
//piCout << me.arguments_full; //piCout << me.arguments_full;
piForeach (PIString & a, me.arguments_full) piForeach (PIString & a, me.arguments_full)
if ((i = a.find('=')) > 0) a.cutRight(a.size_s() - i).trim(); if ((i = a.find('=')) > 0)
a.cutRight(a.size_s() - i).trim();
for (int j = 0; j < me.arguments_full.size_s(); ++j) for (int j = 0; j < me.arguments_full.size_s(); ++j)
if (me.arguments_full[j] == s_void) { if (me.arguments_full[j] == s_void) {
me.arguments_full.remove(j); me.arguments_full.remove(j);
@@ -877,7 +692,8 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
me.arguments_type = me.arguments_full; me.arguments_type = me.arguments_full;
piForeach (PIString & a, me.arguments_type) { piForeach (PIString & a, me.arguments_type) {
crepl.clear(); 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) for (ts = a.size_s() - 1; ts >= 0; --ts)
if (!_isCChar(a[ts]) && !(a[ts].isDigit())) break; if (!_isCChar(a[ts]) && !(a[ts].isDigit())) break;
a.cutRight(a.size_s() - ts - 1); a.cutRight(a.size_s() - ts - 1);
@@ -907,11 +723,8 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
ctemp.trim(); ctemp.trim();
} }
for (ts = ctemp.size_s() - 1; ts > 0; --ts) { for (ts = ctemp.size_s() - 1; ts > 0; --ts) {
if (vn) { if (vn) {if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;}
if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false; else {if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;}
} else {
if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;
}
} }
me.type = ctemp.takeLeft(ts + 1); me.type = ctemp.takeLeft(ts + 1);
me.visibility = cur_def_vis; me.visibility = cur_def_vis;
@@ -949,13 +762,13 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
me.type = type; me.type = type;
restoreTmpMeta(&me); restoreTmpMeta(&me);
if (me.name.isEmpty()) continue; 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()) { while (!me.name.isEmpty()) {
if (me.name.front() == PIChar('*') || me.name.front() == PIChar('&')) { if (me.name.front() == PIChar('*') || me.name.front() == PIChar('&')) {
me.type += me.name.takeLeft(1); me.type += me.name.takeLeft(1);
me.name.trim(); me.name.trim();
} else } else break;
break;
} }
me.is_type_ptr = (me.type.right(1) == PIChar(']') || me.type.right(1) == PIChar('*')); me.is_type_ptr = (me.type.right(1) == PIChar(']') || me.type.right(1) == PIChar('*'));
me.type += crepl; me.type += crepl;
@@ -1002,22 +815,10 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
break; break;
} }
n.push_front(' '); n.push_front(' ');
if (n.find(s_s_const_s) >= 0) { if (n.find(s_s_const_s) >= 0) {n.replaceAll(s_s_const_s, ""); pref += s_const_s;}
n.replaceAll(s_s_const_s, ""); if (n.find(s_s_static_s) >= 0) {n.replaceAll(s_s_static_s, ""); pref += s_static_s;}
pref += s_const_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_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(); n.trim();
int f = 0; int f = 0;
piForeachC (Entity * e, entities) { piForeachC (Entity * e, entities) {
@@ -1117,25 +918,10 @@ double PICodeParser::procMacrosCond(PIString fc) {
while (!fc.isEmpty()) { while (!fc.isEmpty()) {
cc = fc[0].toAscii(); cc = fc[0].toAscii();
nc = (fc.size() > 1 ? fc[1].toAscii() : 0); nc = (fc.size() > 1 ? fc[1].toAscii() : 0);
if (cc == '!') { if (cc == '!') {neg = true; fc.pop_front(); continue;}
neg = true; if (cc == '(') {br = true; brv = procMacrosCond(fc.takeRange('(', ')'));}
fc.pop_front(); if (cc == '&' && nc == '&') {fc.remove(0, 2); oper = 1; continue;}
continue; if (cc == '|' && nc == '|') {fc.remove(0, 2); oper = 2; 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) { if (!br) {
ce = fc.takeCWord(); ce = fc.takeCWord();
if (ce.isEmpty()) ce = fc.takeNumber(); if (ce.isEmpty()) ce = fc.takeNumber();
@@ -1163,7 +949,8 @@ double PICodeParser::procMacrosCond(PIString fc) {
bool PICodeParser::isDefineExists(const PIString & dn) { bool PICodeParser::isDefineExists(const PIString & dn) {
piForeachC (Define & d, defines) { piForeachC (Define & d, defines) {
if (d.first == dn) return true; if (d.first == dn)
return true;
} }
return false; return false;
} }
@@ -1171,7 +958,8 @@ bool PICodeParser::isDefineExists(const PIString & dn) {
double PICodeParser::defineValue(const PIString & dn) { double PICodeParser::defineValue(const PIString & dn) {
piForeachC (Define & d, defines) { piForeachC (Define & d, defines) {
if (d.first == dn) return d.second.isEmpty() ? 1. : d.second.toDouble(); if (d.first == dn)
return d.second.isEmpty() ? 1. : d.second.toDouble();
} }
return dn.toDouble(); return dn.toDouble();
} }
@@ -1199,7 +987,8 @@ void PICodeParser::replaceMeta(PIString & dn) {
PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) { PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
piForeach (Entity * e, entities) piForeach (Entity * e, entities)
if (e->name == en) return e; if (e->name == en)
return e;
return 0; return 0;
} }
@@ -1207,14 +996,8 @@ PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) { bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) {
int dind = fc.find('{', start), find = fc.find(';', start); int dind = fc.find('{', start), find = fc.find(';', start);
//piCout << "isDeclaration" << dind << find << fc.left(10); //piCout << "isDeclaration" << dind << find << fc.left(10);
if (dind < 0 && find < 0) { if (dind < 0 && find < 0) {if (end) *end = -1; return true;}
if (end) *end = -1; if (dind < 0 || find < dind) {if (end) *end = find; return true;}
return true;
}
if (dind < 0 || find < dind) {
if (end) *end = find;
return true;
}
if (end) *end = dind; if (end) *end = dind;
return false; return false;
} }
@@ -1264,11 +1047,10 @@ PIString PICodeParser::procMacros(PIString fc) {
if (skip || grab) { if (skip || grab) {
if (mif.left(2) == s_if) ifcnt++; if (mif.left(2) == s_if) ifcnt++;
if (mif.left(5) == s_endif) { if (mif.left(5) == s_endif) {
if (ifcnt > 0) if (ifcnt > 0) ifcnt--;
ifcnt--;
else { else {
//piCout << "main endif" << skip << grab; //piCout << "main endif" << skip << grab;
if (grab) pfc += procMacros(nfc); if (grab) pfc << procMacros(nfc);
skip = grab = false; skip = grab = false;
continue; continue;
} }
@@ -1277,9 +1059,8 @@ PIString PICodeParser::procMacros(PIString fc) {
//piCout << "main elif" << skip << grab << cond_ok; //piCout << "main elif" << skip << grab << cond_ok;
if (cond_ok) { if (cond_ok) {
if (grab) { if (grab) {
pfc += procMacros(nfc); pfc << procMacros(nfc);
skip = true; skip = true; grab = false;
grab = false;
} }
continue; continue;
} }
@@ -1287,34 +1068,26 @@ PIString PICodeParser::procMacros(PIString fc) {
//piCout << "check elif" << skip << grab << cond_ok; //piCout << "check elif" << skip << grab << cond_ok;
if (!macroCondition(mif, mifcond.trimmed())) continue; if (!macroCondition(mif, mifcond.trimmed())) continue;
//piCout << "check elif ok"; //piCout << "check elif ok";
skip = false; skip = false; grab = cond_ok = true;
grab = cond_ok = true;
continue; continue;
} }
continue; continue;
} }
if (mif.left(4) == s_else && ifcnt == 0) { if (mif.left(4) == s_else && ifcnt == 0) {
//piCout << "main else" << skip << grab; //piCout << "main else" << skip << grab;
if (grab) pfc += procMacros(nfc); if (grab) pfc << procMacros(nfc);
if (skip && !cond_ok) { if (skip && !cond_ok) {skip = false; grab = true;}
skip = false; else {skip = true; grab = false;}
grab = true;
} else {
skip = true;
grab = false;
}
continue; continue;
} }
if (grab) nfc += line + '\n'; if (grab) nfc << line << '\n';
continue; continue;
} }
if (mif.left(2) == s_if) { if (mif.left(2) == s_if) {
//piCout << "main if"; //piCout << "main if";
skip = grab = cond_ok = false; skip = grab = cond_ok = false;
if (macroCondition(mif, mifcond.trimmed())) if (macroCondition(mif, mifcond.trimmed())) grab = cond_ok = true;
grab = cond_ok = true; else skip = true;
else
skip = true;
ifcnt = 0; ifcnt = 0;
nfc.clear(); nfc.clear();
} else { } else {
@@ -1322,10 +1095,8 @@ PIString PICodeParser::procMacros(PIString fc) {
//return false; /// WARNING: now skip errors //return false; /// WARNING: now skip errors
} }
} else { } else {
if (grab) if (grab) nfc << line << '\n';
nfc += line + '\n'; else if (!skip) pfc << line << '\n';
else if (!skip)
pfc += line + '\n';
} }
} }
return pfc; return pfc;
@@ -1376,10 +1147,7 @@ bool PICodeParser::parseDirective(PIString d) {
if (dname == s_undef) { if (dname == s_undef) {
PIString mname = d.takeCWord(); PIString mname = d.takeCWord();
for (int i = 0; i < defines.size_s(); ++i) for (int i = 0; i < defines.size_s(); ++i)
if (defines[i].first == mname) { if (defines[i].first == mname) {defines.remove(i); --i;}
defines.remove(i);
--i;
}
return true; return true;
} }
return true; return true;

View File

@@ -26,27 +26,17 @@
#ifndef PICODEPARSER_H #ifndef PICODEPARSER_H
#define PICODEPARSER_H #define PICODEPARSER_H
#include "pievaluator.h"
#include "pifile.h" #include "pifile.h"
#include "pievaluator.h"
inline bool _isCChar(const PIChar & c) { inline bool _isCChar(const PIChar & c) {return (c.isAlpha() || (c.toAscii() == '_'));}
return (c.isAlpha() || (c.toAscii() == '_')); inline bool _isCChar(const PIString & c) {if (c.isEmpty()) return false; return _isCChar(c[0]);}
}
inline bool _isCChar(const PIString & c) {
if (c.isEmpty()) return false;
return _isCChar(c[0]);
}
class PIP_EXPORT PICodeParser { class PIP_EXPORT PICodeParser {
public: public:
PICodeParser(); PICodeParser();
enum Visibility { enum Visibility {Global, Public, Protected, Private};
Global,
Public,
Protected,
Private
};
enum Attribute { enum Attribute {
NoAttributes = 0x0, NoAttributes = 0x0,
Const = 0x01, Const = 0x01,
@@ -120,18 +110,16 @@ public:
}; };
struct PIP_EXPORT EnumeratorInfo { struct PIP_EXPORT EnumeratorInfo {
EnumeratorInfo(const PIString & n = PIString(), int v = 0, const MetaMap & m = MetaMap()) { EnumeratorInfo(const PIString & n = PIString(), int v = 0, const MetaMap & m = MetaMap()) {name = n; value = v; meta = m;}
name = n;
value = v;
meta = m;
}
MetaMap meta; MetaMap meta;
PIString name; PIString name;
int value; int value;
}; };
struct PIP_EXPORT Enum { struct PIP_EXPORT Enum {
Enum(const PIString & n = PIString()) { name = n; } Enum(const PIString & n = PIString()) {
name = n;
}
MetaMap meta; MetaMap meta;
PIString name; PIString name;
PIVector<EnumeratorInfo> members; PIVector<EnumeratorInfo> members;
@@ -139,7 +127,6 @@ public:
void parseFile(const PIString & file, bool follow_includes = true); void parseFile(const PIString & file, bool follow_includes = true);
void parseFiles(const PIStringList & files, 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 includeDirectory(const PIString & dir) {includes << dir;}
void addDefine(const PIString & def_name, const PIString & def_value) {custom_defines << Define(def_name, def_value);} void addDefine(const PIString & def_name, const PIString & def_value) {custom_defines << Define(def_name, def_value);}
@@ -194,6 +181,7 @@ private:
PIString cur_namespace; PIString cur_namespace;
PIMap<PIString, PIString> tmp_temp; PIMap<PIString, PIString> tmp_temp;
PIMap<PIString, MetaMap> tmp_meta; PIMap<PIString, MetaMap> tmp_meta;
}; };
#endif // PICODEPARSER_H #endif // PICODEPARSER_H

View File

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

View File

@@ -16,15 +16,13 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "pikbdlistener.h"
#include "piincludes_p.h" #include "piincludes_p.h"
#include "piliterals.h" #include "pikbdlistener.h"
#ifndef WINDOWS #ifndef WINDOWS
# include <termios.h> # include <termios.h>
#else #else
# include <wincon.h>
# include <wingdi.h> # include <wingdi.h>
# include <wincon.h>
#endif #endif
/** \class PIKbdListener /** \class PIKbdListener
@@ -121,10 +119,8 @@ const PIKbdListener::EscSeq PIKbdListener::esc_seq[] = {
{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
}; };
void setupTerminal(bool on) { void setupTerminal(bool on) {
printf("\e[?1000"); printf("\e[?1000"); printf(on ? "h" : "l");
printf(on ? "h" : "l"); printf("\e[?1002"); printf(on ? "h" : "l");
printf("\e[?1002");
printf(on ? "h" : "l");
fflush(0); fflush(0);
} }
#endif #endif
@@ -148,7 +144,7 @@ PRIVATE_DEFINITION_END(PIKbdListener)
PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread() { PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread() {
setName("keyboard_listener"_a); setName("keyboard_listener");
_object = this; _object = this;
#ifdef WINDOWS #ifdef WINDOWS
PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE); PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE);
@@ -228,111 +224,33 @@ void PIKbdListener::readKeyboard() {
ke.modifiers = getModifiers(ker.dwControlKeyState, &shift); 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) { switch (ker.wVirtualKeyCode) {
case 8: case 8: PRIVATE->ret = 1; ke.key = Backspace; break;
PRIVATE->ret = 1; case 33: PRIVATE->ret = 1; ke.key = PageUp; break;
ke.key = Backspace; case 34: PRIVATE->ret = 1; ke.key = PageDown; break;
break; case 35: PRIVATE->ret = 1; ke.key = End; break;
case 33: case 36: PRIVATE->ret = 1; ke.key = Home; break;
PRIVATE->ret = 1; case 37: PRIVATE->ret = 1; ke.key = LeftArrow; break;
ke.key = PageUp; case 38: PRIVATE->ret = 1; ke.key = UpArrow; break;
break; case 39: PRIVATE->ret = 1; ke.key = RightArrow; break;
case 34: case 40: PRIVATE->ret = 1; ke.key = DownArrow; break;
PRIVATE->ret = 1; case 45: PRIVATE->ret = 1; ke.key = Insert; break;
ke.key = PageDown; case 46: PRIVATE->ret = 1; ke.key = Delete; break;
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 '\r':
case '\n': case '\n': PRIVATE->ret = 1; ke.key = Return; break;
PRIVATE->ret = 1; case ' ': PRIVATE->ret = 1; ke.key = Space; break;
ke.key = Return; case '\t': PRIVATE->ret = 1; ke.key = Tab; break;
break; case 112: PRIVATE->ret = 1; ke.key = F1; break;
case ' ': case 113: PRIVATE->ret = 1; ke.key = F2; break;
PRIVATE->ret = 1; case 114: PRIVATE->ret = 1; ke.key = F3; break;
ke.key = Space; case 115: PRIVATE->ret = 1; ke.key = F4; break;
break; case 116: PRIVATE->ret = 1; ke.key = F5; break;
case '\t': case 117: PRIVATE->ret = 1; ke.key = F6; break;
PRIVATE->ret = 1; case 118: PRIVATE->ret = 1; ke.key = F7; break;
ke.key = Tab; case 119: PRIVATE->ret = 1; ke.key = F8; break;
break; case 120: PRIVATE->ret = 1; ke.key = F9; break;
case 112: case 121: PRIVATE->ret = 1; ke.key = F10; break;
PRIVATE->ret = 1; case 122: PRIVATE->ret = 1; ke.key = F11; break;
ke.key = F1; case 123: PRIVATE->ret = 1; ke.key = F12; break;
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: default:
PRIVATE->ret = 1; PRIVATE->ret = 1;
rc[0] = 1; rc[0] = 1;
@@ -343,15 +261,10 @@ void PIKbdListener::readKeyboard() {
} }
break; break;
} }
if (ke.key == 0) { if (ke.key == 0) {piMSleep(10); return;}
piMSleep(10); } else {piMSleep(10); return;}
return;
} }
} else { break;
piMSleep(10);
return;
}
} break;
case MOUSE_EVENT: { case MOUSE_EVENT: {
MOUSE_EVENT_RECORD mer = ir.Event.MouseEvent; MOUSE_EVENT_RECORD mer = ir.Event.MouseEvent;
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
@@ -384,23 +297,24 @@ void PIKbdListener::readKeyboard() {
prev_p_me = me; prev_p_me = me;
} }
tm_dbl.reset(); 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; me.buttons = mb;
if (piCompareBinary(&prev_me, &me, sizeof(me))) break; if (piCompareBinary(&prev_me, &me, sizeof(me)))
break;
memcpy((void*)(&prev_me), (const void*)(&me), sizeof(me)); memcpy((void*)(&prev_me), (const void*)(&me), sizeof(me));
//PIString _s[] = {"press", "release", "dbl click", "move"}; //PIString _s[] = {"press", "release", "dbl click", "move"};
//piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y; //piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
mouseEvent(me, kbddata_); mouseEvent(me, kbddata_);
break; break;
} }
} break; }
default: piMSleep(10); return; break;
default:
piMSleep(10);
return;
} }
#else #else
tcsetattr(0, TCSANOW, &PRIVATE->tterm); tcsetattr(0, TCSANOW, &PRIVATE->tterm);
@@ -413,14 +327,8 @@ void PIKbdListener::readKeyboard() {
for (int i = 0; i < PRIVATE->ret; ++i) for (int i = 0; i < PRIVATE->ret; ++i)
std::cout << "'" << (char)(rc[i]) << "' " << (int)(uchar)(rc[i]); std::cout << "'" << (char)(rc[i]) << "' " << (int)(uchar)(rc[i]);
std::cout << std::endl;*/ std::cout << std::endl;*/
if (rc[0] == 0) { if (rc[0] == 0) {piMSleep(10); return;}
piMSleep(10); if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {piMSleep(10); return;}
return;
}
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {
piMSleep(10);
return;
}
if (PRIVATE->ret == 1) { if (PRIVATE->ret == 1) {
if (rc[0] == 8) if (rc[0] == 8)
ke.key = Backspace; ke.key = Backspace;
@@ -439,8 +347,7 @@ void PIKbdListener::readKeyboard() {
ke.key = PIChar::fromConsole(rc[1]).unicode16Code(); ke.key = PIChar::fromConsole(rc[1]).unicode16Code();
} else {// escape-seq } else {// escape-seq
if (rc[1] == '\e') { // search for Alt if (rc[1] == '\e') { // search for Alt
for (int i = 1; i < 7; ++i) for (int i = 1; i < 7; ++i) rc[i] = rc[i + 1];
rc[i] = rc[i + 1];
mod = 2; mod = 2;
PRIVATE->ret--; PRIVATE->ret--;
} }
@@ -489,8 +396,7 @@ void PIKbdListener::readKeyboard() {
for (int i = 2; i < 7; ++i) // search for modifier for (int i = 2; i < 7; ++i) // search for modifier
if (rc[i] == ';') { if (rc[i] == ';') {
mod |= rc[i + 1] - '0' - 1; mod |= rc[i + 1] - '0' - 1;
for (int j = i; j < 6; ++j) for (int j = i; j < 6; ++j) rc[j] = rc[j + 2];
rc[j] = rc[j + 2];
rc[6] = rc[7] = 0; rc[6] = rc[7] = 0;
PRIVATE->ret -= 2; PRIVATE->ret -= 2;
break; break;
@@ -500,8 +406,7 @@ void PIKbdListener::readKeyboard() {
if (PRIVATE->ret >= 3 && rc[1] == 'O') { // search for modifier (F1-F4) if (PRIVATE->ret >= 3 && rc[1] == 'O') { // search for modifier (F1-F4)
if (rc[2] >= '1' && rc[2] <= '8') { if (rc[2] >= '1' && rc[2] <= '8') {
mod |= rc[2] - '0' - 1; mod |= rc[2] - '0' - 1;
for (int j = 2; j < 6; ++j) for (int j = 2; j < 6; ++j) rc[j] = rc[j + 1];
rc[j] = rc[j + 1];
rc[7] = 0; rc[7] = 0;
PRIVATE->ret--; PRIVATE->ret--;
} }
@@ -527,9 +432,11 @@ void PIKbdListener::readKeyboard() {
cout << "'" << (char)(rc[i]) << "' "; cout << "'" << (char)(rc[i]) << "' ";
cout << endl;*/ 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 #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) { if (exit_enabled && ke.key == exit_key) {
PIKbdListener::exiting = true; PIKbdListener::exiting = true;
return; return;

View File

@@ -27,19 +27,17 @@
#define PIKBDLISTENER_H #define PIKBDLISTENER_H
#include "pithread.h" #include "pithread.h"
#include "pitime.h"
#define WAIT_FOR_EXIT \ #define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(PIP_MIN_MSLEEP*5); // TODO: rewrite with condvar
while (!PIKbdListener::exiting) \
piMSleep(PIP_MIN_MSLEEP * 5); // TODO: rewrite with condvar
class PIP_EXPORT PIKbdListener: public PIThread { class PIP_EXPORT PIKbdListener: public PIThread
PIOBJECT_SUBCLASS(PIKbdListener, PIThread); {
PIOBJECT_SUBCLASS(PIKbdListener, PIThread)
friend class PIConsole; friend class PIConsole;
friend class PITerminal; friend class PITerminal;
public: public:
//! Special keyboard keys //! Special keyboard keys
enum SpecialKey { enum SpecialKey {
Tab /** Tab key */ = 0x09, Tab /** Tab key */ = 0x09,
@@ -83,10 +81,7 @@ public:
//! This struct contains information about pressed keyboard key //! This struct contains information about pressed keyboard key
struct PIP_EXPORT KeyEvent { struct PIP_EXPORT KeyEvent {
KeyEvent(int k = 0, KeyModifiers m = 0) { KeyEvent(int k = 0, KeyModifiers m = 0) {key = k; modifiers = m;}
key = k;
modifiers = m;
}
//! Pressed key. It can be simple \b char or special key (see PIKbdListener::SpecialKey) //! Pressed key. It can be simple \b char or special key (see PIKbdListener::SpecialKey)
int key; int key;
@@ -115,12 +110,7 @@ public:
//! This struct contains information about mouse action //! This struct contains information about mouse action
struct PIP_EXPORT MouseEvent { struct PIP_EXPORT MouseEvent {
MouseEvent(MouseAction a = MouseButtonPress, MouseButtons b = 0, KeyModifiers m = 0) { MouseEvent(MouseAction a = MouseButtonPress, MouseButtons b = 0, KeyModifiers m = 0) {x = y = 0; action = a; buttons = b; modifiers = m;}
x = y = 0;
action = a;
buttons = b;
modifiers = m;
}
//! Event X coordinate in view-space, from 0 //! Event X coordinate in view-space, from 0
int x; int x;
@@ -164,9 +154,7 @@ public:
void setSlot(KBFunc slot) {ret_func = slot;} void setSlot(KBFunc slot) {ret_func = slot;}
//! Set external function to "slot" //! Set external function to "slot"
void setSlot(std::function<void(KeyEvent)> slot) { void setSlot(std::function<void(KeyEvent)> slot) {ret_func = [slot](KeyEvent e, void *){slot(e);};}
ret_func = [slot](KeyEvent e, void *) { slot(e); };
}
//! Returns if exit key if awaiting //! Returns if exit key if awaiting
bool exitCaptured() const {return exit_enabled;} bool exitCaptured() const {return exit_enabled;}
@@ -183,17 +171,14 @@ public:
bool isActive() {return is_active;} bool isActive() {return is_active;}
EVENT_HANDLER( void, enableExitCapture) {enableExitCapture('Q');} EVENT_HANDLER( void, enableExitCapture) {enableExitCapture('Q');}
EVENT_HANDLER1(void, enableExitCapture, int, key) { EVENT_HANDLER1(void, enableExitCapture, int, key) {exit_enabled = true; exit_key = key;}
exit_enabled = true;
exit_key = key;
}
EVENT_HANDLER(void, disableExitCapture) {exit_enabled = false;} EVENT_HANDLER(void, disableExitCapture) {exit_enabled = false;}
EVENT_HANDLER(void, setActive) {setActive(true);} EVENT_HANDLER(void, setActive) {setActive(true);}
EVENT_HANDLER1(void, setActive, bool, yes); EVENT_HANDLER1(void, setActive, bool, yes);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void *, data); EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void *, data); EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void * , data)
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void *, data); EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void * , data)
//! \handlers //! \handlers
//! \{ //! \{
@@ -220,9 +205,9 @@ public:
static PIKbdListener * instance() {return _object;} static PIKbdListener * instance() {return _object;}
private: private:
void begin() override; void begin();
void run() override { readKeyboard(); } void run() {readKeyboard();}
void end() override; void end();
#ifndef WINDOWS #ifndef WINDOWS
struct PIP_EXPORT EscSeq { struct PIP_EXPORT EscSeq {
@@ -258,42 +243,17 @@ private:
MouseEvent me, prev_me, prev_p_me; MouseEvent me, prev_me, prev_p_me;
WheelEvent we; WheelEvent we;
static PIKbdListener * _object; static PIKbdListener * _object;
}; };
//! \relatesalso PIBinaryStream inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::KeyEvent & v) {s << v.key << v.modifiers; return s;}
//! \~english Store operator inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::MouseEvent & v) {s << v.x << v.y << (int)v.action << v.buttons << v.modifiers; return s;}
//! \~russian Оператор сохранения inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::WheelEvent & v) {s << (*(PIKbdListener::MouseEvent*)&v) << (uchar)v.direction; return s;}
BINARY_STREAM_WRITE(PIKbdListener::MouseEvent) {
s << v.x << v.y << v.action << v.buttons << v.modifiers;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIKbdListener::MouseEvent) {
s >> v.x >> v.y >> v.action >> v.buttons >> v.modifiers;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Store operator
//! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIKbdListener::WheelEvent) {
s << (*(PIKbdListener::MouseEvent *)&v) << v.direction;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIKbdListener::WheelEvent) {
s >> (*(PIKbdListener::MouseEvent *)&v) >> v.direction;
return s;
}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::KeyEvent & v) {s >> v.key >> v.modifiers; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::MouseEvent & v) {int a(0); s >> v.x >> v.y >> a >> v.buttons >> v.modifiers; v.action = (PIKbdListener::MouseAction)a; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::WheelEvent & v) {uchar d(0); s >> (*(PIKbdListener::MouseEvent*)&v) >> d; v.direction = d; return s;}
REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent) REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent)
REGISTER_PIVARIANTSIMPLE(PIKbdListener::MouseEvent) REGISTER_PIVARIANTSIMPLE(PIKbdListener::MouseEvent)

View File

@@ -27,17 +27,16 @@
#define PISCREEN_H #define PISCREEN_H
#include "pip_console_export.h" #include "pip_console_export.h"
#include "piscreendrawer.h"
#include "piscreentile.h" #include "piscreentile.h"
#include "piscreendrawer.h"
class PIP_CONSOLE_EXPORT PIScreen class PIP_CONSOLE_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase
: public PIThread {
, public PIScreenTypes::PIScreenBase { PIOBJECT_SUBCLASS(PIScreen, PIThread)
PIOBJECT_SUBCLASS(PIScreen, PIThread);
class SystemConsole; class SystemConsole;
public: public:
//! Constructs %PIScreen with key handler "slot" and if "startNow" start it //! Constructs %PIScreen with key handler "slot" and if "startNow" start it
PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0); PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0);
@@ -73,15 +72,12 @@ public:
EVENT_HANDLER0(void, waitForFinish); EVENT_HANDLER0(void, waitForFinish);
EVENT_HANDLER0(void, start) {start(false);} EVENT_HANDLER0(void, start) {start(false);}
EVENT_HANDLER1(void, start, bool, wait) { EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();}
PIThread::start(40);
if (wait) waitForFinish();
}
EVENT_HANDLER0(void, stop) {stop(false);} EVENT_HANDLER0(void, stop) {stop(false);}
EVENT_HANDLER1(void, stop, bool, clear); EVENT_HANDLER1(void, stop, bool, clear);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void *, data); EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
EVENT2(tileEvent, PIScreenTile *, tile, PIScreenTypes::TileEvent, e); EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e)
//! \handlers //! \handlers
//! \{ //! \{
@@ -138,9 +134,9 @@ private:
PIVector<PIVector<PIScreenTypes::Cell> > cells, pcells; PIVector<PIVector<PIScreenTypes::Cell> > cells, pcells;
}; };
void begin() override; void begin();
void run() override; void run();
void end() override; void end();
void key_event(PIKbdListener::KeyEvent key); void key_event(PIKbdListener::KeyEvent key);
EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me); EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me);
EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we); EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we);
@@ -149,9 +145,9 @@ private:
PIVector<PIScreenTile*> prepareMouse(PIKbdListener::MouseEvent * e); PIVector<PIScreenTile*> prepareMouse(PIKbdListener::MouseEvent * e);
PIVector<PIScreenTile*> tilesUnderMouse(int x, int y); PIVector<PIScreenTile*> tilesUnderMouse(int x, int y);
bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent()); bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent());
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e) override; void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e);
void tileRemovedInternal(PIScreenTile * t) override; void tileRemovedInternal(PIScreenTile * t);
void tileSetFocusInternal(PIScreenTile * t) override; void tileSetFocusInternal(PIScreenTile * t);
bool mouse_; bool mouse_;
SystemConsole console; SystemConsole console;
@@ -160,6 +156,7 @@ private:
PIKbdListener::KBFunc ret_func; PIKbdListener::KBFunc ret_func;
PIScreenTile root; PIScreenTile root;
PIScreenTile * tile_focus, * tile_dialog; PIScreenTile * tile_focus, * tile_dialog;
}; };

View File

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

View File

@@ -30,10 +30,10 @@
#include "piscreentypes.h" #include "piscreentypes.h"
#include "pistring.h" #include "pistring.h"
class PIP_CONSOLE_EXPORT PIScreenDrawer { class PIP_CONSOLE_EXPORT PIScreenDrawer
{
friend class PIScreen; friend class PIScreen;
PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell> > & c); PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell> > & c);
public: public:
enum ArtChar { enum ArtChar {
LineVertical = 1, LineVertical = 1,
@@ -49,49 +49,12 @@ public:
void clear(); void clear();
void clearRect(int x0, int y0, int x1, int y1) {fillRect(x0, y0, x1, y1, ' ');} void clearRect(int x0, int y0, int x1, int y1) {fillRect(x0, y0, x1, y1, ' ');}
void drawPixel(int x, 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);
int y, 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);
const PIChar & c, 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);
PIScreenTypes::Color col_char = PIScreenTypes::Default, 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);
PIScreenTypes::Color col_back = PIScreenTypes::Default, 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);
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 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 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(' '));}
@@ -102,6 +65,7 @@ private:
PIVector<PIVector<PIScreenTypes::Cell> > & cells; PIVector<PIVector<PIScreenTypes::Cell> > & cells;
int width, height; int width, height;
PIMap<ArtChar, PIChar> arts_; PIMap<ArtChar, PIChar> arts_;
}; };

View File

@@ -26,20 +26,17 @@
#ifndef PISCREENTILE_H #ifndef PISCREENTILE_H
#define PISCREENTILE_H #define PISCREENTILE_H
#include "pikbdlistener.h"
#include "pip_console_export.h" #include "pip_console_export.h"
#include "piscreentypes.h" #include "piscreentypes.h"
#include "pikbdlistener.h"
class PIScreenDrawer; class PIScreenDrawer;
class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject { class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject {
friend class PIScreen; friend class PIScreen;
PIOBJECT_SUBCLASS(PIScreenTile, PIObject); PIOBJECT_SUBCLASS(PIScreenTile, PIObject)
public: public:
PIScreenTile(const PIString & n = PIString(), PIScreenTile(const PIString & n = PIString(), PIScreenTypes::Direction d = PIScreenTypes::Vertical, PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
PIScreenTypes::Direction d = PIScreenTypes::Vertical,
PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
virtual ~PIScreenTile(); virtual ~PIScreenTile();
void addTile(PIScreenTile * t); void addTile(PIScreenTile * t);
@@ -53,12 +50,7 @@ public:
void setFocus(); void setFocus();
bool hasFocus() const {return has_focus;} bool hasFocus() const {return has_focus;}
void setMargins(int m) {marginLeft = marginRight = marginTop = marginBottom = m;} void setMargins(int m) {marginLeft = marginRight = marginTop = marginBottom = m;}
void setMargins(int l, int r, int t, int b) { void setMargins(int l, int r, int t, int b) {marginLeft = l; marginRight = r; marginTop = t; marginBottom = b;}
marginLeft = l;
marginRight = r;
marginTop = t;
marginBottom = b;
}
int x() const {return x_;} int x() const {return x_;}
int y() const {return y_;} int y() const {return y_;}
@@ -77,6 +69,7 @@ public:
bool visible; bool visible;
protected: protected:
//! Returns desired tile size in "w" and "h" //! Returns desired tile size in "w" and "h"
virtual void sizeHint(int & w, int & h) const; virtual void sizeHint(int & w, int & h) const;
@@ -110,6 +103,7 @@ protected:
private: private:
int pw, ph; int pw, ph;
}; };

View File

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

View File

@@ -110,10 +110,7 @@ union PIP_CONSOLE_EXPORT CellFormat {
}; };
struct PIP_CONSOLE_EXPORT Cell { struct PIP_CONSOLE_EXPORT Cell {
Cell(PIChar c = PIChar(' '), CellFormat f = CellFormat()) { Cell(PIChar c = PIChar(' '), CellFormat f = CellFormat()) {symbol = c; format = f;}
symbol = c;
format = f;
}
CellFormat format; CellFormat format;
PIChar symbol; 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;}
@@ -123,8 +120,7 @@ struct PIP_CONSOLE_EXPORT Cell {
if (c.format.color_back == Transparent) { if (c.format.color_back == Transparent) {
format.color_char = c.format.color_char; format.color_char = c.format.color_char;
format.flags = c.format.flags; format.flags = c.format.flags;
} else } else format = c.format;
format = c.format;
return *this; return *this;
} }
}; };
@@ -144,45 +140,14 @@ public:
virtual void tileSetFocusInternal(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 inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::Cell & v) {s << v.format.raw_format << v.symbol; return s;}
//! \~english Store operator inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::Cell & v) {s >> v.format.raw_format >> v.symbol; return s;}
//! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIScreenTypes::TileEvent) {
s << v.type << v.data;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIScreenTypes::TileEvent) {
s >> v.type >> v.data;
return s;
}
inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::TileEvent & v) {s << v.type << v.data; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::TileEvent & v) {s >> v.type >> v.data; return s;}
REGISTER_PIVARIANTSIMPLE(PIScreenTypes::TileEvent) REGISTER_PIVARIANTSIMPLE(PIScreenTypes::TileEvent)

View File

@@ -26,15 +26,16 @@
#ifndef PITERMINAL_H #ifndef PITERMINAL_H
#define PITERMINAL_H #define PITERMINAL_H
#include "pikbdlistener.h"
#include "pip_console_export.h" #include "pip_console_export.h"
#include "pikbdlistener.h"
#include "piscreentypes.h" #include "piscreentypes.h"
class PIP_CONSOLE_EXPORT PITerminal: public PIThread { class PIP_CONSOLE_EXPORT PITerminal: public PIThread
PIOBJECT_SUBCLASS(PITerminal, PIThread); {
PIOBJECT_SUBCLASS(PITerminal, PIThread)
public: public:
//! Constructs %PITerminal //! Constructs %PITerminal
PITerminal(); PITerminal();
@@ -52,13 +53,12 @@ public:
bool initialize(); bool initialize();
void destroy(); void destroy();
private: private:
void initPrivate(); void initPrivate();
void readConsole(); void readConsole();
void getCursor(int & x, int & y); void getCursor(int & x, int & y);
uchar invertColor(uchar c); uchar invertColor(uchar c);
void run() override; void run();
#ifndef WINDOWS #ifndef WINDOWS
void parseInput(const PIString & s); void parseInput(const PIString & s);
bool isCompleteEscSeq(const PIString & es); bool isCompleteEscSeq(const PIString & es);
@@ -73,6 +73,7 @@ private:
bool cursor_blink, cursor_visible; bool cursor_blink, cursor_visible;
PITimeMeasurer cursor_tm; PITimeMeasurer cursor_tm;
PIVector<PIVector<PIScreenTypes::Cell> > cells; PIVector<PIVector<PIScreenTypes::Cell> > cells;
}; };

View File

@@ -20,12 +20,11 @@
#include "picontainers.h" #include "picontainers.h"
const size_t minAlloc = 64; const ssize_t minAlloc = 64;
size_t _PIContainerConstantsBase::calcMinCountPoT(size_t szof) { ssize_t _PIContainerConstantsBase::calcMinCountPoT(ssize_t szof) {
size_t ret = 0; ssize_t ret = 0, elc = 1;
size_t elc = 1;
while (elc * szof < minAlloc) { while (elc * szof < minAlloc) {
elc *= 2; elc *= 2;
++ret; ++ret;

View File

@@ -41,12 +41,12 @@
#else #else
# include <malloc.h> # include <malloc.h>
#endif #endif
#include <initializer_list>
#include <type_traits>
#include <string.h>
#include <new>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <initializer_list>
#include <new>
#include <string.h>
#include <type_traits>
template <typename C> template <typename C>
@@ -58,7 +58,6 @@ public:
typename C::reverse_iterator end() {return c_.rend(); } typename C::reverse_iterator end() {return c_.rend(); }
typename C::const_reverse_iterator begin() const {return c_.rbegin();} typename C::const_reverse_iterator begin() const {return c_.rbegin();}
typename C::const_reverse_iterator end() const {return c_.rend(); } typename C::const_reverse_iterator end() const {return c_.rend(); }
private: private:
C & c_; C & c_;
}; };
@@ -66,30 +65,21 @@ private:
class PIP_EXPORT _PIContainerConstantsBase { class PIP_EXPORT _PIContainerConstantsBase {
public: public:
static size_t calcMinCountPoT(size_t szof); static ssize_t calcMinCountPoT(ssize_t szof);
}; };
template<typename T> template<typename T>
class _PIContainerConstants { class _PIContainerConstants {
public: public:
static size_t minCountPoT() { static ssize_t minCountPoT() {static ssize_t ret = _PIContainerConstantsBase::calcMinCountPoT(sizeof(T)); return ret;}
static const size_t ret = _PIContainerConstantsBase::calcMinCountPoT(sizeof(T));
return ret;
}
}; };
//! \brief //! \brief
//! \~english Template reverse wrapper over any container //! \~english Template reverse wrapper over any container
//! \~russian Шаблонная функция обертки любого контейнера для обратного доступа через итераторы //! \~russian Шаблонная функция обертки любого контейнера для обратного доступа через итераторы
template<typename C> template <typename C> _PIReverseWrapper<C> PIReverseWrap(C & c) {return _PIReverseWrapper<C>(c);}
_PIReverseWrapper<C> PIReverseWrap(C & c) { template <typename C> _PIReverseWrapper<C> PIReverseWrap(const C & c) {return _PIReverseWrapper<C>(c);}
return _PIReverseWrapper<C>(c);
}
template<typename C>
_PIReverseWrapper<C> PIReverseWrap(const C & c) {
return _PIReverseWrapper<C>(c);
}
//! \brief //! \brief
@@ -187,9 +177,7 @@ _PIReverseWrapper<C> PIReverseWrap(const C & c) {
//! \~russian Порядок обхода для функции изменения размерности reshape(). //! \~russian Порядок обхода для функции изменения размерности reshape().
//! \~ \sa \a PIVector::reshape(), \a PIDeque::reshape() //! \~ \sa \a PIVector::reshape(), \a PIDeque::reshape()
enum ReshapeOrder { 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 Обход элементов по столбцам */, ReshapeByColumn /*! \~english Traversing elements by column \~russian Обход элементов по столбцам */,
}; };

View File

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

View File

@@ -75,9 +75,9 @@
//! if the number of elements is known beforehand. //! if the number of elements is known beforehand.
//! //!
//! The complexity (efficiency) of common operations on PIDeque is as follows: //! The complexity (efficiency) of common operations on PIDeque is as follows:
//! - Random access - constant O(1) //! - Random access - constant 𝓞(1)
//! - Insertion or removal of elements at the end or begin - amortized constant O(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 O(n) //! - Insertion or removal of elements - linear in the distance to the end of the array 𝓞(n)
//! //!
//! \~russian //! \~russian
//! Элементы хранятся непрерывно, а значит доступны не только через итераторы, //! Элементы хранятся непрерывно, а значит доступны не только через итераторы,
@@ -109,9 +109,9 @@
//! если количество элементов известно заранее. //! если количество элементов известно заранее.
//! //!
//! Сложность (эффективность) обычных операций над PIDeque следующая: //! Сложность (эффективность) обычных операций над PIDeque следующая:
//! - Произвольный доступ — постоянная O(1) //! - Произвольный доступ — постоянная 𝓞(1)
//! - Вставка и удаление элементов в конце или начале — амортизированная постоянная O(1) //! - Вставка и удаление элементов в конце или начале — амортизированная постоянная 𝓞(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива O(n) //! - Вставка и удаление элементов — линейная по расстоянию до конца массива 𝓞(n)
//! //!
//! \~\sa \a PIVector, \a PIMap //! \~\sa \a PIVector, \a PIMap
template <typename T> template <typename T>
@@ -127,11 +127,13 @@ public:
//! \~english Constructs an empty array. //! \~english Constructs an empty array.
//! \~russian Создает пустой массив. //! \~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. //! \~english Copy constructor.
//! \~russian Копирующий конструктор. //! \~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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(other.pid_size); alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size); newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
@@ -146,7 +148,7 @@ public:
//! PIDeque <int> v{1,2,3}; //! PIDeque <int> v{1,2,3};
//! piCout << v; // {1, 2, 3} //! piCout << v; // {1, 2, 3}
//! \endcode //! \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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(init_list.size()); alloc_forward(init_list.size());
newT(pid_data, init_list.begin(), 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. //! This constructor reserve `size` and copy from `data` pointer.
//! \~russian Создает массив из указателя на данные `data` и размер `size`. //! \~russian Создает массив из указателя на данные `data` и размер `size`.
//! То есть выделяет память для `size` элементов и копирует данные из указателя `data`. //! То есть выделяет память для `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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(size); alloc_forward(size);
newT(pid_data + pid_start, data, pid_size); newT(pid_data + pid_start, data, pid_size);
@@ -164,9 +166,9 @@ public:
//! \~english Contructs array with size `size` filled elements `e`. //! \~english Contructs array with size `size` filled elements `e`.
//! \~russian Создает массив из `size` элементов заполненных `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)) 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)`. //! \~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;}); //! PIDeque <int> v(5, [](size_t i){return i*2;});
//! piCout << v; // {0, 2, 4, 6, 8} //! piCout << v; // {0, 2, 4, 6, 8}
//! \endcode //! \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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
expand(piv_size, f); resize(piv_size, f);
} }
//! \~english Move constructor. //! \~english Move constructor.
//! \~russian Перемещающий конструктор. //! \~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)) 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(); other._reset();
} }
inline ~PIDeque() { inline virtual ~PIDeque() {
PIINTROSPECTION_CONTAINER_DELETE(T) PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (pid_rsize)) PIINTROSPECTION_CONTAINER_FREE(T, (pid_rsize))
deleteT(pid_data + pid_start, pid_size); deleteT(pid_data + pid_start, pid_size);
dealloc(); dealloc();
_reset();
} }
//! \~english Assign operator. //! \~english Assign operator.
//! \~russian Оператор присваивания. //! \~russian Оператор присваивания.
inline PIDeque<T> & operator =(const PIDeque<T> & other) { inline PIDeque<T> & operator =(const PIDeque<T> & other) {
if (this == &other) return *this; if (this == &other) return *this;
clear(); deleteT(pid_data + pid_start, pid_size);
alloc_forward(other.pid_size); alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size); newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
return *this; return *this;
@@ -224,12 +223,10 @@ public:
class iterator { class iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: private:
inline iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {} inline iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
PIDeque<T> * parent; PIDeque<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T* pointer; typedef T* pointer;
@@ -249,7 +246,7 @@ public:
return *this; return *this;
} }
inline iterator operator ++(int) { inline iterator operator ++(int) {
const auto tmp = *this; auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -258,7 +255,7 @@ public:
return *this; return *this;
} }
inline iterator operator --(int) { inline iterator operator --(int) {
const auto tmp = *this; auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -286,7 +283,9 @@ public:
tmp -= p; tmp -= p;
return tmp; 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 +(size_t p, const iterator & it) {return it + p;}
friend inline iterator operator +(const iterator & it, size_t p) { friend inline iterator operator +(const iterator & it, size_t p) {
@@ -297,20 +296,26 @@ public:
inline bool operator ==(const iterator & it) const {return (pos == it.pos);} inline bool operator ==(const iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const iterator & it) const {return (pos != it.pos);} inline bool operator !=(const iterator & it) const {return (pos != it.pos);}
friend inline bool operator<(const iterator & it1, const iterator & it2) { return it1.pos < it2.pos; } friend inline bool operator <(const iterator & it1, const iterator & it2) {
friend inline bool operator<=(const iterator & it1, const iterator & it2) { return it1.pos <= it2.pos; } 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;
}
friend inline bool operator >(const iterator & it1, const iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const iterator & it1, const iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class const_iterator { class const_iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: private:
inline const_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {} inline const_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
const PIDeque<T> * parent; const PIDeque<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T* pointer; typedef T* pointer;
@@ -328,7 +333,7 @@ public:
return *this; return *this;
} }
inline const_iterator operator ++(int) { inline const_iterator operator ++(int) {
const auto tmp = *this; auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -337,7 +342,7 @@ public:
return *this; return *this;
} }
inline const_iterator operator --(int) { inline const_iterator operator --(int) {
const auto tmp = *this; auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -365,7 +370,9 @@ public:
tmp -= p; tmp -= p;
return tmp; 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 +(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 +(const const_iterator & it, size_t p) {
@@ -376,20 +383,26 @@ public:
inline bool operator ==(const const_iterator & it) const {return (pos == it.pos);} inline bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const const_iterator & it) const {return (pos != it.pos);} inline bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
friend inline bool operator<(const const_iterator & it1, const const_iterator & it2) { return it1.pos < it2.pos; } friend inline bool operator <(const const_iterator & it1, const const_iterator & it2) {
friend inline bool operator<=(const const_iterator & it1, const const_iterator & it2) { return it1.pos <= it2.pos; } 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;
}
friend inline bool operator >(const const_iterator & it1, const const_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const const_iterator & it1, const const_iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class reverse_iterator { class reverse_iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: private:
inline reverse_iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {} inline reverse_iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
PIDeque<T> * parent; PIDeque<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T* pointer; typedef T* pointer;
@@ -409,7 +422,7 @@ public:
return *this; return *this;
} }
inline reverse_iterator operator ++(int) { inline reverse_iterator operator ++(int) {
const auto tmp = *this; auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -418,7 +431,7 @@ public:
return *this; return *this;
} }
inline reverse_iterator operator --(int) { inline reverse_iterator operator --(int) {
const auto tmp = *this; auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -446,7 +459,9 @@ public:
tmp -= p; tmp -= p;
return tmp; 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 +(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 +(const reverse_iterator & it, size_t p) {
@@ -457,20 +472,26 @@ public:
inline bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);} inline bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);} inline bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
friend inline bool operator<(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos < it2.pos; } friend inline bool operator <(const reverse_iterator & it1, const reverse_iterator & it2) {
friend inline bool operator<=(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos <= it2.pos; } 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;
}
friend inline bool operator >(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class const_reverse_iterator { class const_reverse_iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: private:
inline const_reverse_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {} inline const_reverse_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
const PIDeque<T> * parent; const PIDeque<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T* pointer; typedef T* pointer;
@@ -487,7 +508,7 @@ public:
return *this; return *this;
} }
inline const_reverse_iterator operator ++(int) { inline const_reverse_iterator operator ++(int) {
const auto tmp = *this; auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -496,7 +517,7 @@ public:
return *this; return *this;
} }
inline const_reverse_iterator operator --(int) { inline const_reverse_iterator operator --(int) {
const auto tmp = *this; auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -537,10 +558,18 @@ public:
inline bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);} inline bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);} inline bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
friend inline bool operator<(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos < it2.pos; } friend inline bool operator <(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {
friend inline bool operator<=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos <= it2.pos; } 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;
}
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;
}
}; };
@@ -584,8 +613,7 @@ public:
//! \~english Returns a reverse iterator to the element. //! \~english Returns a reverse iterator to the element.
//! following the last element of the reversed array. //! following the last element of the reversed array.
//! \~russian Обратный итератор на элемент, //! \~russian Обратный итератор на элемент, следующий за последним элементом.
//! следующий за последним элементом.
//! \~\details ![rbegin, rend](doc/images/pivector_rbegin.png) //! \~\details ![rbegin, rend](doc/images/pivector_rbegin.png)
//! //!
//! \~english It corresponds to the element preceding the first element of the non-reversed array. //! \~english It corresponds to the element preceding the first element of the non-reversed array.
@@ -617,7 +645,7 @@ public:
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. //! \~english Number of elements that the container has currently allocated space for.
//! \~russian Количество элементов, для которого сейчас выделена память массивом. //! \~russian Количество элементов, для которого сейчас выделена память контейнером.
//! \~\details //! \~\details
//! \~english To find out the actual number of items, use the function \a size(). //! \~english To find out the actual number of items, use the function \a size().
//! \~russian Чтобы узнать фактическое количество элементов используйте функцию \a size(). //! \~russian Чтобы узнать фактическое количество элементов используйте функцию \a size().
@@ -627,18 +655,18 @@ public:
inline size_t _start() const {return pid_start;} inline size_t _start() const {return pid_start;}
//! \~english Checks if the container has no elements. //! \~english Checks if the container has no elements.
//! \~russian Проверяет пуст ли массив. //! \~russian Проверяет пуст ли контейнер.
//! \~\return //! \~\return
//! \~english **true** if the container is empty, **false** otherwise //! \~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() //! \~\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. //! \~english Checks if the container has elements.
//! \~russian Проверяет не пуст ли массив. //! \~russian Проверяет не пуст ли контейнер.
//! \~\return //! \~\return
//! \~english **true** if the container is not empty, **false** otherwise //! \~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() //! \~\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);}
@@ -661,7 +689,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a every(), \a contains(), \a entries(), \a forEach() //! \~\sa \a every(), \a contains(), \a entries(), \a forEach()
inline bool any(std::function<bool(const T & e)> test) const { 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; if (test(pid_data[i])) return true;
} }
return false; return false;
@@ -686,7 +714,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a any(), \a contains(), \a entries(), \a forEach() //! \~\sa \a any(), \a contains(), \a entries(), \a forEach()
inline bool every(std::function<bool(const T & e)> test) const { 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; if (!test(pid_data[i])) return false;
} }
return true; return true;
@@ -722,34 +750,6 @@ public:
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти. //! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline const T & at(size_t index) const {return pid_data[pid_start + index];} inline const T & at(size_t index) const {return pid_data[pid_start + index];}
//! \~english Returns the first element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает первый элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a indexWhere()
inline const T & atWhere(std::function<bool(const T & e)> test, ssize_t start = 0, const T & def = T()) const {
const ssize_t i = indexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
//! \~english Returns the last element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает последний элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a lastIndexWhere()
inline const T & lastAtWhere(std::function<bool(const T & e)> test, ssize_t start = -1, const T & def = T()) const {
const ssize_t i = lastIndexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
//! \~english Last element. //! \~english Last element.
//! \~russian Последний элемент массива. //! \~russian Последний элемент массива.
//! \~\details //! \~\details
@@ -804,7 +804,7 @@ public:
//! возвращается **false**, что означает, что массив даже не просматривается. //! возвращается **false**, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIDeque<int> v{1, 2, 3, 4}; //! PIDeque<int> v{1, 2, 3, 4};
@@ -825,39 +825,12 @@ public:
start = pid_size + start; start = pid_size + start;
if (start < 0) start = 0; 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; if (e == pid_data[i]) return true;
} }
return false; 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. //! \~english Count elements equal `e` in the array.
//! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве. //! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве.
//! \~\details //! \~\details
@@ -874,7 +847,7 @@ public:
//! возвращается 0, что означает, что массив даже не просматривается. //! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIDeque<int> v{2, 2, 4, 2, 6}; //! PIDeque<int> v{2, 2, 4, 2, 6};
@@ -883,13 +856,13 @@ public:
//! piCout << v.entries(2, -4); // 2 //! piCout << v.entries(2, -4); // 2
//! \endcode //! \endcode
//! \~\sa \a every(), \a any(), \a contains(), \a forEach(), \a indexOf() //! \~\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; int ec = 0;
if (start < 0) { if (start < 0) {
start = pid_size + start; start = pid_size + start;
if (start < 0) start = 0; 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; if (e == pid_data[i]) ++ec;
} }
return ec; return ec;
@@ -914,16 +887,16 @@ public:
//! возвращается 0, что означает, что массив даже не просматривается. //! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\sa \a every(), \a any(), \a contains(), \a forEach(), \a indexWhere() //! \~\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; int ec = 0;
if (start < 0) { if (start < 0) {
start = pid_size + start; start = pid_size + start;
if (start < 0) start = 0; 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; if (test(pid_data[i])) ++ec;
} }
return ec; return ec;
@@ -947,7 +920,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается. //! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIDeque<int> v{2, 5, 9}; //! PIDeque<int> v{2, 5, 9};
@@ -958,14 +931,14 @@ public:
//! piCout << v.indexOf(2, -3); // 0 //! piCout << v.indexOf(2, -3); // 0
//! \endcode //! \endcode
//! \~\sa \a indexWhere(), \a lastIndexOf(), \a lastIndexWhere(), \a contains() //! \~\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) { if (start < 0) {
start = pid_size + start; start = pid_size + start;
if (start < 0) start = 0; 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]) { if (e == pid_data[i]) {
return ssize_t(i) - pid_start; return i - pid_start;
} }
} }
return -1; return -1;
@@ -990,7 +963,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается. //! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIDeque<PIString> v{"do", "re", "mi", "re"}; //! PIDeque<PIString> v{"do", "re", "mi", "re"};
@@ -999,14 +972,14 @@ public:
//! piCout << v.indexWhere([](const PIString & s){return s.startsWith('k');}); // -1 //! piCout << v.indexWhere([](const PIString & s){return s.startsWith('k');}); // -1
//! \endcode //! \endcode
//! \~\sa \a indexOf(), \a lastIndexOf(), \a lastIndexWhere(), \a contains() //! \~\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) { if (start < 0) {
start = pid_size + start; start = pid_size + start;
if (start < 0) start = 0; 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])) { if (test(pid_data[i])) {
return ssize_t(i) - pid_start; return i - pid_start;
} }
} }
return -1; return -1;
@@ -1032,7 +1005,7 @@ public:
//! c которого начинать поиск в обратном направлении. //! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив. //! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу.
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается. //! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента //! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив. //! и означает, что просматривается весь массив.
@@ -1049,9 +1022,9 @@ public:
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const { inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
if (start >= size_s()) start = pid_size - 1; if (start >= size_s()) start = pid_size - 1;
if (start < 0) start = pid_size + start; 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]) { if (e == pid_data[i]) {
return i - ssize_t(pid_start); return i - pid_start;
} }
} }
return -1; return -1;
@@ -1077,7 +1050,7 @@ public:
//! c которого начинать поиск в обратном направлении. //! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив. //! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу.
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается. //! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента //! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив. //! и означает, что просматривается весь массив.
@@ -1085,9 +1058,9 @@ public:
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const { 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 >= size_s()) start = pid_size - 1;
if (start < 0) start = pid_size + start; 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])) { if (test(pid_data[i])) {
return i - ssize_t(pid_start); return i - pid_start;
} }
} }
return -1; return -1;
@@ -1146,7 +1119,7 @@ public:
PIDeque<T> getRange(size_t index, size_t count) const { PIDeque<T> getRange(size_t index, size_t count) const {
if (index >= pid_size || count == 0) return PIDeque<T>(); if (index >= pid_size || count == 0) return PIDeque<T>();
if (index + count > pid_size) count = pid_size - index; 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. //! \~english Clear array, remove all elements.
@@ -1156,14 +1129,16 @@ public:
//! \~english Reserved memory will not be released. //! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится. //! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize() //! \~\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() { inline PIDeque<T> & clear() {
deleteT(pid_data + pid_start, pid_size); resize(0);
pid_size = 0;
pid_start = (pid_rsize - pid_size) / 2;
return *this; 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() { inline PIDeque<T> & clear() {
PIINTROSPECTION_CONTAINER_UNUSED(T, pid_size) PIINTROSPECTION_CONTAINER_UNUSED(T, pid_size)
pid_size = 0; pid_size = 0;
@@ -1215,12 +1190,16 @@ public:
//! \~english First does `resize(new_size)` then `fill(e)`. //! \~english First does `resize(new_size)` then `fill(e)`.
//! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`. //! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`.
//! \~\sa \a fill(), \a resize() //! \~\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) { inline PIDeque<T> & assign(size_t new_size, const T & e) {
resize(new_size); resize(new_size);
return fill(e); 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) { inline PIDeque<T> & assign(size_t new_size, const T & e) {
_resizeRaw(new_size); _resizeRaw(new_size);
return fill(e); return fill(e);
@@ -1238,12 +1217,20 @@ public:
//! лишние элементы удаляются с конца массива. //! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear() //! \~\sa \a size(), \a clear()
inline PIDeque<T> & resize(size_t new_size, const T & e = T()) { inline PIDeque<T> & resize(size_t new_size, const T & e = T()) {
if (new_size == 0) return clear();
if (new_size < pid_size) { 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; pid_size = new_size;
} else if (new_size > pid_size) { if (new_size == 0) {
expand(new_size, e); 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; return *this;
} }
@@ -1260,31 +1247,41 @@ public:
//! лишние элементы удаляются с конца массива. //! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear() //! \~\sa \a size(), \a clear()
inline PIDeque<T> & resize(size_t new_size, std::function<T(size_t i)> f) { 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) { 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; pid_size = new_size;
} else if (new_size > pid_size) { if (new_size == 0) {
expand(new_size, f); 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; 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) { inline PIDeque<T> & _resizeRaw(size_t new_size) {
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
if (new_size > pid_size) { 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) { 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); alloc_forward(new_size);
return *this; 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. //! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов. //! \~russian Резервируется память под как минимум `new_size` элементов.
@@ -1302,7 +1299,7 @@ public:
//! \~\sa \a size(), \a capacity(), \a resize() //! \~\sa \a size(), \a capacity(), \a resize()
inline PIDeque<T> & reserve(size_t new_size) { inline PIDeque<T> & reserve(size_t new_size) {
if (new_size <= pid_rsize) return *this; if (new_size <= pid_rsize) return *this;
const size_t os = pid_size; size_t os = pid_size;
alloc_forward(new_size); alloc_forward(new_size);
pid_size = os; pid_size = os;
return *this; return *this;
@@ -1322,21 +1319,17 @@ public:
inline PIDeque<T> & insert(size_t index, const T & e = T()) { inline PIDeque<T> & insert(size_t index, const T & e = T()) {
if (index == pid_size) return push_back(e); if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1) 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) { if (dir) {
alloc_forward(pid_size + 1); alloc_forward(pid_size + 1);
if (index < pid_size - 1) { if (index < pid_size - 1) {
const size_t os = pid_size - index - 1; size_t os = pid_size - index - 1;
memmove(reinterpret_cast<void *>(pid_data + pid_start + index + 1), memmove((void*)(&(pid_data[index + pid_start + 1])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
} }
} else { } else {
alloc_backward(pid_size + 1, -1); alloc_backward(pid_size + 1, -1);
if (index > 0) { if (index > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start), memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T));
reinterpret_cast<const void *>(pid_data + pid_start + 1),
index * sizeof(T));
} }
} }
elementNew(pid_data + pid_start + index, e); elementNew(pid_data + pid_start + index, e);
@@ -1352,21 +1345,17 @@ public:
inline PIDeque<T> & insert(size_t index, T && e) { inline PIDeque<T> & insert(size_t index, T && e) {
if (index == pid_size) return push_back(e); if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1) 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) { if (dir) {
alloc_forward(pid_size + 1); alloc_forward(pid_size + 1);
if (index < pid_size - 1) { if (index < pid_size - 1) {
const size_t os = pid_size - index - 1; size_t os = pid_size - index - 1;
memmove(reinterpret_cast<void *>(pid_data + pid_start + index + 1), memmove((void*)(&(pid_data[index + pid_start + 1])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
} }
} else { } else {
alloc_backward(pid_size + 1, -1); alloc_backward(pid_size + 1, -1);
if (index > 0) { if (index > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start), memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T));
reinterpret_cast<const void *>(pid_data + pid_start + 1),
index * sizeof(T));
} }
} }
elementNew(pid_data + pid_start + index, std::move(e)); elementNew(pid_data + pid_start + index, std::move(e));
@@ -1387,21 +1376,17 @@ public:
} }
#endif #endif
assert(&v != this); 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) { if (dir) {
const ssize_t os = pid_size - index; ssize_t os = pid_size - index;
alloc_forward(pid_size + v.pid_size); alloc_forward(pid_size + v.pid_size);
if (os > 0) { if (os > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + index + v.pid_size), memmove((void*)(&(pid_data[index + pid_start + v.pid_size])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
} }
} else { } else {
alloc_backward(pid_size + v.pid_size, -v.pid_size); alloc_backward(pid_size + v.pid_size, -v.pid_size);
if (index > 0) { if (index > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start), memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + v.pid_size])), index * sizeof(T));
reinterpret_cast<const void *>(pid_data + pid_start + v.pid_size),
index * sizeof(T));
} }
} }
newT(pid_data + pid_start + index, v.pid_data + v.pid_start, v.pid_size); 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). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append(), \a prepend(), \a remove() //! \~\sa \a append(), \a prepend(), \a remove()
inline PIDeque<T> & insert(size_t index, std::initializer_list<T> init_list) { inline PIDeque<T> & insert(size_t index, std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this; bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
const bool dir = init_list.size() > pid_size ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) { if (dir) {
const ssize_t os = ssize_t(pid_size) - index; ssize_t os = pid_size - index;
alloc_forward(pid_size + init_list.size()); alloc_forward(pid_size + init_list.size());
if (os > 0) { if (os > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + index + init_list.size()), memmove((void*)(&(pid_data[index + pid_start + init_list.size()])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
} }
} else { } else {
alloc_backward(pid_size + init_list.size(), -init_list.size()); alloc_backward(pid_size + init_list.size(), -init_list.size());
if (index > 0) { if (index > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start), memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + init_list.size()])), index * sizeof(T));
reinterpret_cast<const void *>(pid_data + pid_start + init_list.size()),
index * sizeof(T));
} }
} }
newT(pid_data + pid_start + index, init_list.begin(), init_list.size()); 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) { inline PIDeque<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this; if (count == 0) return *this;
if (index + count >= pid_size) { if (index + count >= pid_size) {
if (index < pid_size) { resize(index);
deleteT(pid_data + pid_start + index, pid_size - index); return *this;
pid_size = index; }
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 { } else {
if (index > 0) { if (index > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + count), memmove((void*)(&(pid_data[pid_start + count])), (const void*)(&(pid_data[pid_start])), index * sizeof(T));
reinterpret_cast<const void *>(pid_data + pid_start),
index * sizeof(T));
} }
pid_start += count; pid_start += count;
} }
pid_size -= count; pid_size -= count;
}
return *this; return *this;
} }
@@ -1486,7 +1461,7 @@ public:
piSwap<T*>(pid_data, other.pid_data); piSwap<T*>(pid_data, other.pid_data);
piSwap<size_t>(pid_size, other.pid_size); piSwap<size_t>(pid_size, other.pid_size);
piSwap<size_t>(pid_rsize, other.pid_rsize); piSwap<size_t>(pid_rsize, other.pid_rsize);
piSwap<size_t>(pid_start, other.pid_start); piSwap<ssize_t>(pid_start, other.pid_start);
} }
//! \~english Sorts the elements in non-descending order. //! \~english Sorts the elements in non-descending order.
@@ -1528,11 +1503,16 @@ public:
//! Complexity `O(N·log(N))`. //! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется. //! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется функция сравнения `comp`. //! Для сравнения элементов используется функция сравнения `comp`.
//! Функция сравнения, возвращает `true` если первый аргумент меньше //! Функция сравнения, возвращает `true` если первый аргумент меньше второго.
//! второго. Сигнатура функции сравнения должна быть эквивалентна следующей: \code bool comp(const T &a, const T &b); \endcode Сигнатура //! Сигнатура функции сравнения должна быть эквивалентна следующей:
//! не обязана содержать const &, однако, функция не может изменять переданные объекты. Функция обязана возвращать `false` для //! \code
//! одинаковых элементов, иначе это приведёт к неопределённому поведению программы и ошибкам памяти. Для сортировки используется функция //! bool comp(const T &a, const T &b);
//! [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort). Сложность сортировки `O(N·log(N))`. //! \endcode
//! Сигнатура не обязана содержать const &, однако, функция не может изменять переданные объекты.
//! Функция обязана возвращать `false` для одинаковых элементов,
//! иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort).
//! Сложность сортировки `O(N·log(N))`.
//! \~\code //! \~\code
//! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3}; //! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort([](const int & a, const int & b){return a > b;}); //! v.sort([](const int & a, const int & b){return a > b;});
@@ -1562,7 +1542,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a reversed() //! \~\sa \a reversed()
inline PIDeque<T> & reverse() { 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) { 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]);
} }
@@ -1592,12 +1572,10 @@ public:
//! Если `add_size < 0`, то с конца массива удаляются элементы. //! Если `add_size < 0`, то с конца массива удаляются элементы.
//! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым. //! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым.
//! \~\sa \a resize() //! \~\sa \a resize()
inline PIDeque<T> & enlarge(ssize_t add_size, const T & e = T()) { inline PIDeque<T> & enlarge(llong pid_size) {
const ssize_t ns = size_s() + add_size; llong ns = size_s() + pid_size;
if (ns <= 0) if (ns <= 0) clear();
clear(); else resize(size_t(ns));
else
resize(size_t(ns), e);
return *this; return *this;
} }
@@ -1630,7 +1608,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere() //! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIDeque<T> & removeAll(const T & e) { inline PIDeque<T> & removeAll(const T & e) {
for (size_t i = 0; i < pid_size; ++i) { for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
if (pid_data[i + pid_start] == e) { if (pid_data[i + pid_start] == e) {
remove(i); remove(i);
--i; --i;
@@ -1651,7 +1629,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere() //! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIDeque<T> & removeWhere(std::function<bool(const T & e)> test) { inline PIDeque<T> & removeWhere(std::function<bool(const T & e)> test) {
for (size_t i = 0; i < pid_size; ++i) { for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
if (test(pid_data[i + pid_start])) { if (test(pid_data[i + pid_start])) {
remove(i); remove(i);
--i; --i;
@@ -1715,8 +1693,7 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a push_back() //! \~\sa \a push_back()
inline PIDeque<T> & push_back(std::initializer_list<T> init_list) { inline PIDeque<T> & push_back(std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this; size_t ps = pid_size;
const size_t ps = pid_size;
alloc_forward(pid_size + init_list.size()); alloc_forward(pid_size + init_list.size());
newT(pid_data + pid_start + ps, init_list.begin(), init_list.size()); newT(pid_data + pid_start + ps, init_list.begin(), init_list.size());
return *this; return *this;
@@ -1729,14 +1706,13 @@ public:
//! \~russian Перегруженая функция. //! \~russian Перегруженая функция.
//! \~\sa \a push_back() //! \~\sa \a push_back()
inline PIDeque<T> & push_back(const PIDeque<T> & v) { inline PIDeque<T> & push_back(const PIDeque<T> & v) {
if (v.isEmpty()) return *this;
#ifndef NDEBUG #ifndef NDEBUG
if (&v == this) { if (&v == this) {
printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T)); printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
} }
#endif #endif
assert(&v != this); assert(&v != this);
const size_t ps = pid_size; size_t ps = pid_size;
alloc_forward(pid_size + v.pid_size); alloc_forward(pid_size + v.pid_size);
newT(pid_data + ps + pid_start, v.pid_data + v.pid_start, v.pid_size); newT(pid_data + ps + pid_start, v.pid_data + v.pid_start, v.pid_size);
return *this; return *this;
@@ -1859,9 +1835,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert() //! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
inline PIDeque<T> & push_front(const T & e) { inline PIDeque<T> & push_front(const T & e) {
if (isEmpty()) return push_back(e); insert(0, e);
alloc_backward(pid_size + 1, -1);
elementNew(pid_data + pid_start, e);
return *this; return *this;
} }
@@ -1872,9 +1846,7 @@ public:
//! \~russian Перегруженая функция. //! \~russian Перегруженая функция.
//! \~\sa \a push_front() //! \~\sa \a push_front()
inline PIDeque<T> & push_front(T && e) { inline PIDeque<T> & push_front(T && e) {
if (isEmpty()) return push_back(std::move(e)); insert(0, std::move(e));
alloc_backward(pid_size + 1, -1);
elementNew(pid_data + pid_start, std::move(e));
return *this; return *this;
} }
@@ -1889,7 +1861,10 @@ public:
//! piCout << v; // {4, 5, 1, 2, 3} //! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode //! \endcode
//! \~\sa \a push_front() //! \~\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. //! \~english Appends the given elements to the begin of the array.
//! \~russian Добавляет элементы в начало массива. //! \~russian Добавляет элементы в начало массива.
@@ -1901,7 +1876,10 @@ public:
//! Добавляет элементы из //! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append() //! \~\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. //! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива. //! \~russian Добавляет элемент `e` в начало массива.
@@ -1960,7 +1938,7 @@ public:
//! Добавляет элементы из //! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append() //! \~\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. //! \~english Remove one element from the end of the array.
//! \~russian Удаляет один элемент с конца массива. //! \~russian Удаляет один элемент с конца массива.
@@ -1977,8 +1955,7 @@ public:
//! \~\sa \a pop_front(), \a take_back(), \a take_front() //! \~\sa \a pop_front(), \a take_back(), \a take_front()
inline PIDeque<T> & pop_back() { inline PIDeque<T> & pop_back() {
if (pid_size == 0) return *this; if (pid_size == 0) return *this;
elementDelete(pid_data[pid_size + pid_start - 1]); resize(pid_size - 1);
pid_size = pid_size - 1;
return *this; return *this;
} }
@@ -1999,9 +1976,7 @@ public:
//! \~\sa \a pop_back(), \a take_back(), \a take_front() //! \~\sa \a pop_back(), \a take_back(), \a take_front()
inline PIDeque<T> & pop_front() { inline PIDeque<T> & pop_front() {
if (pid_size == 0) return *this; if (pid_size == 0) return *this;
elementDelete(pid_data[pid_start]); remove(0);
pid_start += 1;
pid_size -= 1;
return *this; return *this;
} }
@@ -2015,7 +1990,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front() //! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_back() { inline T take_back() {
const T e(back()); T e(back());
pop_back(); pop_back();
return e; return e;
} }
@@ -2030,7 +2005,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front() //! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_front() { inline T take_front() {
const T e(front()); T e(front());
pop_front(); pop_front();
return e; return e;
} }
@@ -2047,7 +2022,6 @@ public:
template <typename ST> template <typename ST>
inline PIDeque<ST> toType() const { inline PIDeque<ST> toType() const {
PIDeque<ST> ret(pid_size); PIDeque<ST> ret(pid_size);
ret.reserve(pid_size);
for (size_t i = 0; i < pid_size; ++i) { for (size_t i = 0; i < pid_size; ++i) {
ret[i] = ST(pid_data[i + pid_start]); ret[i] = ST(pid_data[i + pid_start]);
} }
@@ -2055,9 +2029,9 @@ public:
} }
//! \~english Returns a new array with all elements //! \~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 Возвращает новый массив со всеми элементами, //! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `bool test(const T & e)`. //! прошедшими проверку, задаваемую в передаваемой функции `test`.
//! \~\details //! \~\details
//! \~\code //! \~\code
//! PIDeque<int> v{3, 2, 5, 2, 7}; //! PIDeque<int> v{3, 2, 5, 2, 7};
@@ -2073,39 +2047,6 @@ public:
return ret; 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. //! \~english Execute function `void f(const T & e)` for every element in array.
//! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива. //! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива.
//! \~\details //! \~\details
@@ -2146,63 +2087,6 @@ public:
return *this; 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 //! \~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. //! of calling a provided function `ST f(const T & e)` on every element in the calling array.
//! \~russian Создаёт новый массив с результатом вызова указанной функции //! \~russian Создаёт новый массив с результатом вызова указанной функции
@@ -2212,78 +2096,23 @@ public:
//! once for each element in an array, in order, //! once for each element in an array, in order,
//! and constructs a new array from the results. //! and constructs a new array from the results.
//! \~russian Метод `map` вызывает переданную функцию `ST f(const T & e)` //! \~russian Метод `map` вызывает переданную функцию `ST f(const T & e)`
//! один раз для каждого элемента в порядке их появления от начала к концу (слева на право) //! один раз для каждого элемента в порядке их появления
//! и конструирует новый массив из результатов её вызова. //! и конструирует новый массив из результатов её вызова.
//! \~\code //! \~\code
//! PIDeque<int> v{1, 2, 3}; //! PIDeque<int> v{1, 2, 3};
//! PIStringList sl = v.map<PIString>([](const int & i){return PIString::fromNumber(i);}); //! PIStringList sl = v.map<PIString>([](const int & i){return PIString::fromNumber(i);});
//! piCout << sl; // {"1", "2", "3"} //! piCout << sl; {"1", "2", "3"}
//! \endcode //! \endcode
//! \~\sa \a forEach(), \a reduce() //! \~\sa \a forEach(), \a reduce()
template <typename ST> template <typename ST>
inline PIDeque<ST> map(std::function<ST(const T & e)> f) const { inline PIDeque<ST> map(std::function<ST(const T & e)> f) const {
PIDeque<ST> ret; PIDeque<ST> ret; ret.reserve(pid_size);
ret.reserve(pid_size);
for (size_t i = pid_start; i < pid_start + pid_size; ++i) { for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
ret << f(pid_data[i]); ret << f(pid_data[i]);
} }
return ret; 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)` //! \~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. //! to each element of the array (from left to right), returns one value.
//! \~russian Применяет функцию `ST f(const T & e, const ST & acc)` //! \~russian Применяет функцию `ST f(const T & e, const ST & acc)`
@@ -2304,7 +2133,7 @@ public:
//! \param initial _optional_ Object used as the second argument //! \param initial _optional_ Object used as the second argument
//! when the `f` function is first called. //! when the `f` function is first called.
//! \~russian Метод reduce() выполняет функцию `f` //! \~russian Метод reduce() выполняет функцию `f`
//! один раз для каждого элемента, присутствующего в массиве от начала к концу (слева на право). //! один раз для каждого элемента, присутствующего в массиве.
//! Если при вызове reduce() передан аргумент `initial`, //! Если при вызове reduce() передан аргумент `initial`,
//! то при первом вызове функции `f` значение `acc` //! то при первом вызове функции `f` значение `acc`
//! будет равным значению `initial`. //! будет равным значению `initial`.
@@ -2324,7 +2153,7 @@ public:
//! int s = v.reduce<int>([](const int & e, const int & acc){return e + acc;}); //! int s = v.reduce<int>([](const int & e, const int & acc){return e + acc;});
//! piCout << s; // 15 //! piCout << s; // 15
//! \endcode //! \endcode
//! \~\sa \a reduceIndexed(), \a reduceReverse(), \a reduceReverseIndexed(), \a forEach(), \a map() //! \~\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 { inline ST reduce(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial); ST ret(initial);
@@ -2334,42 +2163,6 @@ public:
return ret; return ret;
} }
//! \~english Same as \a reduce() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduce() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
ret = f(i - pid_start, pid_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduce() but from end to begin (from right to left).
//! \~russian Аналогично \a reduce() но от конца до начала (справа на лево).
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceReverse(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
ret = f(pid_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduceReverse() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduceReverse() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduceReverse()
template<typename ST>
inline ST reduceReverseIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
ret = f(size_t(i) - pid_start, pid_data[i], ret);
}
return ret;
}
//! \~english Changes the dimension of the array, creates a two-dimensional array from a one-dimensional array. //! \~english Changes the dimension of the array, creates a two-dimensional array from a one-dimensional array.
//! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный. //! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный.
//! \~\details //! \~\details
@@ -2398,7 +2191,7 @@ public:
} }
#endif #endif
assert(rows*cols == pid_size); assert(rows*cols == pid_size);
ret.expand(rows); ret.resize(rows);
if (order == ReshapeByRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r] = PIDeque<T>(&(pid_data[r*cols]), cols); ret[r] = PIDeque<T>(&(pid_data[r*cols]), cols);
@@ -2406,7 +2199,7 @@ public:
} }
if (order == ReshapeByColumn) { if (order == ReshapeByColumn) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r].expand(cols); ret[r].resize(cols);
for (size_t c = 0; c < cols; c++) { for (size_t c = 0; c < cols; c++) {
ret[r][c] = pid_data[c*rows + r]; ret[r][c] = pid_data[c*rows + r];
} }
@@ -2429,12 +2222,14 @@ public:
//! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6} //! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6}
//! \endcode //! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape() //! \~\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 { inline PIDeque<C> flatten(ReshapeOrder order = ReshapeByRow) const {
PIDeque<C> ret; PIDeque<C> ret;
if (isEmpty()) return ret; if (isEmpty()) return ret;
const size_t rows = size(); size_t rows = size();
const size_t cols = at(0).size(); size_t cols = at(0).size();
ret.reserve(rows * cols); ret.reserve(rows * cols);
if (order == ReshapeByRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
@@ -2470,217 +2265,116 @@ public:
//! piCout << xv.reshape<int>(2,3); // {{1, 2, 3}, {4, 5, 6}} //! piCout << xv.reshape<int>(2,3); // {{1, 2, 3}, {4, 5, 6}}
//! \endcode //! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape() //! \~\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 { inline PIDeque<PIDeque<C>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
PIDeque<C> fl = flatten<C>(); PIDeque<C> fl = flatten<C>();
return fl.reshape(rows, cols, order); 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: private:
inline void _reset() { inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;}
pid_size = 0;
pid_rsize = 0;
pid_start = 0;
pid_data = nullptr;
}
inline size_t asize(ssize_t s) { inline size_t asize(ssize_t s) {
if (s <= 0) return 0; if (s <= 0) return 0;
if (pid_rsize * 2 >= size_t(s) && pid_rsize < size_t(s)) { if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s)) {
return pid_rsize * 2; return pid_rsize + pid_rsize;
} }
size_t t = _PIContainerConstants<T>::minCountPoT(); ssize_t t = _PIContainerConstants<T>::minCountPoT(), s_ = s - 1;
s -= 1; while (s_ >> t)
while (s >> t) {
++t; ++t;
}
return (1 << t); return (1 << t);
} }
template<typename T1 = T, typename std::enable_if<
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0> !std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) { inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(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]); elementNew(dst + i, src[i]);
} }
} template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0> , int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) { inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(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<
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0> !std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if (d != nullptr) { if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i) { for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]); elementDelete(d[i]);
} }
} }
} }
template<typename T1 = T, typename std::enable_if<
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0> std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
} }
template<typename T1 = T, typename std::enable_if<
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0> !std::is_trivially_copyable<T1>::value
inline void elementNew(T * to, const T & from) { , int>::type = 0>
new (to) T(from); 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
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0> , int>::type = 0>
inline void elementNew(T * to, T && from) { inline void elementNew(T * to, T && from) {new(to)T(std::move(from));}
new (to) T(std::move(from)); 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(T1 * to, const T & from) {(*to) = from;}
inline void elementNew(T1 * to, const T & from) { template<typename T1 = T, typename std::enable_if<
(*to) = from; 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> template<typename T1 = T, typename std::enable_if<
inline void elementNew(T * to, T && from) { !std::is_trivially_copyable<T1>::value
(*to) = std::move(from); , int>::type = 0>
} inline void elementDelete(T & from) {from.~T();}
template<typename T1 = T, typename std::enable_if<
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0> std::is_trivially_copyable<T1>::value
inline void elementDelete(T & from) { , int>::type = 0>
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 elementDelete(T & from) {}
inline void dealloc() { inline void dealloc() {
if (pid_data != nullptr) { if ((uchar*)pid_data != 0) free((uchar*)pid_data);
free(reinterpret_cast<void *>(pid_data)); pid_data = 0;
pid_data = nullptr;
} }
}
inline void checkMove() { inline void checkMove() {
if (pid_size >= 4) { if (pid_size >= 4) {
if (pid_size < pid_rsize / 6) { if (pid_size < pid_rsize / 6) {
if (pid_start < (pid_size * 2) || ssize_t(pid_start) > (ssize_t(pid_rsize) - (ssize_t(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))) {
size_t ns = (pid_rsize - pid_size) / 2; ssize_t ns = (pid_rsize - pid_size) / 2;
if (pid_start != ns) { if (pid_start != ns) {
memmove(reinterpret_cast<void *>(pid_data + ns), memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
reinterpret_cast<const void *>(pid_data + pid_start),
pid_size * sizeof(T));
pid_start = ns; pid_start = ns;
} }
} }
} }
} else { } else {
const size_t ns = (pid_rsize - pid_size) / 2; ssize_t ns = (pid_rsize - pid_size) / 2;
if (pid_start != ns) { if (pid_start != ns) {
memmove(reinterpret_cast<void *>(pid_data + ns), memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
reinterpret_cast<const void *>(pid_data + pid_start),
pid_size * sizeof(T));
pid_start = ns; pid_start = ns;
} }
} }
} }
inline void alloc_forward(size_t new_size) { // direction == true -> alloc forward
inline void alloc_forward(size_t new_size) {
if (pid_start + new_size <= pid_rsize) { if (pid_start + new_size <= pid_rsize) {
pid_size = new_size; pid_size = new_size;
if (pid_start > 0) checkMove(); checkMove();
return; return;
} }
pid_size = new_size; 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) { if (as != pid_rsize) {
PIINTROSPECTION_CONTAINER_ALLOC(T, (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))); T * p_d = (T*)(realloc((void*)(pid_data), as*sizeof(T)));
#ifndef NDEBUG #ifndef NDEBUG
if (!p_d) { if (!p_d) {
printf("error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T)); printf("error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
@@ -2691,15 +2385,19 @@ private:
pid_rsize = as; pid_rsize = as;
} }
} }
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) { //alloc backward
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) { size_t as;
const size_t as = ssize_t(pid_start) + start_offset < 0 ? asize(pid_rsize - start_offset) : pid_rsize; if (pid_start + start_offset < 0) {
as = asize(pid_rsize - start_offset);
} else {
as = pid_rsize;
}
if (as > pid_rsize) { if (as > pid_rsize) {
T * td = reinterpret_cast<T *>(malloc(as * sizeof(T))); T * td = (T*)(malloc(as * sizeof(T)));
const size_t ns = pid_start + as - pid_rsize; ssize_t ns = pid_start + as - pid_rsize;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize)) PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
if (pid_rsize > 0 && pid_data != 0) { if (pid_rsize > 0 && pid_data != 0) {
memcpy(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(); dealloc();
} }
pid_data = td; pid_data = td;
@@ -2711,28 +2409,9 @@ private:
checkMove(); checkMove();
} }
inline void expand(size_t new_size, const T & e = T()) { T * pid_data;
const size_t os = pid_size; size_t pid_size, pid_rsize;
alloc_forward(new_size); ssize_t pid_start;
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;
}; };
@@ -2758,21 +2437,19 @@ inline std::ostream & operator<<(std::ostream & s, const PIDeque<T> & v) {
template<typename T> template<typename T>
inline PICout operator <<(PICout s, const PIDeque<T> & v) { inline PICout operator <<(PICout s, const PIDeque<T> & v) {
s.space(); s.space();
s.saveAndSetControls(0); s.setControl(0, true);
s << "{"; s << "{";
for (size_t i = 0; i < v.size(); ++i) { for (size_t i = 0; i < v.size(); ++i) {
s << v[i]; s << v[i];
if (i < v.size() - 1) s << ", "; if (i < v.size() - 1) s << ", ";
} }
s << "}"; s << "}";
s.restoreControls(); s.restoreControl();
return s; return s;
} }
template<typename T> template<typename T>
inline void piSwap(PIDeque<T> & f, PIDeque<T> & s) { inline void piSwap(PIDeque<T> & f, PIDeque<T> & s) {f.swap(s);}
f.swap(s);
}
#endif // PIDEQUE_H #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 Associative array with custom types of key and value
//! \file pimap.h *
//! \brief * This file declares PIMap
//! \~english Declares \a PIMap */
//! \~russian Объявление \a PIMap
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//! \~\}
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Associative array with custom types of key and value Associative array with custom types of key and value
@@ -34,129 +25,57 @@
#ifndef PIMAP_H #ifndef PIMAP_H
#define PIMAP_H #define PIMAP_H
#include "pivector.h"
#include "pideque.h" #include "pideque.h"
#include "pipair.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; 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 { class PIMap {
template<typename Key1, typename T1> template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIMap<Key1, T1> & v);
friend class PIMapIteratorConst; template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIMap<Key1, T1> & v);
template<typename Key1, typename T1> template <typename Key1, typename T1> friend class PIMapIterator;
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);
public: public:
typedef T mapped_type; PIMap() {}
typedef Key key_type; PIMap(const PIMap<Key, T> & other) {*this = other;}
typedef PIPair<Key, T> value_type; PIMap(PIMap<Key, T> && other) : pim_content(std::move(other.pim_content)) {}
PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
//! \~english Constructs an empty map. for (auto i: init_list)
//! \~russian Создает пустой словарь.
inline PIMap() {}
//! \~english Copy constructor.
//! \~russian Копирующий конструктор.
inline PIMap(const PIMap<Key, T> & other): pim_content(other.pim_content), pim_index(other.pim_index) {}
//! \~english Move constructor.
//! \~russian Перемещающий конструктор.
inline PIMap(PIMap<Key, T> && other): pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {}
//! \~english Contructs map from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Создает словарь из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\details
//! \~\code
//! PIMap <int, PIString> m{{1, "a"}, {2, "b"}};
//! piCout << m; // {1: a, 2: b}
//! \endcode
inline PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
for (auto i: init_list) {
insert(std::get<0>(i), std::get<1>(i)); insert(std::get<0>(i), std::get<1>(i));
} }
} virtual ~PIMap() {;}
//! \~english Assign operator. PIMap<Key, T> & operator =(const PIMap<Key, T> & other) {
//! \~russian Оператор присваивания.
inline PIMap<Key, T> & operator=(const PIMap<Key, T> & other) {
if (this == &other) return *this; if (this == &other) return *this;
clear(); clear();
pim_content = other.pim_content; pim_content = other.pim_content;
pim_index = other.pim_index;
return *this; return *this;
} }
//! \~english Assign move operator. PIMap<Key, T> & operator =(PIMap<Key, T> && other) {
//! \~russian Оператор перемещающего присваивания.
inline PIMap<Key, T> & operator=(PIMap<Key, T> && other) {
swap(other); swap(other);
return *this; return *this;
} }
typedef T mapped_type;
typedef Key key_type;
typedef PIPair<Key, T> value_type;
class iterator { class iterator {
friend class PIMap<Key, T>; friend class PIMap<Key, T>;
private: private:
iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {} iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent; const PIMap<Key, T> * parent;
ssize_t pos; ssize_t pos;
public: public:
iterator(): parent(nullptr), pos(0) {} iterator(): parent(0), pos(0) {}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);} const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
T & value() {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);} T & value() {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
inline PIPair<Key, T> operator*() const { 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));}
return PIPair<Key, T>(const_cast<PIMap<Key, T> *>(parent)->_key(pos), const_cast<PIMap<Key, T> *>(parent)->_value(pos));
}
void operator ++() {++pos;} void operator ++() {++pos;}
void operator ++(int) {++pos;} void operator ++(int) {++pos;}
void operator --() {--pos;} void operator --() {--pos;}
@@ -167,19 +86,15 @@ public:
class reverse_iterator { class reverse_iterator {
friend class PIMap<Key, T>; friend class PIMap<Key, T>;
private: private:
reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {} reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent; const PIMap<Key, T> * parent;
ssize_t pos; ssize_t pos;
public: public:
reverse_iterator(): parent(nullptr), pos(0) {} reverse_iterator(): parent(0), pos(0) {}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);} const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);} T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
inline PIPair<Key, T> operator*() const { 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));}
return PIPair<Key, T>(const_cast<PIMap<Key, T> *>(parent)->_key(pos), const_cast<PIMap<Key, T> *>(parent)->_value(pos));
}
void operator ++() {--pos;} void operator ++() {--pos;}
void operator ++(int) {--pos;} void operator ++(int) {--pos;}
void operator --() {++pos;} void operator --() {++pos;}
@@ -190,15 +105,14 @@ public:
class const_iterator { class const_iterator {
friend class PIMap<Key, T>; friend class PIMap<Key, T>;
private: private:
const_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {} const_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent; const PIMap<Key, T> * parent;
ssize_t pos; ssize_t pos;
public: public:
const_iterator(): parent(nullptr), pos(0) {} const_iterator(): parent(0), pos(0) {}
const value_type operator *() const {return parent->_pair(pos);} const value_type operator *() const {return parent->_pair(pos);}
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);} const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
const T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);} const T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
void operator ++() {++pos;} void operator ++() {++pos;}
@@ -207,152 +121,64 @@ public:
void operator --(int) {--pos;} void operator --(int) {--pos;}
bool operator ==(const const_iterator & it) const {return (pos == it.pos);} bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
bool operator !=(const const_iterator & it) const {return (pos != it.pos);} bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
mutable value_type cval;
}; };
class const_reverse_iterator { class const_reverse_iterator {
friend class PIMap<Key, T>; friend class PIMap<Key, T>;
private: private:
const_reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {} const_reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent; const PIMap<Key, T> * parent;
ssize_t pos; ssize_t pos;
public: public:
const_reverse_iterator(): parent(nullptr), pos(0) {} const_reverse_iterator(): parent(0), pos(0) {}
const value_type operator *() const {return parent->_pair(pos);} const value_type operator *() const {return parent->_pair(pos);}
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
void operator ++() {--pos;} void operator ++() {--pos;}
void operator ++(int) {--pos;} void operator ++(int) {--pos;}
void operator --() {++pos;} void operator --() {++pos;}
void operator --(int) {++pos;} void operator --(int) {++pos;}
bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);} bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);} bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
mutable value_type cval;
}; };
iterator begin() {return iterator(this, 0);}
iterator 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. PIMapIterator<Key, T> makeIterator() const {return PIMapIterator<Key, T>(*this);}
//! \~russian Итератор на первый элемент. PIMapIterator<Key, T> makeReverseIterator() const {return PIMapIterator<Key, T>(*this, true);}
inline iterator begin() { return iterator(this, 0); }
//! \~english Iterator to the element following the last element. size_t size() const {return pim_content.size();}
//! \~russian Итератор на элемент, следующий за последним элементом. int size_s() const {return pim_content.size_s();}
inline iterator end() { return iterator(this, size()); } 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); } T & operator [](const Key & key) {
inline const_iterator end() const { return const_iterator(this, size()); }
//! \~english Returns a reverse iterator to the first element of the reversed array.
//! \~russian Обратный итератор на первый элемент.
inline reverse_iterator rbegin() { return reverse_iterator(this, size() - 1); }
//! \~english Returns a reverse iterator to the element.
//! following the last element of the reversed array.
//! \~russian Обратный итератор на элемент,
//! следующий за последним элементом.
inline reverse_iterator rend() { return reverse_iterator(this, -1); }
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(this, size() - 1); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(this, -1); }
//! \relatesalso PIMapIteratorConst
inline PIMapIteratorConst<Key, T> makeIterator() const { return PIMapIteratorConst<Key, T>(*this); }
//! \relatesalso PIMapIterator
inline PIMapIterator<Key, T> makeIterator() { return PIMapIterator<Key, T>(*this); }
//! \relatesalso PIMapIteratorConstReverse
inline PIMapIteratorConstReverse<Key, T> makeReverseIterator() const { return PIMapIteratorConstReverse<Key, T>(*this); }
//! \relatesalso PIMapIteratorReverse
inline PIMapIteratorReverse<Key, T> makeReverseIterator() { return PIMapIteratorReverse<Key, T>(*this); }
//! \~english Number of elements in the container.
//! \~russian Количество элементов массива.
//! \~\sa \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline size_t size() const { return pim_content.size(); }
//! \~english Number of elements in the container as signed value.
//! \~russian Количество элементов массива в виде знакового числа.
//! \~\sa \a size(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline int size_s() const { return pim_content.size_s(); }
//! \~english Same as \a size().
//! \~russian Синоним \a size().
//! \~\sa \a size(), \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline size_t length() const { return pim_content.size(); }
//! \~english Checks if the container has no elements.
//! \~russian Проверяет пуст ли массив.
//! \~\return
//! \~english **true** if the container is empty, **false** otherwise
//! \~russian **true** если массив пуст, **false** иначе.
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline bool isEmpty() const { return (pim_content.size() == 0); }
//! \~english Checks if the container has elements.
//! \~russian Проверяет не пуст ли массив.
//! \~\return
//! \~english **true** if the container is not empty, **false** otherwise
//! \~russian **true** если массив не пуст, **false** иначе.
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline bool isNotEmpty() const { return (pim_content.size() > 0); }
//! \~english Full access to element key `key`.
//! \~russian Полный доступ к элементу по ключу `key`.
//! \~\details
//! \~english If the map contains no item with key `key`,
//! the function inserts a default-constructed value into the map with key `key`,
//! and returns a reference to it.
//! \~russian Если элемента с таким ключом `key` не существует,
//! то он будет создан конструктором по умолчанию и добавлен в массив
//! по ключу `key`, а затем возвращена ссылка на этот новый элемент.
//! \~\code
//! PIMap <PIString, int> m;
//! m["огурец"] = 500;
//! piCout << m; // {огурец: 500}
//! m["лук"] = 25;
//! piCout << m; // {огурец: 500, лук: 25}
//! m["огурец"] = 350;
//! piCout << m; // {огурец: 350, лук: 25}
//! \endcode
//! \~\sa \a insert(), \a value(), \a key()
inline T & operator[](const Key & key) {
bool f(false); bool f(false);
const ssize_t i = _find(key, f); ssize_t i = _find(key, f);
if (f) return _value(i); if (!f) pim_content.insert(i, PIPair<Key, T>(key, T()));
pim_content.push_back(T()); return pim_content[i].second;
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
return pim_content.back();
} }
const T operator [](const Key & key) const {
//! \~english Read only access to element by `key`.
//! \~russian Доступ исключительно на чтение к элементу по ключу `key`.
//! \~\note
//! \~english Element with key `key` must exists,
//! otherwise it will lead to undefined program behavior and memory errors.
//! \~russian Элемент по ключу `key` должен существовать,
//! иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
//! \~\sa \a operator[](), \a value(), \a key()
inline const T & at(const Key & key) const {
bool f(false); bool f(false);
const ssize_t i = _find(key, f); ssize_t i = _find(key, f);
return _value(i); 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. PIMap<Key, T> & operator <<(const PIMap<Key, T> & other) {
//! \~russian Удаляет элемент с ключом `key` из массива и возвращает его.
inline T take(const Key & key, const T & default_ = T()) {
bool f(false);
const ssize_t i = _find(key, f);
if (!f) return default_;
const T ret = _value(i);
_remove(i);
return ret;
}
//! \~english Inserts all elements in array `other` to this array with overwrite.
//! \~russian Вставляет все элементы `other` этот массив с перезаписью.
inline PIMap<Key, T> & operator<<(const PIMap<Key, T> & other) {
#ifndef NDEBUG #ifndef NDEBUG
if (&other == this) { if (&other == this) {
printf("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));
@@ -360,651 +186,205 @@ public:
#endif #endif
assert(&other != this); assert(&other != this);
if (other.isEmpty()) return *this; if (other.isEmpty()) return *this;
if (other.size() == 1) { // if (other.size() == 1) {insert(other.pim_index[0].key, other.pim_content[0]); return *this;}
insert(other.pim_index[0].key, other.pim_content[0]); // 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;}
return *this; for (int i = 0; i < other.pim_content.size_s(); ++i)
} insert(other.pim_content[i].first, other.pim_content[i].second);
if (other.size() == 2) {
insert(other.pim_index[0].key, other.pim_content[0]);
insert(other.pim_index[1].key, other.pim_content[1]);
return *this;
}
for (int i = 0; i < other.pim_index.size_s(); ++i) {
insert(other.pim_index[i].key, other.pim_content[other.pim_index[i].index]);
}
return *this; return *this;
} }
//! \~english Compare operator with array `m`. bool operator ==(const PIMap<Key, T> & t) const {return (pim_content == t.pim_content);}
//! \~russian Оператор сравнения с массивом `m`. bool operator !=(const PIMap<Key, T> & t) const {return (pim_content != t.pim_content);}
inline bool operator==(const PIMap<Key, T> & m) const { return (pim_content == m.pim_content && pim_index == m.pim_index); } bool contains(const Key & key) const {bool f(false); _find(key, f); return f;}
//! \~english Compare operator with array `m`. PIMap<Key, T> & reserve(size_t new_size) {pim_content.reserve(new_size);return *this;}
//! \~russian Оператор сравнения с массивом `m`.
inline bool operator!=(const PIMap<Key, T> & m) const { return (pim_content != m.pim_content || pim_index != m.pim_index); }
//! \~english Tests if element with key `key` exists in the array. PIMap<Key, T> & removeOne(const Key & key) {bool f(false); ssize_t i = _find(key, f); if (f) _remove(i); return *this;}
//! \~russian Проверяет наличие элемента с ключом `key` в массиве. PIMap<Key, T> & remove(const Key & key) {return removeOne(key);}
inline bool contains(const Key & key) const { PIMap<Key, T> & erase(const Key & key) {return removeOne(key);}
bool f(false); PIMap<Key, T> & clear() {pim_content.clear(); return *this;}
_find(key, f);
return f;
}
//! \~english Tests if element with value `value` exists in the array. void swap(PIMap<Key, T> & other) {
//! \~russian Проверяет наличие элемента со значением `value` в массиве.
inline bool containsValue(const T & value) const { return pim_content.contains(value); }
//! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов.
inline PIMap<Key, T> & reserve(size_t new_size) {
pim_content.reserve(new_size);
pim_index.reserve(new_size);
return *this;
}
//! \~english Remove element with key `key` from the array.
//! \~russian Удаляет элемент с ключом `key` из массива.
inline PIMap<Key, T> & remove(const Key & key) {
bool f(false);
const ssize_t i = _find(key, f);
if (f) _remove(i);
return *this;
}
//! \~english Remove all elements in the array
//! passes the test implemented by the provided function `test`.
//! \~russian Удаляет все элементы, удовлетворяющие условию,
//! заданному в передаваемой функции `test`.
inline PIMap<Key, T> & removeWhere(std::function<bool(const Key & key, const T & value)> test) {
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
if (test(mi.key, pim_content[mi.index])) {
_remove(i);
--i;
}
}
return *this;
}
//! \~english Same as \a remove().
//! \~russian Синоним функции \a remove().
inline PIMap<Key, T> & erase(const Key & key) { return remove(key); }
//! \~english Clear array, remove all elements.
//! \~russian Очищает массив, удаляет все элементы.
//! \~\details
//! \~\note
//! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize()
inline PIMap<Key, T> & clear() {
pim_content.clear();
pim_index.clear();
return *this;
}
//! \~english Swaps array `v` other with this array.
//! \~russian Меняет местами массив `v` с этим массивом.
//! \~\details
//! \~english This operation is very fast and never fails.
//! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев.
inline void swap(PIMap<Key, T> & other) {
pim_content.swap(other.pim_content); pim_content.swap(other.pim_content);
pim_index.swap(other.pim_index);
} }
//! \~english Inserts value `value` with key `key` in the array. PIMap<Key, T> & insert(const Key & key, const T & value) {
//! \~russian Вставляет значение `value` с ключом `key` в массив.
//! \~\details
//! \~english If an element with the key `key` already exists, it will be overwritten with the value `value`.
//! \~russian Если элемент с ключом `key` уже существует, то он будет перезаписан на значение `value`.
inline PIMap<Key, T> & insert(const Key & key, const T & value) {
bool f(false); 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) { if (f) {
_value(i) = value; pim_content[i].second = value;
} else { } else {
pim_content.push_back(value); pim_content.insert(i, PIPair<Key, T>(key, value));
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
} }
return *this; return *this;
} }
PIMap<Key, T> & insert(const Key & key, T && value) {
inline PIMap<Key, T> & insert(const Key & key, T && value) {
bool f(false); 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) { if (f) {
_value(i) = std::move(value); pim_content[i].second = std::move(value);
} else { } else {
pim_content.push_back(std::move(value)); // pim_content.push_back(std::move(value));
pim_index.insert(i, MapIndex(key, pim_content.size() - 1)); // pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
pim_content.insert(i, PIPair<Key, T>(key, std::move(value)));
} }
return *this; return *this;
} }
const T value(const Key & key, const T & default_ = T()) const {
//! \~english Inserts value `pair` in the array.
//! \~russian Вставляет пару `pair` в массив.
//! \~\details
//! \~english The first element of the pair is the key, and the second is the value.
//! \~russian Первый элемент пары является ключом, а второй значением.
inline PIMap<Key, T> & insert(const PIPair<Key, T> & pair) {
bool f(false); bool f(false);
const ssize_t i = _find(pair.first, f); ssize_t i = _find(key, f);
if (f) {
_value(i) = pair.second;
} else {
pim_content.push_back(pair.second);
pim_index.insert(i, MapIndex(pair.first, pim_content.size() - 1));
}
return *this;
}
inline PIMap<Key, T> & insert(PIPair<Key, T> && pair) {
bool f(false);
Key k(std::move(pair.first));
const ssize_t i = _find(k, f);
if (f) {
_value(i) = std::move(pair.second);
} else {
pim_content.push_back(std::move(pair.second));
pim_index.insert(i, MapIndex(k, pim_content.size() - 1));
}
return *this;
}
//! \~english Returns the value of the element by the key `key`
//! or `default_` if there is no such element.
//! \~russian Возвращает значение элемента по ключу `key`
//! или `default_` если такого элемента нет.
inline T value(const Key & key, const T & default_ = T()) const {
bool f(false);
const ssize_t i = _find(key, f);
if (!f) return default_; if (!f) return default_;
return _value(i); return pim_content[i].second;
}
//! \~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;
} }
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_; return default_;
} }
PIVector<Key> keys() const {
//! \~english Returns an array of keys of all elements
//! \~russian Возвращает массив ключей всех элементов
inline PIVector<Key> keys() const {
PIVector<Key> ret; PIVector<Key> ret;
ret.reserve(pim_index.size()); for (size_t i = 0; i < pim_content.size(); ++i) ret << pim_content[i].first;
for (int i = 0; i < pim_index.size_s(); ++i) {
ret << pim_index[i].key;
}
return ret; return ret;
} }
//! \~english Execute function `void f(const Key & key, const T & value)` for every element in array. void dump() {
//! \~russian Выполняет функцию `void f(const Key & key, const T & value)` для каждого элемента массива. piCout << "PIMap" << size() << "entries" << PICoutManipulators::NewLine << "content:";
inline void forEach(std::function<void(const Key & key, const T & value)> f) const { for (size_t i = 0; i < pim_content.size(); ++i)
for (int i = 0; i < pim_index.size_s(); ++i) { piCout << PICoutManipulators::Tab << i << ":" << pim_content[i];
const auto & mi(pim_index[i]); // piCout << "index:";
f(mi.key, pim_content[mi.index]); // for (size_t i = 0; i < pim_index.size(); ++i)
} // piCout << PICoutManipulators::Tab << i << ":" << pim_index[i].key << "->" << pim_index[i].index;
} }
//! \~english Сreates a new map PIMap<Key2, T2> populated with the results protected:
//! of calling a provided function `PIPair<Key2, T2> f(const Key & key, const T & value)` on every element in the calling array. // struct MapIndex {
//! \~russian Создаёт новый словарь PIMap<Key2, T2> с результатом вызова указанной функции // MapIndex(Key k = Key(), size_t i = 0): key(k), index(i) {;}
//! `PIPair<Key2, T2> f(const Key & key, const T & value)` для каждого элемента массива. // Key key;
template<typename Key2, typename T2> // size_t index;
inline PIMap<Key2, T2> map(std::function<PIPair<Key2, T2>(const Key & key, const T & value)> f) const { // bool operator ==(const MapIndex & s) const {return key == s.key;}
PIMap<Key2, T2> ret; // bool operator !=(const MapIndex & s) const {return key != s.key;}
ret.reserve(size()); // bool operator <(const MapIndex & s) const {return key < s.key;}
for (int i = 0; i < pim_index.size_s(); ++i) { // bool operator >(const MapIndex & s) const {return key > s.key;}
const auto & mi(pim_index[i]); // };
ret.insert(f(mi.key, pim_content[mi.index])); // 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);
return ret;
}
//! \~english Сreates a new array PIVector<ST> populated with the results ssize_t binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
//! of calling a provided function `ST f(const Key & key, const T & value)` on every element in the calling array. ssize_t mid;
//! \~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;
}
private:
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; }
};
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);
inline ssize_t _binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
ssize_t mid = 0;
while (first <= last) { while (first <= last) {
mid = (first + last) / 2; mid = (first + last) / 2;
if (key > pim_index[mid].key) if (key > pim_content[mid].first) first = mid + 1;
first = mid + 1; else if (key < pim_content[mid].first) last = mid - 1;
else if (key < pim_index[mid].key) else {found = true; return mid;}
last = mid - 1;
else {
found = true;
return mid;
}
} }
found = false; found = false;
return first; return first;
} }
ssize_t _find(const Key & k, bool & found) const {
inline ssize_t _find(const Key & k, bool & found) const { if (pim_content.isEmpty()) {
if (pim_index.isEmpty()) {
found = false; found = false;
return 0; return 0;
} }
return _binarySearch(0, pim_index.size_s() - 1, k, found); return binarySearch(0, pim_content.size_s() - 1, k, found);
} }
void _remove(ssize_t index) {
inline void _remove(ssize_t index) { pim_content.remove(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;
} }
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()); Key & _key(ssize_t index) {return pim_content[index].first;}
pim_content.resize(pim_index.size()); T & _value(ssize_t index) {return pim_content[index].second;}
}
inline const value_type _pair(ssize_t index) const { PIDeque<PIPair<Key, T>> pim_content;
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]; }
PIVector<T> pim_content;
PIDeque<MapIndex> pim_index;
}; };
//! \addtogroup Containers
//! \{
//! \class PIMapIteratorConst
//! \brief
//! \~english Java-style iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap.
//! \~\}
//! \details
//! \~english
//! This class used to easy serial access keys and values in PIMap with read only permitions.
//! Use constructor to create iterator, or use \a PIMap::makeIterator()
//! \~russian
//! Этот класс используется для удобного перебора ключей и значений всего словаря только для чтения.
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeIterator();
//! while (it.next()) {
//! piCout << it.key() << it.value();
//! }
//! // 1 one
//! // 2 two
//! // 4 four
//! \endcode
template<typename Key, typename T>
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 { class PIMapIterator {
typedef PIMap<Key, T> MapType; typedef PIMap<Key, T> MapType;
public: public:
inline PIMapIterator(PIMap<Key, T> & map): m(map), pos(-1) {} PIMapIterator(const PIMap<Key, T> & map, bool reverse = false): m(map), pos(-1), rev(reverse) {
if (rev) pos = m.size_s();
//! \~english Returns current key. }
//! \~russian Возвращает ключ текущего элемента. const Key & key() const {return const_cast<MapType & >(m)._key(pos);}
//! \~\sa \a value() const T & value() const {return const_cast<MapType & >(m)._value(pos);}
inline const Key & key() const { return m._key(pos); } T & valueRef() const {return const_cast<MapType & >(m)._value(pos);}
inline bool hasNext() const {
//! \~english Returns current value. if (rev) {
//! \~russian Возвращает значение текущего элемента. return pos > 0;
//! \~\sa \a key() } else {
inline T & value() { return m._value(pos); } return pos < (m.size_s() - 1);
}
//! \~english Returns true if iterator can jump to next entry return false;
//! \~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() { inline bool next() {
if (rev) {
--pos;
return pos >= 0;
} else {
++pos; ++pos;
return pos < m.size_s(); return pos < m.size_s();
} }
return false;
//! \~english Reset iterator to initial position. }
//! \~russian Переходит на начало. inline void reset() {
//! \~\sa \a next() if (rev) {
inline void reset() { pos = -1; } pos = m.size_s();
} else {
private: pos = -1;
MapType & m; }
ssize_t pos;
};
//! \addtogroup Containers
//! \{
//! \class PIMapIteratorReverse
//! \brief
//! \~english Java-style reverse iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap в обратном порядке.
//! \~\}
//! \details
//! \~english
//! This class used to easy serial reverse access keys and values in PIMap with write permitions.
//! Use constructor to create iterator, or use \a PIMap::makeReverseIterator().
//! \~russian
//! Этот класс используется для удобного перебора ключей и значений всего словаря в обратном порядке с доступом на запись.
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeReverseIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeReverseIterator();
//! while (it.next()) {
//! it.value().append("_!");
//! piCout << it.key() << it.value();
//! }
//! // 4 four_!
//! // 2 two_!
//! // 1 one_!
//! \endcode
template<typename Key, typename T>
class PIMapIteratorReverse {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIteratorReverse(PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline T & value() { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos > 0; }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
--pos;
return pos >= 0;
} }
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = m.size_s(); }
private: private:
MapType & m; const MapType & m;
ssize_t pos; ssize_t pos;
bool rev;
}; };
#ifdef PIP_STD_IOSTREAM #ifdef PIP_STD_IOSTREAM
//! \~english Output operator to [std::ostream](https://en.cppreference.com/w/cpp/io/basic_ostream).
//! \~russian Оператор вывода в [std::ostream](https://ru.cppreference.com/w/cpp/io/basic_ostream).
template<typename Key, typename Type> template<typename Key, typename Type>
inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v) { inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v) {
s << "{"; s << "{";
bool first = true; bool first = true;
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) { for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first) s << ", "; if (!first)
s << ", ";
first = false; first = false;
s << i.key() << ": " << i.value(); s << i->first << ": " << i->second;
} }
s << "}"; s << "}";
return s; return s;
} }
#endif #endif
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename Key, typename Type> template<typename Key, typename Type>
inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) { inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) {
s.space(); s.space();
s.saveAndSetControls(0); s.setControl(0, true);
s << "{"; s << "{";
bool first = true; bool first = true;
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) { for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first) s << ", "; if (!first)
s << ", ";
first = false; first = false;
s << i.key() << ": " << i.value(); s << i->first << ": " << i->second;
} }
s << "}"; s << "}";
s.restoreControls(); s.restoreControl();
return s; return s;
} }
template<typename Key, typename Type> template<typename Key, typename Type> inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {f.swap(s);}
inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {
f.swap(s);
}
#endif // PIMAP_H #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. //! \~english Class template that provides a way to store two heterogeneous objects as a single unit.
//! \~russian Класс, который позволяет хранить два разнородных объекта как единое целое. //! \~russian Класс, который позволяет хранить два разнородных объекта как единое целое.
//! \~\} //! \~\}
//! \details
//! \~english
//! \~russian
//! \~\sa \a PIMap //! \~\sa \a PIMap
template<typename Type0, typename Type1> template<typename Type0, typename Type1>
class PIPair { class PIPair {
public: public:
//! \~english Constructs an empty PIPair. //! \~english Constructs an empty PIPair.
//! \~russian Создает пустой PIPair. //! \~russian Создает пустой PIPair.
PIPair() : first(), second() {} PIPair() : first(), second() {}
//! \~english Constructs PIPair from [std::tuple](https://en.cppreference.com/w/cpp/utility/tuple). //! \~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). //! \~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); first = std::get<0>(tuple);
second = std::get<1>(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`. //! \~english Constructs PIPair from values `value0` and `value1`.
//! \~russian Создает PIPair из `value0` и `value1`. //! \~russian Создает PIPair из `value0` и `value1`.
PIPair(const Type0 & value0, const Type1 & value1) { PIPair(const Type0 & value0, const Type1 & value1) {
@@ -117,9 +114,9 @@ inline std::ostream & operator<<(std::ostream & s, const PIPair<Type0, Type1> &
template<typename Type0, typename Type1> 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.space();
s.saveAndSetControls(0); s.setControl(0, true);
s << "(" << v.first << ", " << v.second << ")"; s << "(" << v.first << ", " << v.second << ")";
s.restoreControls(); s.restoreControl();
return s; return s;
} }
@@ -136,7 +133,6 @@ PIPair<T1, T2> createPIPair(const T1 & f, const T2 & s) {
return PIPair<T1,T2>(f, s); return PIPair<T1,T2>(f, s);
} }
//! \~english Creates \a PIPair object, deducing the target type from the types of arguments. //! \~english Creates \a PIPair object, deducing the target type from the types of arguments.
//! \~russian Создает \a PIPair выводя типы из аргументов. //! \~russian Создает \a PIPair выводя типы из аргументов.
//! \sa \a createPIPair() //! \sa \a createPIPair()
@@ -145,5 +141,4 @@ PIPair<T1, T2> createPIPair(T1 && f, T2 && s) {
return PIPair<T1,T2>(std::move(f), std::move(s)); return PIPair<T1,T2>(std::move(f), std::move(s));
} }
#endif // PIPAIR_H #endif // PIPAIR_H

View File

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

View File

@@ -37,37 +37,27 @@
template <typename T> template <typename T>
class PISet: public PIMap<T, uchar> { class PISet: public PIMap<T, uchar> {
typedef PIMap<T, uchar> _CSet; typedef PIMap<T, uchar> _CSet;
public: public:
//! Contructs an empty set //! Contructs an empty set
PISet() {} PISet() {}
virtual ~PISet() {;}
//! Contructs set with one element "value" //! 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" //! Contructs set with elements "v0" and "v1"
PISet(const T & v0, const T & v1) { PISet(const T & v0, const T & v1) {_CSet::insert(v0, 0); _CSet::insert(v1, 0);}
_CSet::insert(v0, 0);
_CSet::insert(v1, 0);
}
//! Contructs set with elements "v0", "v1" and "v2" //! Contructs set with elements "v0", "v1" and "v2"
PISet(const T & v0, const T & v1, const T & v2) { PISet(const T & v0, const T & v1, const T & v2) {_CSet::insert(v0, 0); _CSet::insert(v1, 0); _CSet::insert(v2, 0);}
_CSet::insert(v0, 0);
_CSet::insert(v1, 0);
_CSet::insert(v2, 0);
}
//! Contructs set with elements "v0", "v1", "v2" and "v3" //! Contructs set with elements "v0", "v1", "v2" and "v3"
PISet(const T & v0, const T & v1, const T & v2, const T & 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);}
_CSet::insert(v0, 0);
_CSet::insert(v1, 0);
_CSet::insert(v2, 0);
_CSet::insert(v3, 0);
}
//! Contructs set from vector of elements //! Contructs set from vector of elements
explicit PISet(const PIVector<T> & values) { PISet(const PIVector<T> & values) {
if (values.isEmpty()) return; if (values.isEmpty()) return;
for (int i = 0; i < values.size_s(); ++i) { for (int i = 0; i < values.size_s(); ++i) {
_CSet::insert(values[i], 0); _CSet::insert(values[i], 0);
@@ -75,7 +65,7 @@ public:
} }
//! Contructs set from deque of elements //! Contructs set from deque of elements
explicit PISet(const PIDeque<T> & values) { PISet(const PIDeque<T> & values) {
if (values.isEmpty()) return; if (values.isEmpty()) return;
for (int i = 0; i < values.size_s(); ++i) { for (int i = 0; i < values.size_s(); ++i) {
_CSet::insert(values[i], 0); _CSet::insert(values[i], 0);
@@ -84,39 +74,27 @@ public:
typedef T key_type; typedef T key_type;
PISet<T> & operator<<(const T & t) { PISet<T> & operator <<(const T & t) {_CSet::insert(t, 0); return *this;}
_CSet::insert(t, 0); PISet<T> & operator <<(T && t) {_CSet::insert(std::move(t), 0); return *this;}
return *this; PISet<T> & operator <<(const PISet<T> & other) {(*(_CSet*)this) << *((_CSet*)&other); 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 //! 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 //! Returns if element "t" exists in this set
PISet<T> & remove(const T & t) { PISet<T> & remove(const T & t) {_CSet::remove(t); return *this;}
_CSet::remove(t);
return *this;
}
//! Unite set with "v" //! Unite set with "v"
PISet<T> & unite(const PISet<T> & v) { PISet<T> & unite(const PISet<T> & v) {
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
_CSet::insert(i.key(), 0); _CSet::insert(i->first, 0);
return *this; return *this;
} }
//! Subtract set with "v" //! Subtract set with "v"
PISet<T> & subtract(const PISet<T> & v) { PISet<T> & subtract(const PISet<T> & v) {
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
_CSet::remove(i.key()); _CSet::remove(i->first);
return *this; return *this;
} }
@@ -143,69 +121,41 @@ public:
PISet<T> & operator &=(const PISet<T> & v) {return intersect(v);} PISet<T> & operator &=(const PISet<T> & v) {return intersect(v);}
//! Returns content of set as PIVector //! Returns content of set as PIVector
PIVector<T> toVector() const { PIVector<T> toVector() const {PIVector<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << (*i).first; return ret;}
PIVector<T> ret;
for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i)
ret << i.key();
return ret;
}
//! Returns content of set as PIDeque //! Returns content of set as PIDeque
PIDeque<T> toDeque() const { PIDeque<T> toDeque() const {PIDeque<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << (*i).first; return ret;}
PIDeque<T> ret;
for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i)
ret << i.key();
return ret;
}
}; };
//! \relatesalso PISet \brief Returns unite of two sets //! \relatesalso PISet \brief Returns unite of two sets
template<typename T> template <typename T> PISet<T> operator +(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
PISet<T> operator+(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.unite(v1);
return ret;
}
//! \relatesalso PISet \brief Returns subtraction of two sets //! \relatesalso PISet \brief Returns subtraction of two sets
template<typename T> template <typename T> PISet<T> operator -(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.subtract(v1); return ret;}
PISet<T> operator-(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.subtract(v1);
return ret;
}
//! \relatesalso PISet \brief Returns unite of two sets //! \relatesalso PISet \brief Returns unite of two sets
template<typename T> template <typename T> PISet<T> operator |(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
PISet<T> operator|(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.unite(v1);
return ret;
}
//! \relatesalso PISet \brief Returns intersetion of two sets //! \relatesalso PISet \brief Returns intersetion of two sets
template<typename T> template <typename T> PISet<T> operator &(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.intersect(v1); return ret;}
PISet<T> operator&(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.intersect(v1);
return ret;
}
template<typename Type> template<typename Type>
inline PICout operator <<(PICout s, const PISet<Type> & v) { inline PICout operator <<(PICout s, const PISet<Type> & v) {
s.space(); s.space();
s.saveAndSetControls(0); s.setControl(0, true);
s << "{"; s << "{";
bool first = true; bool first = true;
for (typename PIMap<Type, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) { for (typename PIMap<Type, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first) s << ", "; if (!first)
s << ", ";
first = false; first = false;
s << i.key(); s << i->first;
} }
s << "}"; s << "}";
s.restoreControls(); s.restoreControl();
return s; return s;
} }

View File

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

View File

@@ -74,9 +74,9 @@
//! if the number of elements is known beforehand. //! if the number of elements is known beforehand.
//! //!
//! The complexity (efficiency) of common operations on PIVector is as follows: //! The complexity (efficiency) of common operations on PIVector is as follows:
//! - Random access - constant O(1) //! - Random access - constant 𝓞(1)
//! - Insertion or removal of elements at the end - amortized constant O(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 O(n) //! - Insertion or removal of elements - linear in the distance to the end of the array 𝓞(n)
//! //!
//! \~russian //! \~russian
//! Элементы хранятся непрерывно, а значит доступны не только через итераторы, //! Элементы хранятся непрерывно, а значит доступны не только через итераторы,
@@ -109,9 +109,9 @@
//! если количество элементов известно заранее. //! если количество элементов известно заранее.
//! //!
//! Сложность (эффективность) обычных операций над PIVector следующая: //! Сложность (эффективность) обычных операций над PIVector следующая:
//! - Произвольный доступ — постоянная O(1) //! - Произвольный доступ — постоянная 𝓞(1)
//! - Вставка и удаление элементов в конце — амортизированная постоянная O(1) //! - Вставка и удаление элементов в конце — амортизированная постоянная 𝓞(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива O(n) //! - Вставка и удаление элементов — линейная по расстоянию до конца массива 𝓞(n)
//! //!
//! \~\sa \a PIDeque, \a PIMap //! \~\sa \a PIDeque, \a PIMap
template <typename T> template <typename T>
@@ -127,13 +127,15 @@ public:
//! \~english Constructs an empty array. //! \~english Constructs an empty array.
//! \~russian Создает пустой массив. //! \~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`. //! \~english Contructs array from raw `data`.
//! This constructor reserve `size` and copy from `data` pointer. //! This constructor reserve `size` and copy from `data` pointer.
//! \~russian Создает массив из указателя на данные `data` и размер `size`. //! \~russian Создает массив из указателя на данные `data` и размер `size`.
//! То есть выделяет память для `size` элементов и копирует данные из указателя `data`. //! То есть выделяет память для `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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(size); alloc(size);
newT(piv_data, data, piv_size); newT(piv_data, data, piv_size);
@@ -141,7 +143,7 @@ public:
//! \~english Copy constructor. //! \~english Copy constructor.
//! \~russian Копирующий конструктор. //! \~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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(v.piv_size); alloc(v.piv_size);
newT(piv_data, v.piv_data, piv_size); newT(piv_data, v.piv_data, piv_size);
@@ -156,7 +158,7 @@ public:
//! PIVector <int> v{1,2,3}; //! PIVector <int> v{1,2,3};
//! piCout << v; // {1, 2, 3} //! piCout << v; // {1, 2, 3}
//! \endcode //! \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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(init_list.size()); alloc(init_list.size());
newT(piv_data, init_list.begin(), init_list.size()); newT(piv_data, init_list.begin(), init_list.size());
@@ -164,9 +166,9 @@ public:
//! \~english Contructs array with size `size` filled elements `e`. //! \~english Contructs array with size `size` filled elements `e`.
//! \~russian Создает массив из `size` элементов заполненных `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)) 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)`. //! \~english Contructs array with size `size` and elements created by function `f(size_t i)`.
@@ -182,26 +184,24 @@ public:
//! PIVector <int> v(5, [](size_t i){return i*2;}); //! PIVector <int> v(5, [](size_t i){return i*2;});
//! piCout << v; // {0, 2, 4, 6, 8} //! piCout << v; // {0, 2, 4, 6, 8}
//! \endcode //! \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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
expand(size, f); resize(size, f);
} }
//! \~english Move constructor. //! \~english Move constructor.
//! \~russian Перемещающий конструктор. //! \~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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
piv_data = v.piv_data;
piv_size = v.piv_size;
piv_rsize = v.piv_rsize;
v._reset(); v._reset();
} }
inline ~PIVector() { inline virtual ~PIVector() {
PIINTROSPECTION_CONTAINER_DELETE(T) PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize)) PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize))
deleteT(piv_data, piv_size); deleteT(piv_data, piv_size);
dealloc(); dealloc();
_reset();
} }
//! \~english Assign operator. //! \~english Assign operator.
@@ -209,6 +209,7 @@ public:
inline PIVector<T> & operator =(const PIVector<T> & v) { inline PIVector<T> & operator =(const PIVector<T> & v) {
if (this == &v) return *this; if (this == &v) return *this;
clear(); clear();
deleteT(piv_data, piv_size);
alloc(v.piv_size); alloc(v.piv_size);
newT(piv_data, v.piv_data, piv_size); newT(piv_data, v.piv_data, piv_size);
return *this; return *this;
@@ -223,12 +224,10 @@ public:
class iterator { class iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: private:
inline iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {} inline iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
PIVector<T> * parent; PIVector<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T* pointer; typedef T* pointer;
@@ -248,7 +247,7 @@ public:
return *this; return *this;
} }
inline iterator operator ++(int) { inline iterator operator ++(int) {
const auto tmp = *this; auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -257,7 +256,7 @@ public:
return *this; return *this;
} }
inline iterator operator --(int) { inline iterator operator --(int) {
const auto tmp = *this; auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -285,7 +284,9 @@ public:
tmp -= p; tmp -= p;
return tmp; 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 +(size_t p, const iterator & it) {return it + p;}
friend inline iterator operator +(const iterator & it, size_t p) { friend inline iterator operator +(const iterator & it, size_t p) {
@@ -296,20 +297,26 @@ public:
inline bool operator ==(const iterator & it) const {return (pos == it.pos);} inline bool operator ==(const iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const iterator & it) const {return (pos != it.pos);} inline bool operator !=(const iterator & it) const {return (pos != it.pos);}
friend inline bool operator<(const iterator & it1, const iterator & it2) { return it1.pos < it2.pos; } friend inline bool operator <(const iterator & it1, const iterator & it2) {
friend inline bool operator<=(const iterator & it1, const iterator & it2) { return it1.pos <= it2.pos; } 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;
}
friend inline bool operator >(const iterator & it1, const iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const iterator & it1, const iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class const_iterator { class const_iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: private:
inline const_iterator(const PIVector<T> * v, ssize_t p): parent(v), pos(p) {} inline const_iterator(const PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
const PIVector<T> * parent; const PIVector<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T* pointer; typedef T* pointer;
@@ -327,7 +334,7 @@ public:
return *this; return *this;
} }
inline const_iterator operator ++(int) { inline const_iterator operator ++(int) {
const auto tmp = *this; auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -336,7 +343,7 @@ public:
return *this; return *this;
} }
inline const_iterator operator --(int) { inline const_iterator operator --(int) {
const auto tmp = *this; auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -364,7 +371,9 @@ public:
tmp -= p; tmp -= p;
return tmp; 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 +(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 +(const const_iterator & it, size_t p) {
@@ -375,20 +384,26 @@ public:
inline bool operator ==(const const_iterator & it) const {return (pos == it.pos);} inline bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const const_iterator & it) const {return (pos != it.pos);} inline bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
friend inline bool operator<(const const_iterator & it1, const const_iterator & it2) { return it1.pos < it2.pos; } friend inline bool operator <(const const_iterator & it1, const const_iterator & it2) {
friend inline bool operator<=(const const_iterator & it1, const const_iterator & it2) { return it1.pos <= it2.pos; } 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;
}
friend inline bool operator >(const const_iterator & it1, const const_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const const_iterator & it1, const const_iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class reverse_iterator { class reverse_iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: private:
inline reverse_iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {} inline reverse_iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
PIVector<T> * parent; PIVector<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T* pointer; typedef T* pointer;
@@ -408,7 +423,7 @@ public:
return *this; return *this;
} }
inline reverse_iterator operator ++(int) { inline reverse_iterator operator ++(int) {
const auto tmp = *this; auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -417,7 +432,7 @@ public:
return *this; return *this;
} }
inline reverse_iterator operator --(int) { inline reverse_iterator operator --(int) {
const auto tmp = *this; auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -445,7 +460,9 @@ public:
tmp -= p; tmp -= p;
return tmp; 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 +(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 +(const reverse_iterator & it, size_t p) {
@@ -456,20 +473,26 @@ public:
inline bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);} inline bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);} inline bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
friend inline bool operator<(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos < it2.pos; } friend inline bool operator <(const reverse_iterator & it1, const reverse_iterator & it2) {
friend inline bool operator<=(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos <= it2.pos; } 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;
}
friend inline bool operator >(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class const_reverse_iterator { class const_reverse_iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: private:
inline const_reverse_iterator(const PIVector<T> * v, ssize_t p): parent(v), pos(p) {} inline const_reverse_iterator(const PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
const PIVector<T> * parent; const PIVector<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T* pointer; typedef T* pointer;
@@ -486,7 +509,7 @@ public:
return *this; return *this;
} }
inline const_reverse_iterator operator ++(int) { inline const_reverse_iterator operator ++(int) {
const auto tmp = *this; auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -495,7 +518,7 @@ public:
return *this; return *this;
} }
inline const_reverse_iterator operator --(int) { inline const_reverse_iterator operator --(int) {
const auto tmp = *this; auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -536,10 +559,18 @@ public:
inline bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);} inline bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);} inline bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
friend inline bool operator<(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos < it2.pos; } friend inline bool operator <(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {
friend inline bool operator<=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos <= it2.pos; } 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;
}
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. //! \~english Iterator to the first element.
@@ -614,7 +645,7 @@ public:
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. //! \~english Number of elements that the container has currently allocated space for.
//! \~russian Количество элементов, для которого сейчас выделена память массивом. //! \~russian Количество элементов, для которого сейчас выделена память контейнером.
//! \~\details //! \~\details
//! \~english To find out the actual number of items, use the function \a size(). //! \~english To find out the actual number of items, use the function \a size().
//! \~russian Чтобы узнать фактическое количество элементов используйте функцию \a size(). //! \~russian Чтобы узнать фактическое количество элементов используйте функцию \a size().
@@ -622,18 +653,18 @@ public:
inline size_t capacity() const {return piv_rsize;} inline size_t capacity() const {return piv_rsize;}
//! \~english Checks if the container has no elements. //! \~english Checks if the container has no elements.
//! \~russian Проверяет пуст ли массив. //! \~russian Проверяет пуст ли контейнер.
//! \~\return //! \~\return
//! \~english **true** if the container is empty, **false** otherwise //! \~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() //! \~\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. //! \~english Checks if the container has elements.
//! \~russian Проверяет не пуст ли массив. //! \~russian Проверяет не пуст ли контейнер.
//! \~\return //! \~\return
//! \~english **true** if the container is not empty, **false** otherwise //! \~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() //! \~\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);}
@@ -717,35 +748,6 @@ public:
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти. //! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline const T & at(size_t index) const {return piv_data[index];} inline const T & at(size_t index) const {return piv_data[index];}
//! \~english Returns the first element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает первый элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a indexWhere()
inline const T & atWhere(std::function<bool(const T & e)> test, ssize_t start = 0, const T & def = T()) const {
const ssize_t i = indexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
//! \~english Returns the last element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает последний элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a lastIndexWhere()
inline const T & lastAtWhere(std::function<bool(const T & e)> test, ssize_t start = -1, const T & def = T()) const {
const ssize_t i = lastIndexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
//! \~english Last element. //! \~english Last element.
//! \~russian Последний элемент массива. //! \~russian Последний элемент массива.
//! \~\details //! \~\details
@@ -800,7 +802,7 @@ public:
//! возвращается **false**, что означает, что массив даже не просматривается. //! возвращается **false**, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIVector<int> v{1, 2, 3, 4}; //! PIVector<int> v{1, 2, 3, 4};
@@ -827,33 +829,6 @@ public:
return false; 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. //! \~english Count elements equal `e` in the array.
//! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве. //! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве.
//! \~\details //! \~\details
@@ -870,7 +845,7 @@ public:
//! возвращается 0, что означает, что массив даже не просматривается. //! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIVector<int> v{2, 2, 4, 2, 6}; //! PIVector<int> v{2, 2, 4, 2, 6};
@@ -910,7 +885,7 @@ public:
//! возвращается 0, что означает, что массив даже не просматривается. //! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\sa \a every(), \a any(), \a contains(), \a forEach(), \a indexWhere() //! \~\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, ssize_t start = 0) const {
@@ -943,7 +918,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается. //! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIVector<int> v{2, 5, 9}; //! PIVector<int> v{2, 5, 9};
@@ -984,7 +959,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается. //! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIVector<PIString> v{"do", "re", "mi", "re"}; //! PIVector<PIString> v{"do", "re", "mi", "re"};
@@ -1024,7 +999,7 @@ public:
//! c которого начинать поиск в обратном направлении. //! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив. //! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу.
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается. //! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента //! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив. //! и означает, что просматривается весь массив.
@@ -1067,7 +1042,7 @@ public:
//! c которого начинать поиск в обратном направлении. //! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив. //! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево). //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу.
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается. //! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента //! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив. //! и означает, что просматривается весь массив.
@@ -1134,7 +1109,7 @@ public:
PIVector<T> getRange(size_t index, size_t count) const { PIVector<T> getRange(size_t index, size_t count) const {
if (index >= piv_size || count == 0) return PIVector<T>(); if (index >= piv_size || count == 0) return PIVector<T>();
if (index + count > piv_size) count = piv_size - index; 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. //! \~english Clear array, remove all elements.
@@ -1144,13 +1119,16 @@ public:
//! \~english Reserved memory will not be released. //! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится. //! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize() //! \~\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() { inline PIVector<T> & clear() {
deleteT(piv_data, piv_size); resize(0);
piv_size = 0;
return *this; 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() { inline PIVector<T> & clear() {
PIINTROSPECTION_CONTAINER_UNUSED(T, piv_size) PIINTROSPECTION_CONTAINER_UNUSED(T, piv_size)
piv_size = 0; piv_size = 0;
@@ -1201,12 +1179,16 @@ public:
//! \~english First does `resize(new_size)` then `fill(e)`. //! \~english First does `resize(new_size)` then `fill(e)`.
//! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`. //! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`.
//! \~\sa \a fill(), \a resize() //! \~\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) { inline PIVector<T> & assign(size_t new_size, const T & f) {
resize(new_size); resize(new_size);
return fill(f); 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) { inline PIVector<T> & assign(size_t new_size, const T & f) {
_resizeRaw(new_size); _resizeRaw(new_size);
return fill(f); return fill(f);
@@ -1225,10 +1207,17 @@ public:
//! \~\sa \a size(), \a clear() //! \~\sa \a size(), \a clear()
inline PIVector<T> & resize(size_t new_size, const T & e = T()) { inline PIVector<T> & resize(size_t new_size, const T & e = T()) {
if (new_size < piv_size) { 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; 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; return *this;
} }
@@ -1246,29 +1235,38 @@ public:
//! \~\sa \a size(), \a clear() //! \~\sa \a size(), \a clear()
inline PIVector<T> & resize(size_t new_size, std::function<T(size_t i)> f) { inline PIVector<T> & resize(size_t new_size, std::function<T(size_t i)> f) {
if (new_size < piv_size) { if (new_size < piv_size) {
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; 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; 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) { inline PIVector<T> & _resizeRaw(size_t new_size) {
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
if (new_size > piv_size) { 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) { 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); alloc(new_size);
return *this; 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. //! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов. //! \~russian Резервируется память под как минимум `new_size` элементов.
@@ -1286,7 +1284,7 @@ public:
//! \~\sa \a size(), \a capacity(), \a resize() //! \~\sa \a size(), \a capacity(), \a resize()
inline PIVector<T> & reserve(size_t new_size) { inline PIVector<T> & reserve(size_t new_size) {
if (new_size <= piv_rsize) return *this; if (new_size <= piv_rsize) return *this;
const size_t os = piv_size; size_t os = piv_size;
alloc(new_size); alloc(new_size);
piv_size = os; piv_size = os;
return *this; return *this;
@@ -1306,8 +1304,8 @@ public:
inline PIVector<T> & insert(size_t index, const T & e = T()) { inline PIVector<T> & insert(size_t index, const T & e = T()) {
alloc(piv_size + 1); alloc(piv_size + 1);
if (index < piv_size - 1) { if (index < piv_size - 1) {
const size_t os = piv_size - index - 1; 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)); memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
} }
PIINTROSPECTION_CONTAINER_USED(T, 1) PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, e); elementNew(piv_data + index, e);
@@ -1323,8 +1321,8 @@ public:
inline PIVector<T> & insert(size_t index, T && e) { inline PIVector<T> & insert(size_t index, T && e) {
alloc(piv_size + 1); alloc(piv_size + 1);
if (index < piv_size - 1) { if (index < piv_size - 1) {
const size_t os = piv_size - index - 1; 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)); memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
} }
PIINTROSPECTION_CONTAINER_USED(T, 1) PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, std::move(e)); elementNew(piv_data + index, std::move(e));
@@ -1345,12 +1343,10 @@ public:
} }
#endif #endif
assert(&v != this); assert(&v != this);
const ssize_t os = piv_size - index; ssize_t os = piv_size - index;
alloc(piv_size + v.piv_size); alloc(piv_size + v.piv_size);
if (os > 0) { if (os > 0) {
memmove(reinterpret_cast<void *>(piv_data + index + v.piv_size), memmove((void*)(&(piv_data[index + v.piv_size])), (const void*)(&(piv_data[index])), os * sizeof(T));
reinterpret_cast<const void *>(piv_data + index),
os * sizeof(T));
} }
newT(piv_data + index, v.piv_data, v.piv_size); newT(piv_data + index, v.piv_data, v.piv_size);
return *this; return *this;
@@ -1367,13 +1363,10 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append(), \a prepend(), \a remove() //! \~\sa \a append(), \a prepend(), \a remove()
inline PIVector<T> & insert(size_t index, std::initializer_list<T> init_list) { inline PIVector<T> & insert(size_t index, std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this; ssize_t os = piv_size - index;
const ssize_t os = piv_size - index;
alloc(piv_size + init_list.size()); alloc(piv_size + init_list.size());
if (os > 0) { if (os > 0) {
memmove(reinterpret_cast<void *>(piv_data + index + init_list.size()), memmove((void*)(&(piv_data[index + init_list.size()])), (const void*)(&(piv_data[index])), os * sizeof(T));
reinterpret_cast<const void *>(piv_data + index),
os * sizeof(T));
} }
newT(piv_data + index, init_list.begin(), init_list.size()); newT(piv_data + index, init_list.begin(), init_list.size());
return *this; return *this;
@@ -1391,16 +1384,13 @@ public:
inline PIVector<T> & remove(size_t index, size_t count = 1) { inline PIVector<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this; if (count == 0) return *this;
if (index + count >= piv_size) { if (index + count >= piv_size) {
if (index < piv_size) { resize(index);
deleteT(piv_data + index, piv_size - index); return *this;
piv_size = index;
} }
} else { size_t os = piv_size - index - count;
const size_t os = piv_size - index - count; deleteT(&(piv_data[index]), count);
deleteT(piv_data + index, count); memmove((void*)(&(piv_data[index])), (const void*)(&(piv_data[index + count])), os * sizeof(T));
memmove(reinterpret_cast<void *>(piv_data + index), reinterpret_cast<const void *>(piv_data + index + count), os * sizeof(T));
piv_size -= count; piv_size -= count;
}
return *this; return *this;
} }
@@ -1454,11 +1444,16 @@ public:
//! Complexity `O(N·log(N))`. //! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется. //! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется функция сравнения `comp`. //! Для сравнения элементов используется функция сравнения `comp`.
//! Функция сравнения, возвращает `true` если первый аргумент меньше //! Функция сравнения, возвращает `true` если первый аргумент меньше второго.
//! второго. Сигнатура функции сравнения должна быть эквивалентна следующей: \code bool comp(const T &a, const T &b); \endcode Сигнатура //! Сигнатура функции сравнения должна быть эквивалентна следующей:
//! не обязана содержать const &, однако, функция не может изменять переданные объекты. Функция обязана возвращать `false` для //! \code
//! одинаковых элементов, иначе это приведёт к неопределённому поведению программы и ошибкам памяти. Для сортировки используется функция //! bool comp(const T &a, const T &b);
//! [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort). Сложность сортировки `O(N·log(N))`. //! \endcode
//! Сигнатура не обязана содержать const &, однако, функция не может изменять переданные объекты.
//! Функция обязана возвращать `false` для одинаковых элементов,
//! иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort).
//! Сложность сортировки `O(N·log(N))`.
//! \~\code //! \~\code
//! PIVector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3}; //! PIVector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort([](const int & a, const int & b){return a > b;}); //! v.sort([](const int & a, const int & b){return a > b;});
@@ -1487,7 +1482,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a reversed() //! \~\sa \a reversed()
inline PIVector<T> & reverse() { 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) { 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]);
} }
@@ -1517,12 +1512,10 @@ public:
//! Если `add_size < 0`, то с конца массива удаляются элементы. //! Если `add_size < 0`, то с конца массива удаляются элементы.
//! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым. //! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым.
//! \~\sa \a resize() //! \~\sa \a resize()
inline PIVector<T> & enlarge(ssize_t add_size, const T & e = T()) { inline PIVector<T> & enlarge(llong add_size, const T & e = T()) {
const ssize_t ns = size_s() + add_size; llong ns = size_s() + add_size;
if (ns <= 0) if (ns <= 0) clear();
clear(); else resize(size_t(ns), e);
else
resize(size_t(ns), e);
return *this; return *this;
} }
@@ -1640,8 +1633,7 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a push_back() //! \~\sa \a push_back()
inline PIVector<T> & push_back(std::initializer_list<T> init_list) { inline PIVector<T> & push_back(std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this; size_t ps = piv_size;
const size_t ps = piv_size;
alloc(piv_size + init_list.size()); alloc(piv_size + init_list.size());
newT(piv_data + ps, init_list.begin(), init_list.size()); newT(piv_data + ps, init_list.begin(), init_list.size());
return *this; return *this;
@@ -1654,14 +1646,13 @@ public:
//! \~russian Перегруженая функция. //! \~russian Перегруженая функция.
//! \~\sa \a push_back() //! \~\sa \a push_back()
inline PIVector<T> & push_back(const PIVector<T> & v) { inline PIVector<T> & push_back(const PIVector<T> & v) {
if (v.isEmpty()) return *this;
#ifndef NDEBUG #ifndef NDEBUG
if (&v == this) { if (&v == this) {
printf("error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T)); printf("error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T));
} }
#endif #endif
assert(&v != this); assert(&v != this);
const size_t ps = piv_size; size_t ps = piv_size;
alloc(piv_size + v.piv_size); alloc(piv_size + v.piv_size);
newT(piv_data + ps, v.piv_data, v.piv_size); newT(piv_data + ps, v.piv_data, v.piv_size);
return *this; return *this;
@@ -1776,7 +1767,10 @@ public:
//! piCout << v; // {5, 4, 1, 2, 3} //! piCout << v; // {5, 4, 1, 2, 3}
//! \endcode //! \endcode
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert() //! \~\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. //! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива. //! \~russian Добавляет элемент `e` в начало массива.
@@ -1784,7 +1778,10 @@ public:
//! \~english Overloaded function. //! \~english Overloaded function.
//! \~russian Перегруженая функция. //! \~russian Перегруженая функция.
//! \~\sa \a push_front() //! \~\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. //! \~english Appends the given array `v` to the begin of the array.
//! \~russian Добавляет массив `v` в начало массива. //! \~russian Добавляет массив `v` в начало массива.
@@ -1797,7 +1794,10 @@ public:
//! piCout << v; // {4, 5, 1, 2, 3} //! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode //! \endcode
//! \~\sa \a push_front() //! \~\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. //! \~english Appends the given elements to the begin of the array.
//! \~russian Добавляет элементы в начало массива. //! \~russian Добавляет элементы в начало массива.
@@ -1809,7 +1809,10 @@ public:
//! Добавляет элементы из //! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append() //! \~\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. //! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива. //! \~russian Добавляет элемент `e` в начало массива.
@@ -1877,8 +1880,7 @@ public:
//! \~\sa \a pop_front(), \a take_back(), \a take_front() //! \~\sa \a pop_front(), \a take_back(), \a take_front()
inline PIVector<T> & pop_back() { inline PIVector<T> & pop_back() {
if (piv_size == 0) return *this; if (piv_size == 0) return *this;
deleteT(piv_data + piv_size - 1, 1); resize(piv_size - 1);
piv_size = piv_size - 1;
return *this; return *this;
} }
@@ -1913,7 +1915,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front() //! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_back() { inline T take_back() {
const T e(back()); T e(back());
pop_back(); pop_back();
return e; return e;
} }
@@ -1928,7 +1930,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front() //! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_front() { inline T take_front() {
const T e(front()); T e(front());
pop_front(); pop_front();
return e; return e;
} }
@@ -1944,8 +1946,7 @@ public:
//! \~\sa \a map() //! \~\sa \a map()
template <typename ST> template <typename ST>
inline PIVector<ST> toType() const { inline PIVector<ST> toType() const {
PIVector<ST> ret; PIVector<ST> ret; ret.reserve(piv_size);
ret.reserve(piv_size);
for (size_t i = 0; i < piv_size; ++i) { for (size_t i = 0; i < piv_size; ++i) {
ret << ST(piv_data[i]); ret << ST(piv_data[i]);
} }
@@ -1953,9 +1954,9 @@ public:
} }
//! \~english Returns a new array with all elements //! \~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 Возвращает новый массив со всеми элементами, //! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `bool test(const T & e)`. //! прошедшими проверку, задаваемую в передаваемой функции `test`.
//! \~\details //! \~\details
//! \~\code //! \~\code
//! PIVector<int> v{3, 2, 5, 2, 7}; //! PIVector<int> v{3, 2, 5, 2, 7};
@@ -1971,39 +1972,6 @@ public:
return ret; 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. //! \~english Execute function `void f(const T & e)` for every element in array.
//! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива. //! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива.
//! \~\details //! \~\details
@@ -2044,63 +2012,6 @@ public:
return *this; 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 //! \~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. //! of calling a provided function `ST f(const T & e)` on every element in the calling array.
//! \~russian Создаёт новый массив с результатом вызова указанной функции //! \~russian Создаёт новый массив с результатом вызова указанной функции
@@ -2115,73 +2026,18 @@ public:
//! \~\code //! \~\code
//! PIVector<int> v{1, 2, 3}; //! PIVector<int> v{1, 2, 3};
//! PIVector<PIString> sl = v.map<PIString>([](const int & i){return PIString::fromNumber(i);}); //! PIVector<PIString> sl = v.map<PIString>([](const int & i){return PIString::fromNumber(i);});
//! piCout << sl; // {"1", "2", "3"} //! piCout << sl; {"1", "2", "3"}
//! \endcode //! \endcode
//! \~\sa \a forEach(), \a reduce() //! \~\sa \a forEach(), \a reduce()
template <typename ST> template <typename ST>
inline PIVector<ST> map(std::function<ST(const T & e)> f) const { inline PIVector<ST> map(std::function<ST(const T & e)> f) const {
PIVector<ST> ret; PIVector<ST> ret; ret.reserve(piv_size);
ret.reserve(piv_size);
for (size_t i = 0; i < piv_size; ++i) { for (size_t i = 0; i < piv_size; ++i) {
ret << f(piv_data[i]); ret << f(piv_data[i]);
} }
return ret; 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)` //! \~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. //! to each element of the array (from left to right), returns one value.
//! \~russian Применяет функцию `ST f(const T & e, const ST & acc)` //! \~russian Применяет функцию `ST f(const T & e, const ST & acc)`
@@ -2232,42 +2088,6 @@ public:
return ret; return ret;
} }
//! \~english Same as \a reduce() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduce() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (size_t i = 0; i < piv_size; ++i) {
ret = f(i, piv_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduce() but from end to begin (from right to left).
//! \~russian Аналогично \a reduce() но от конца до начала (справа на лево).
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceReverse(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = piv_size; i >= 0; --i) {
ret = f(piv_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduceReverse() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduceReverse() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduceReverse()
template<typename ST>
inline ST reduceReverseIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = piv_size; i >= 0; --i) {
ret = f(i, piv_data[i], ret);
}
return ret;
}
//! \~english Changes the dimension of the array, creates a two-dimensional array from a one-dimensional array. //! \~english Changes the dimension of the array, creates a two-dimensional array from a one-dimensional array.
//! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный. //! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный.
//! \~\details //! \~\details
@@ -2296,7 +2116,7 @@ public:
assert(rows*cols == piv_size); assert(rows*cols == piv_size);
PIVector<PIVector<T>> ret; PIVector<PIVector<T>> ret;
if (isEmpty()) return ret; if (isEmpty()) return ret;
ret.expand(rows); ret.resize(rows);
if (order == ReshapeByRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r] = PIVector<T>(&(piv_data[r*cols]), cols); ret[r] = PIVector<T>(&(piv_data[r*cols]), cols);
@@ -2327,12 +2147,14 @@ public:
//! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6} //! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6}
//! \endcode //! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape() //! \~\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 { inline PIVector<C> flatten(ReshapeOrder order = ReshapeByRow) const {
PIVector<C> ret; PIVector<C> ret;
if (isEmpty()) return ret; if (isEmpty()) return ret;
const size_t rows = size(); size_t rows = size();
const size_t cols = at(0).size(); size_t cols = at(0).size();
ret.reserve(rows * cols); ret.reserve(rows * cols);
if (order == ReshapeByRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
@@ -2368,195 +2190,96 @@ public:
//! piCout << xv.reshape<int>(2,3); // {{1, 2, 3}, {4, 5, 6}} //! piCout << xv.reshape<int>(2,3); // {{1, 2, 3}, {4, 5, 6}}
//! \endcode //! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape() //! \~\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 { inline PIVector<PIVector<C>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
PIVector<C> fl = flatten<C>(); PIVector<C> fl = flatten<C>();
return fl.reshape(rows, cols, order); 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: private:
inline void _reset() { inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;}
piv_size = 0;
piv_rsize = 0;
piv_data = nullptr;
}
inline size_t asize(size_t s) { inline size_t asize(size_t s) {
if (s == 0) return 0; if (s == 0) return 0;
if (piv_rsize * 2 >= s && piv_rsize < s) { if (piv_rsize + piv_rsize >= s && piv_rsize < s) {
return piv_rsize * 2; return piv_rsize + piv_rsize;
} }
ssize_t t = _PIContainerConstants<T>::minCountPoT(); ssize_t t = _PIContainerConstants<T>::minCountPoT(), s_ = s - 1;
s -= 1; while (s_ >> t)
while (s >> t)
++t; ++t;
return (1 << t); return (1 << t);
} }
template<typename T1 = T, typename std::enable_if<
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0> !std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) { inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(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]); elementNew(dst + i, src[i]);
} }
} template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0> , int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) { inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(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<
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0> !std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if (d != nullptr) { if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i) { for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]); elementDelete(d[i]);
} }
} }
} }
template<typename T1 = T, typename std::enable_if<
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0> std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
} }
template<typename T1 = T, typename std::enable_if<
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0> !std::is_trivially_copyable<T1>::value
inline void elementNew(T * to, const T & from) { , int>::type = 0>
new (to) T(from); 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
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0> , int>::type = 0>
inline void elementNew(T * to, T && from) { inline void elementNew(T * to, T && from) {new(to)T(std::move(from));}
new (to) T(std::move(from)); 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(T1 * to, const T & from) {(*to) = from;}
inline void elementNew(T1 * to, const T & from) { template<typename T1 = T, typename std::enable_if<
(*to) = from; 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> template<typename T1 = T, typename std::enable_if<
inline void elementNew(T * to, T && from) { !std::is_trivially_copyable<T1>::value
(*to) = std::move(from); , int>::type = 0>
} inline void elementDelete(T & from) {from.~T();}
template<typename T1 = T, typename std::enable_if<
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0> std::is_trivially_copyable<T1>::value
inline void elementDelete(T & from) { , int>::type = 0>
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 elementDelete(T & from) {}
inline void dealloc() { inline void dealloc() {
if (piv_data != nullptr) { if ((uchar*)piv_data != 0) free((uchar*)piv_data);
free(reinterpret_cast<void *>(piv_data)); piv_data = 0;
piv_data = nullptr;
} }
}
inline void expand(size_t new_size, const T & e = T()) {
const size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size - os))
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, e);
}
}
inline void expand(size_t new_size, std::function<T(size_t i)> f) {
const size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size - os))
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, f(i));
}
}
inline void alloc(size_t new_size) { inline void alloc(size_t new_size) {
if (new_size <= piv_rsize) { if (new_size <= piv_rsize) {
piv_size = new_size; piv_size = new_size;
return; return;
} }
piv_size = new_size; piv_size = new_size;
const size_t as = asize(new_size); size_t as = asize(new_size);
if (as == piv_rsize) return; if (as == piv_rsize) return;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-piv_rsize)) PIINTROSPECTION_CONTAINER_ALLOC(T, (as-piv_rsize))
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(piv_data), as * sizeof(T))); T * p_d = (T*)(realloc((void*)(piv_data), as*sizeof(T)));
#ifndef NDEBUG #ifndef NDEBUG
if (!p_d) { if (!p_d) {
printf("error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T)); printf("error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T));
@@ -2567,9 +2290,8 @@ private:
piv_rsize = as; piv_rsize = as;
} }
T * piv_data = nullptr; T * piv_data;
size_t piv_size = 0; size_t piv_size, piv_rsize;
size_t piv_rsize = 0;
}; };
@@ -2594,7 +2316,7 @@ inline std::ostream & operator<<(std::ostream & s, const PIVector<T> & v) {
template<typename T> template<typename T>
inline PICout operator <<(PICout s, const PIVector<T> & v) { inline PICout operator <<(PICout s, const PIVector<T> & v) {
s.space(); s.space();
s.saveAndSetControls(0); s.setControl(0, true);
s << "{"; s << "{";
for (size_t i = 0; i < v.size(); ++i) { for (size_t i = 0; i < v.size(); ++i) {
s << v[i]; s << v[i];
@@ -2603,13 +2325,11 @@ inline PICout operator<<(PICout s, const PIVector<T> & v) {
} }
} }
s << "}"; s << "}";
s.restoreControls(); s.restoreControl();
return s; return s;
} }
template<typename T> template<typename T>
inline void piSwap(PIVector<T> & f, PIVector<T> & s) { inline void piSwap(PIVector<T> & f, PIVector<T> & s) {f.swap(s);}
f.swap(s);
}
#endif // PIVECTOR_H #endif // PIVECTOR_H

View File

@@ -39,17 +39,17 @@ template<typename T>
class PIVector2D { class PIVector2D {
public: public:
inline PIVector2D() {rows_ = cols_ = 0;} inline PIVector2D() {rows_ = cols_ = 0;}
inline PIVector2D(size_t rows, size_t cols, const T & f = T()) { inline PIVector2D(size_t rows, size_t cols, const T & f = T()) {
rows_ = rows; rows_ = rows;
cols_ = cols; cols_ = cols;
mat.resize(rows*cols, f); mat.resize(rows*cols, f);
} }
inline PIVector2D(size_t rows, size_t cols, const PIVector<T> & v) : rows_(rows), cols_(cols), mat(v) {
inline PIVector2D(size_t rows, size_t cols, const PIVector<T> & v): rows_(rows), cols_(cols), mat(v) { mat.resize(rows * cols); } mat.resize(rows*cols);
}
inline PIVector2D(size_t rows, size_t cols, PIVector<T> && v): rows_(rows), cols_(cols), mat(std::move(v)) { mat.resize(rows * cols); } inline PIVector2D(size_t rows, size_t cols, PIVector<T> && v) : rows_(rows), cols_(cols), mat(std::move(v)) {
mat.resize(rows*cols);
}
inline PIVector2D(const PIVector<PIVector<T>> & v) { inline PIVector2D(const PIVector<PIVector<T>> & v) {
rows_ = v.size(); rows_ = v.size();
if (rows_) { if (rows_) {
@@ -64,32 +64,19 @@ public:
} }
inline size_t rows() const {return rows_;} inline size_t rows() const {return rows_;}
inline size_t cols() const {return cols_;} inline size_t cols() const {return cols_;}
inline size_t size() const {return mat.size();} inline size_t size() const {return mat.size();}
inline ssize_t size_s() const {return mat.size_s();} inline ssize_t size_s() const {return mat.size_s();}
inline size_t length() const {return mat.length();} inline size_t length() const {return mat.length();}
inline size_t capacity() const {return mat.capacity();} inline size_t capacity() const {return mat.capacity();}
inline bool isEmpty() const {return mat.isEmpty();} inline bool isEmpty() const {return mat.isEmpty();}
inline bool isNotEmpty() const { return mat.isNotEmpty(); }
class Row { class Row {
friend class PIVector2D<T>; friend class PIVector2D<T>;
private: private:
inline Row(PIVector2D<T> * p, size_t row): p_(&(p->mat)) { inline Row(PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {st_ = p->cols_ * row; sz_ = p->cols_;}
st_ = p->cols_ * row;
sz_ = p->cols_;
}
PIVector<T> * p_; PIVector<T> * p_;
size_t st_, sz_; size_t st_, sz_;
public: public:
inline size_t size() const {return sz_;} inline size_t size() const {return sz_;}
inline T & operator [](size_t index) {return (*p_)[st_ + index];} inline T & operator [](size_t index) {return (*p_)[st_ + index];}
@@ -98,12 +85,12 @@ public:
inline const T * data(size_t index = 0) const {return p_->data(st_ + index);} inline const T * data(size_t index = 0) const {return p_->data(st_ + index);}
inline Row & operator =(const Row & other) { inline Row & operator =(const Row & other) {
if (p_ == other.p_ && st_ == other.st_) return *this; if (p_ == other.p_ && st_ == other.st_) return *this;
const size_t sz = piMin<size_t>(sz_, other.sz_); size_t sz = piMin<size_t>(sz_, other.sz_);
p_->_copyRaw(p_->data(st_), other.data(), sz); p_->_copyRaw(p_->data(st_), other.data(), sz);
return *this; return *this;
} }
inline Row & operator =(const PIVector<T> & other) { inline Row & operator =(const PIVector<T> & other) {
const size_t sz = piMin<size_t>(sz, other.size()); size_t sz = piMin<size_t>(sz, other.size());
p_->_copyRaw(p_->data(st_), other.data(), sz); p_->_copyRaw(p_->data(st_), other.data(), sz);
return *this; return *this;
} }
@@ -112,16 +99,10 @@ public:
class Col { class Col {
friend class PIVector2D<T>; friend class PIVector2D<T>;
private: private:
inline Col(PIVector2D<T> * p, size_t row): p_(&(p->mat)) { inline Col(PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {step_ = p->cols_; row_ = row; sz_ = p->rows_;}
step_ = p->cols_;
row_ = row;
sz_ = p->rows_;
}
PIVector<T> * p_; PIVector<T> * p_;
size_t step_, row_, sz_; size_t step_, row_, sz_;
public: public:
inline size_t size() const {return sz_;} inline size_t size() const {return sz_;}
inline T & operator [](size_t index) {return (*p_)[index * step_ + row_];} inline T & operator [](size_t index) {return (*p_)[index * step_ + row_];}
@@ -130,37 +111,29 @@ public:
inline const T * data(size_t index = 0) const {return p_->data(index * step_ + row_);} inline const T * data(size_t index = 0) const {return p_->data(index * step_ + row_);}
inline Col & operator =(const Col & other) { inline Col & operator =(const Col & other) {
if (p_ == other.p_ && row_ == other.row_) return *this; if (p_ == other.p_ && row_ == other.row_) return *this;
const size_t sz = piMin<size_t>(sz_, other.sz_); size_t sz = piMin<size_t>(sz_, other.sz_);
for (int i = 0; i < sz; ++i) for (int i=0; i<sz; ++i) (*p_)[i * step_ + row_] = other[i];
(*p_)[i * step_ + row_] = other[i];
return *this; return *this;
} }
inline Row & operator =(const PIVector<T> & other) { inline Row & operator =(const PIVector<T> & other) {
const size_t sz = piMin<size_t>(sz_, other.size()); size_t sz = piMin<size_t>(sz_, other.size());
for (int i = 0; i < sz; ++i) for (int i=0; i<sz; ++i) (*p_)[i * step_ + row_] = other[i];
(*p_)[i * step_ + row_] = other[i];
return *this; return *this;
} }
inline PIVector<T> toVector() const { inline PIVector<T> toVector() const {
PIVector<T> ret; PIVector<T> ret;
ret.reserve(sz_); ret.reserve(sz_);
for (size_t i = 0; i < sz_; i++) for (size_t i=0; i<sz_; i++) ret << (*p_)[i * step_ + row_];
ret << (*p_)[i * step_ + row_];
return ret; return ret;
} }
}; };
class RowConst { class RowConst {
friend class PIVector2D<T>; friend class PIVector2D<T>;
private: private:
inline RowConst(const PIVector2D<T> * p, size_t row): p_(&(p->mat)) { inline RowConst(const PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {st_ = p->cols_ * row; sz_ = p->cols_;}
st_ = p->cols_ * row;
sz_ = p->cols_;
}
const PIVector<T> * p_; const PIVector<T> * p_;
size_t st_, sz_; size_t st_, sz_;
public: public:
inline size_t size() const {return sz_;} inline size_t size() const {return sz_;}
inline const T & operator [](size_t index) const {return (*p_)[st_ + index];} inline const T & operator [](size_t index) const {return (*p_)[st_ + index];}
@@ -170,16 +143,10 @@ public:
class ColConst { class ColConst {
friend class PIVector2D<T>; friend class PIVector2D<T>;
private: private:
inline ColConst(const PIVector2D<T> * p, size_t row): p_(&(p->mat)) { inline ColConst(const PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {step_ = p->cols_; row_ = row; sz_ = p->rows_;}
step_ = p->cols_;
row_ = row;
sz_ = p->rows_;
}
const PIVector<T> * p_; const PIVector<T> * p_;
size_t step_, row_, sz_; size_t step_, row_, sz_;
public: public:
inline size_t size() const {return p_->rows_;} inline size_t size() const {return p_->rows_;}
inline const T & operator [](size_t index) const {return (*p_)[index * step_ + row_];} inline const T & operator [](size_t index) const {return (*p_)[index * step_ + row_];}
@@ -187,8 +154,7 @@ public:
inline PIVector<T> toVector() const { inline PIVector<T> toVector() const {
PIVector<T> ret; PIVector<T> ret;
ret.reserve(sz_); ret.reserve(sz_);
for (int i = 0; i < size(); i++) for (int i=0; i<size(); i++) ret << (*p_)[i * step_ + row_];
ret << (*p_)[i * step_ + row_];
return ret; return ret;
} }
}; };
@@ -206,24 +172,24 @@ public:
inline Col col(size_t index) {return Col(this, index);} inline Col col(size_t index) {return Col(this, index);}
inline ColConst col(size_t index) const {return ColConst(this, index);} inline ColConst col(size_t index) const {return ColConst(this, index);}
inline PIVector2D<T> & setRow(size_t row, const Row & other) { inline PIVector2D<T> & setRow(size_t row, const Row & other) {
const size_t sz = piMin<size_t>(cols_, other.sz_); size_t sz = piMin<size_t>(cols_, other.sz_);
mat._copyRaw(mat.data(cols_ * row), other.data(), sz); mat._copyRaw(mat.data(cols_ * row), other.data(), sz);
return *this; return *this;
} }
inline PIVector2D<T> & setRow(size_t row, const RowConst & other) { inline PIVector2D<T> & setRow(size_t row, const RowConst & other) {
const size_t sz = piMin<size_t>(cols_, other.sz_); size_t sz = piMin<size_t>(cols_, other.sz_);
mat._copyRaw(mat.data(cols_ * row), other.data(), sz); mat._copyRaw(mat.data(cols_ * row), other.data(), sz);
return *this; return *this;
} }
inline PIVector2D<T> & setRow(size_t row, const PIVector<T> & other) { inline PIVector2D<T> & setRow(size_t row, const PIVector<T> & other) {
const size_t sz = piMin<size_t>(cols_, other.size()); size_t sz = piMin<size_t>(cols_, other.size());
mat._copyRaw(mat.data(cols_ * row), other.data(), sz); mat._copyRaw(mat.data(cols_ * row), other.data(), sz);
return *this; return *this;
} }
inline PIVector2D<T> & addRow(const Row & other) { inline PIVector2D<T> & addRow(const Row & other) {
if (cols_ == 0) cols_ = other.sz_; if (cols_ == 0) cols_ = other.sz_;
const size_t sz = piMin<size_t>(cols_, other.sz_); size_t sz = piMin<size_t>(cols_, other.sz_);
const size_t ps = mat.size(); size_t ps = mat.size();
mat.resize(mat.size() + cols_); mat.resize(mat.size() + cols_);
mat._copyRaw(mat.data(ps), other.data(), sz); mat._copyRaw(mat.data(ps), other.data(), sz);
rows_++; rows_++;
@@ -231,8 +197,8 @@ public:
} }
inline PIVector2D<T> & addRow(const RowConst & other) { inline PIVector2D<T> & addRow(const RowConst & other) {
if (cols_ == 0) cols_ = other.sz_; if (cols_ == 0) cols_ = other.sz_;
const size_t sz = piMin<size_t>(cols_, other.sz_); size_t sz = piMin<size_t>(cols_, other.sz_);
const size_t ps = mat.size(); size_t ps = mat.size();
mat.resize(mat.size() + cols_); mat.resize(mat.size() + cols_);
mat._copyRaw(mat.data(ps), other.data(), sz); mat._copyRaw(mat.data(ps), other.data(), sz);
rows_++; rows_++;
@@ -240,8 +206,8 @@ public:
} }
inline PIVector2D<T> & addRow(const PIVector<T> & other) { inline PIVector2D<T> & addRow(const PIVector<T> & other) {
if (cols_ == 0) cols_ = other.size(); if (cols_ == 0) cols_ = other.size();
const size_t sz = piMin<size_t>(cols_, other.size()); size_t sz = piMin<size_t>(cols_, other.size());
const size_t ps = mat.size(); size_t ps = mat.size();
mat.resize(mat.size() + cols_); mat.resize(mat.size() + cols_);
mat._copyRaw(mat.data(ps), other.data(), sz); mat._copyRaw(mat.data(ps), other.data(), sz);
rows_++; rows_++;
@@ -251,7 +217,7 @@ public:
inline PIVector2D<T> & resize(size_t rows, size_t cols, const T & f = T()) { inline PIVector2D<T> & resize(size_t rows, size_t cols, const T & f = T()) {
mat.resize(rows*cols_, f); mat.resize(rows*cols_, f);
rows_ = rows; rows_ = rows;
const int cs = (cols - cols_); int cs = (cols - cols_);
if (cs < 0) { if (cs < 0) {
for (size_t r=0; r<rows; ++r) { for (size_t r=0; r<rows; ++r) {
mat.remove(r*cols + cols, -cs); mat.remove(r*cols + cols, -cs);
@@ -271,24 +237,22 @@ public:
} }
inline bool operator ==(const PIVector2D<T> & t) const { inline bool operator ==(const PIVector2D<T> & t) const {
if (cols_ != t.cols_ || rows_ != t.rows_) return false; if (cols_ != t.cols_ || rows_ != t.rows_)
return false;
return mat == t.mat; return mat == t.mat;
} }
inline bool operator !=(const PIVector2D<T> & t) const {return !(*this == t);} inline bool operator !=(const PIVector2D<T> & t) const {return !(*this == t);}
inline PIVector<PIVector<T>> toVectors() const { PIVector<PIVector<T> > toVectors() const {
PIVector<PIVector<T> > ret; PIVector<PIVector<T> > ret;
ret.reserve(rows_); ret.reserve(rows_);
for(size_t i = 0; i < rows_; ++i) for(size_t i = 0; i < rows_; ++i)
ret << PIVector<T>(mat.data(i*cols_), cols_); ret << PIVector<T>(mat.data(i*cols_), cols_);
return ret; return ret;
} }
PIVector<T> toPlainVector() const {return mat;}
inline PIVector<T> toPlainVector() const { return mat; } PIVector<T> & plainVector() {return mat;}
const PIVector<T> & plainVector() const {return mat;}
inline PIVector<T> & plainVector() { return mat; }
inline const PIVector<T> & plainVector() const { return mat; }
inline void swap(PIVector2D<T> & other) { inline void swap(PIVector2D<T> & other) {
mat.swap(other.mat); mat.swap(other.mat);
@@ -296,7 +260,9 @@ public:
piSwap<size_t>(cols_, other.cols_); piSwap<size_t>(cols_, other.cols_);
} }
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0> template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector2D<T> & _resizeRaw(size_t r, size_t c) { inline PIVector2D<T> & _resizeRaw(size_t r, size_t c) {
rows_ = r; rows_ = r;
cols_ = c; cols_ = c;
@@ -309,14 +275,11 @@ public:
mat.clear(); mat.clear();
} }
template<typename ST> void forEach(std::function<void(const T &)> f) const {
inline PIVector2D<ST> map(std::function<ST(const T & e)> f) const { mat.forEach(f);
return PIVector2D<ST>(rows_, cols_, mat.map(f));
} }
inline void forEach(std::function<void(const T &)> f) const { mat.forEach(f); } PIVector2D<T> & forEach(std::function<void(T &)> f) {
inline PIVector2D<T> & forEach(std::function<void(T &)> f) {
mat.forEach(f); mat.forEach(f);
return *this; return *this;
} }
@@ -329,7 +292,7 @@ protected:
template<typename T> template<typename T>
inline PICout operator <<(PICout s, const PIVector2D<T> & v) { inline PICout operator <<(PICout s, const PIVector2D<T> & v) {
s.saveAndSetControls(0); s.setControl(0, true);
s << "{"; s << "{";
for (size_t i = 0; i < v.rows(); ++i) { for (size_t i = 0; i < v.rows(); ++i) {
s << "{ "; s << "{ ";
@@ -342,7 +305,7 @@ inline PICout operator<<(PICout s, const PIVector2D<T> & v) {
} }
if (v.isEmpty()) s << "{ }"; if (v.isEmpty()) s << "{ }";
s << "}"; s << "}";
s.restoreControls(); s.restoreControl();
return s; return s;
} }

View File

@@ -34,20 +34,370 @@
#ifndef PIBASE_H #ifndef PIBASE_H
#define PIBASE_H #define PIBASE_H
#include "pibase_macros.h" #include "pip_version.h"
#include "piplatform.h"
#include "pip_export.h" #include "pip_export.h"
#include "pip_defs.h"
#include <string.h> #include <string.h>
//! \~english
//! Meta-information section for any entity.
//! Parsing by \a pip_cmg and can be accessed by \a PICodeInfo.
//! Contains sequence of key=value pairs, e.g.
//! \~russian
//! Секция метаинформации для любой сущности.
//! Парсится \a pip_cmg и доступна с помощью \a PICodeInfo.
//! Содержит набор пар ключ=значение, например
//! \~
//! PIMETA(id=12345,tag="my string")
#define PIMETA(...)
#ifdef DOXYGEN
//! \~\brief
//! \~english Major value of PIP version
//! \~russian Мажорная версия PIP
# define PIP_VERSION_MAJOR
//! \~\brief
//! \~english Minor value of PIP version
//! \~russian Минорная версия PIP
# define PIP_VERSION_MINOR
//! \~\brief
//! \~english Revision value of PIP version
//! \~russian Ревизия версии PIP
# define PIP_VERSION_REVISION
//! \~\brief
//! \~english Suffix of PIP version
//! \~russian Суффикс версии PIP
# define PIP_VERSION_SUFFIX
//! \~\brief
//! \~english Version of PIP in hex - 0x##(Major)##(Minor)##(Revision)
//! \~russian Версия PIP в hex - 0x##(Major)##(Minor)##(Revision)
# define PIP_VERSION
//! \~\brief
//! \~english Macro is defined when compile-time debug is enabled
//! \~russian Макрос объявлен когда включена compile-time отладка
# define PIP_DEBUG
//! \~\brief
//! \~english Macro is defined when operation system is any Windows
//! \~russian Макрос объявлен когда операционная система Windows
# define WINDOWS
//! \~\brief
//! \~english Macro is defined when operation system is QNX or Blackberry
//! \~russian Макрос объявлен когда операционная система QNX или Blackberry
# define QNX
//! \~\brief
//! \~english Macro is defined when operation system is Blackberry
//! \~russian Макрос объявлен когда операционная система Blackberry
# define BLACKBERRY
//! \~\brief
//! \~english Macro is defined when operation system is FreeBSD
//! \~russian Макрос объявлен когда операционная система FreeBSD
# define FREE_BSD
//! \~\brief
//! \~english Macro is defined when operation system is Mac OS
//! \~russian Макрос объявлен когда операционная система Mac OS
# define MAC_OS
//! \~\brief
//! \~english Macro is defined when operation system is Android
//! \~russian Макрос объявлен когда операционная система Android
# define ANDROID
//! \~\brief
//! \~english Macro is defined when operation system is any Linux
//! \~russian Макрос объявлен когда операционная система Linux
# define LINUX
//! \~\brief
//! \~english Macro is defined when operation system is FreeRTOS
//! \~russian Макрос объявлен когда операционная система FreeRTOS
# define FREERTOS
//! \~\brief
//! \~english Macro is defined when compiler is GCC or MinGW
//! \~russian Макрос объявлен когда компилятор GCC или MinGW
# define CC_GCC
//! \~\brief
//! \~english Macro is defined when PIP is decided that host is support language
//! \~russian Макрос объявлен когда PIP решил что система поддерживает локализацию
# define HAS_LOCALE
//! \~\brief
//! \~english Macro is defined when PIP is building for embedded systems
//! \~russian Макрос объявлен когда PIP собирается для встраиваемых систем
# define MICRO_PIP
//! \~\brief
//! \~english Macro is defined when compiler is Visual Studio
//! \~russian Макрос объявлен когда компилятор Visual Studio
# define CC_VC
//! \~\brief
//! \~english Macro is defined when compiler is AVR GCC
//! \~russian Макрос объявлен когда компилятор AVR GCC
# define CC_AVR_GCC
//! \~\brief
//! \~english Macro is defined when compiler is unknown
//! \~russian Макрос объявлен когда компилятор неизвестен
# define CC_OTHER
//! \~\brief
//! \~english Macro is defined when PIP can use "rt" library for \a PITimer::ThreadRT timers implementation
//! \~russian Макрос объявлен когда PIP может использовать библиотеку "rt" для \a PITimer::ThreadRT реализации таймера
# define PIP_TIMER_RT
//! \~\brief
//! \~english Macro to declare private section, "export" is optional
//! \~russian Макрос для объявления частной секции, "export" необязателен
# define PRIVATE_DECLARATION(export)
//! \~\brief
//! \~english Macro to start definition of private section
//! \~russian Макрос для начала реализации частной секции
# define PRIVATE_DEFINITION_START(Class)
//! \~\brief
//! \~english Macro to end definition of private section
//! \~russian Макрос для окончания реализации частной секции
# define PRIVATE_DEFINITION_END(Class)
//! \~\brief
//! \~english Macro to access private section by pointer
//! \~russian Макрос для доступа к частной секции
# define PRIVATE
//! \~\brief
//! \~english Macro to access private section by pointer without brakes ()
//! \~russian Макрос для доступа к частной секции без обрамляющих скобок ()
# define PRIVATEWB
//! \~\brief
//! \~english Macro to start static initializer
//! \~russian Макрос для начала статической инициализации
# define STATIC_INITIALIZER_BEGIN
//! \~\brief
//! \~english Macro to end static initializer
//! \~russian Макрос для окончания статической инициализации
# define STATIC_INITIALIZER_END
#undef MICRO_PIP
#undef FREERTOS
#endif //DOXYGEN
#ifdef CC_AVR_GCC #ifdef CC_AVR_GCC
# include <ArduinoSTL.h> # include <ArduinoSTL.h>
#endif #endif
#include <atomic>
#include <cassert>
#include <cstddef>
#include <functional> #include <functional>
#include <initializer_list> #include <cstddef>
#include <cassert>
#include <limits> #include <limits>
#include <atomic>
#ifdef WINDOWS
# ifdef CC_VC
# define SHUT_RDWR 2
# pragma comment(lib, "Ws2_32.lib")
# pragma comment(lib, "Iphlpapi.lib")
# pragma comment(lib, "Psapi.lib")
# ifdef ARCH_BITS_32
# define _X86_
# else
# define _IA64_
# endif
# else
# define SHUT_RDWR SD_BOTH
# endif
typedef int socklen_t;
extern long long __pi_perf_freq;
#endif
#ifndef DOXYGEN
#ifdef ANDROID
///# define tcdrain(fd) ioctl(fd, TCSBRK, 1)
//inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
//inline int mbtowc(wchar_t * w, const char * c, size_t) {*w = ((wchar_t * )&c)[0]; return 1;}
#endif
#ifdef MAC_OS
# define environ (*_NSGetEnviron())
typedef long time_t;
#endif
#ifdef LINUX
# define environ __environ
#endif
#ifdef FREE_BSD
extern char ** environ;
#endif
#ifndef NO_UNUSED
# define NO_UNUSED(x) (void)x
#endif
#ifndef assert
# define assert(x)
# define assertm(exp, msg)
#else
# define assertm(exp, msg) assert(((void)msg, exp))
#endif
#ifdef MICRO_PIP
# define __PIP_TYPENAME__(T) "?"
#else
# define __PIP_TYPENAME__(T) typeid(T).name()
#endif
#ifdef CC_GCC
# undef DEPRECATED
# define DEPRECATED __attribute__((deprecated))
# if CC_GCC_VERSION > 0x025F // > 2.95
# ifdef LINUX
# define HAS_LOCALE
# endif
# ifdef MAC_OS
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
# pragma GCC diagnostic ignored "-Wc++11-extensions"
# endif
# endif
# ifdef ANDROID
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic ignored "-Wextra"
# pragma GCC diagnostic ignored "-Wc++11-extensions"
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
//# pragma GCC diagnostic ignored "-Wliteral-suffix"
# endif
#endif
#ifdef CC_VC
# undef DEPRECATED
# define DEPRECATED
# pragma warning(disable: 4018)
# pragma warning(disable: 4061)
# pragma warning(disable: 4100)
# pragma warning(disable: 4239)
# pragma warning(disable: 4242)
# pragma warning(disable: 4244)
# pragma warning(disable: 4251)
# pragma warning(disable: 4365)
# pragma warning(disable: 4512)
# pragma warning(disable: 4668)
# pragma warning(disable: 4710)
# pragma warning(disable: 4800)
# pragma warning(disable: 4820)
# pragma warning(disable: 4986)
# pragma warning(disable: 4996)
# ifdef ARCH_BITS_32
typedef long ssize_t;
# else
typedef long long ssize_t;
# endif
#endif
#ifdef CC_OTHER
# undef DEPRECATED
# define DEPRECATED
#endif
#endif //DOXYGEN
// Private data macros
#ifndef DOXYGEN
#define PRIVATE_DECLARATION(e) \
struct __Private__; \
friend struct __Private__; \
struct e __PrivateInitializer__ { \
__PrivateInitializer__(); \
__PrivateInitializer__(const __PrivateInitializer__ & o); \
~__PrivateInitializer__(); \
__PrivateInitializer__ & operator =(const __PrivateInitializer__ & o); \
__Private__ * p; \
}; \
__PrivateInitializer__ __privateinitializer__;
#define PRIVATE_DEFINITION_START(c) \
struct c::__Private__ {
#define PRIVATE_DEFINITION_END(c) \
}; \
c::__PrivateInitializer__::__PrivateInitializer__() {p = new c::__Private__();} \
c::__PrivateInitializer__::__PrivateInitializer__(const c::__PrivateInitializer__ & ) {/*if (p) delete p;*/ p = new c::__Private__();} \
c::__PrivateInitializer__::~__PrivateInitializer__() {delete p; p = 0;} \
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator =(const c::__PrivateInitializer__ & ) {if (p) delete p; p = new c::__Private__(); return *this;}
#define PRIVATE (__privateinitializer__.p)
#define PRIVATEWB __privateinitializer__.p
#endif //DOXYGEN
#define NO_COPY_CLASS(name) \
name(const name&) = delete; \
name& operator=(const name&) = delete;
#define _PIP_ADD_COUNTER_WS(a, cnt) a##cnt
#define _PIP_ADD_COUNTER_WF(a, cnt) _PIP_ADD_COUNTER_WS(a, cnt)
#define _PIP_ADD_COUNTER(a) _PIP_ADD_COUNTER_WF(a, __COUNTER__)
#define STATIC_INITIALIZER_BEGIN \
class { \
class _Initializer_ { \
public: \
_Initializer_() {
#define STATIC_INITIALIZER_END \
} \
} _initializer_; \
} _PIP_ADD_COUNTER(_pip_initializer_);
//! \~\brief
//! \~english Minimal sleep in milliseconds for internal PIP using
//! \~russian Минимальное значание задержки в милисекундах для внутреннего использования в библиотеке PIP
//! \~\details
//! \~english Using in \a piMinSleep(), \a PIThread, \a PITimer::Pool. By default 1ms.
//! \~russian Используется в \a piMinSleep(), \a PIThread, \a PITimer::Pool. По умолчанию равна 1мс.
#ifndef PIP_MIN_MSLEEP
# ifndef MICRO_PIP
# define PIP_MIN_MSLEEP 1.
# else
# define PIP_MIN_MSLEEP 10.
# endif
#endif
//! \~\brief
//! \~english Macro used for infinite loop
//! \~russian Макрос для бесконечного цикла
#define FOREVER for (;;)
//! \~\brief
//! \~english Macro used for infinite wait
//! \~russian Макрос для бесконечного ожидания
#define FOREVER_WAIT FOREVER piMinSleep();
//! \~\brief
//! \~english Macro used for infinite wait
//! \~russian Макрос для бесконечного ожидания
#define WAIT_FOREVER FOREVER piMinSleep();
//! \~\brief //! \~\brief
//! \~english Global variable enabling output to piCout, default is true //! \~english Global variable enabling output to piCout, default is true
@@ -75,12 +425,7 @@ typedef long double ldouble;
//! \~\details //! \~\details
//! \~english Example:\n \snippet piincludes.cpp swap //! \~english Example:\n \snippet piincludes.cpp swap
//! \~russian Пример:\n \snippet piincludes.cpp swap //! \~russian Пример:\n \snippet piincludes.cpp swap
template<typename T> template<typename T> inline void piSwap(T & f, T & s) {T t(std::move(f)); f = std::move(s); s = std::move(t);}
inline void piSwap(T & f, T & s) {
T t(std::move(f));
f = std::move(s);
s = std::move(t);
}
//! \~\brief //! \~\brief
//! \~english Templated function for swap two values without "=" //! \~english Templated function for swap two values without "="
@@ -88,8 +433,7 @@ inline void piSwap(T & f, T & s) {
//! \~\details //! \~\details
//! \~english Example:\n \snippet piincludes.cpp swapBinary //! \~english Example:\n \snippet piincludes.cpp swapBinary
//! \~russian Пример:\n \snippet piincludes.cpp swapBinary //! \~russian Пример:\n \snippet piincludes.cpp swapBinary
template<typename T> template<typename T> inline void piSwapBinary(T & f, T & s) {
inline void piSwapBinary(T & f, T & s) {
if ((size_t*)&f == (size_t*)&s) return; if ((size_t*)&f == (size_t*)&s) return;
size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T); size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T);
size_t i = 0; size_t i = 0;
@@ -105,8 +449,7 @@ inline void piSwapBinary(T & f, T & s) {
} }
} }
template<> template<> inline void piSwapBinary(const void *& f, const void *& s) {
inline void piSwapBinary(const void *& f, const void *& s) {
if ((size_t*)f == (size_t*)s) return; if ((size_t*)f == (size_t*)s) return;
size_t j = (sizeof(void *) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(void *); size_t j = (sizeof(void *) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(void *);
size_t i = 0; size_t i = 0;
@@ -132,7 +475,8 @@ inline void piSwapBinary(const void *& f, const void *& s) {
//! \~russian Пример:\n \snippet piincludes.cpp compareBinary //! \~russian Пример:\n \snippet piincludes.cpp compareBinary
inline bool piCompareBinary(const void * f, const void * s, size_t size) { inline bool piCompareBinary(const void * f, const void * s, size_t size) {
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i)
if (((const uchar *)f)[i] != ((const uchar *)s)[i]) return false; if (((const uchar*)f)[i] != ((const uchar*)s)[i])
return false;
return true; return true;
} }
@@ -156,10 +500,7 @@ inline bool piCompareBinary(const void * f, const void * s, size_t size) {
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp round //! \snippet piincludes.cpp round
template<typename T> template<typename T> inline constexpr int piRound(const T & v) {return int(v >= T(0.) ? v + T(0.5) : v - T(0.5));}
inline constexpr int piRound(const T & v) {
return int(v >= T(0.) ? v + T(0.5) : v - T(0.5));
}
//! \~\brief //! \~\brief
//! \~english Templated function return floor of float falue //! \~english Templated function return floor of float falue
@@ -181,10 +522,7 @@ inline constexpr int piRound(const T & v) {
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp floor //! \snippet piincludes.cpp floor
template<typename T> template<typename T> inline constexpr int piFloor(const T & v) {return v < T(0) ? int(v) - 1 : int(v);}
inline constexpr int piFloor(const T & v) {
return v < T(0) ? int(v) - 1 : int(v);
}
//! \~\brief //! \~\brief
//! \~english Templated function return ceil of float falue //! \~english Templated function return ceil of float falue
@@ -206,10 +544,7 @@ inline constexpr int piFloor(const T & v) {
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp ceil //! \snippet piincludes.cpp ceil
template<typename T> template<typename T> inline constexpr int piCeil(const T & v) {return v < T(0) ? int(v) : int(v) + 1;}
inline constexpr int piCeil(const T & v) {
return v < T(0) ? int(v) : int(v) + 1;
}
//! \~\brief //! \~\brief
//! \~english Templated function return absolute of numeric falue //! \~english Templated function return absolute of numeric falue
@@ -239,20 +574,11 @@ inline constexpr int piCeil(const T & v) {
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp abs //! \snippet piincludes.cpp abs
template<typename T> template<typename T> inline constexpr T piAbs(const T & v) {return (v >= T(0) ? v : -v);}
inline constexpr T piAbs(const T & v) {
return (v >= T(0) ? v : -v);
}
template<typename T>
constexpr T piMin(const T & f, const T & s) {
return ((f > s) ? s : f);
}
//! \~\brief //! \~\brief
//! \~english Templated function return minimum of several values //! \~english Templated function return minimum of two values
//! \~russian Шаблонный метод, возвращающий минимум из нескольких значений //! \~russian Шаблонный метод, возвращающий минимум из двух значений
//! \~\details //! \~\details
//! \~english //! \~english
//! There are some macros: //! There are some macros:
@@ -276,20 +602,39 @@ constexpr T piMin(const T & f, const T & s) {
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp min2 //! \snippet piincludes.cpp min2
template<typename T, typename... Args> template<typename T> inline constexpr T piMin(const T & f, const T & s) {return ((f > s) ? s : f);}
constexpr T piMin(const T & f, const T & s, const Args &... args) {
return piMin<T>(piMin<T>(f, s), args...);
}
template<typename T>
constexpr T piMax(const T & f, const T & s) {
return ((f < s) ? s : f);
}
//! \~\brief //! \~\brief
//! \~english Templated function return maximum of several values //! \~english Templated function return minimum of tree values
//! \~russian Шаблонный метод, возвращающий максимум из нескольких значений //! \~russian Шаблонный метод, возвращающий минимум из трех значений
//! \~\details
//! \~english
//! There are some macros:
//! - \c piMins for "short"
//! - \c piMini for "int"
//! - \c piMinl for "long"
//! - \c piMinll for "llong"
//! - \c piMinf for "float"
//! - \c piMind for "double"
//!
//! Example:
//! \snippet piincludes.cpp min3
//! \~russian
//! Есть несколько макросов:
//! - \c piMins для "short"
//! - \c piMini для "int"
//! - \c piMinl для "long"
//! - \c piMinll для "llong"
//! - \c piMinf для "float"
//! - \c piMind для "double"
//!
//! Пример:
//! \snippet piincludes.cpp min3
template<typename T> inline constexpr T piMin(const T & f, const T & s, const T & t) {return ((f < s && f < t) ? f : ((s < t) ? s : t));}
//! \~\brief
//! \~english Templated function return maximum of two values
//! \~russian Шаблонный метод, возвращающий максимум из двух значений
//! \~\details //! \~\details
//! \~english //! \~english
//! There are some macros: //! There are some macros:
@@ -313,11 +658,35 @@ constexpr T piMax(const T & f, const T & s) {
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp max2 //! \snippet piincludes.cpp max2
template<typename T, typename... Args> template<typename T> inline constexpr T piMax(const T & f, const T & s) {return ((f < s) ? s : f);}
constexpr T piMax(const T & f, const T & s, const Args &... args) {
return piMax<T>(piMax<T>(f, s), args...);
}
//! \~\brief
//! \~english Templated function return maximum of tree values
//! \~russian Шаблонный метод, возвращающий максимум из трех значений
//! \~\details
//! \~english
//! There are some macros:
//! - \c piMaxs for "short"
//! - \c piMaxi for "int"
//! - \c piMaxl for "long"
//! - \c piMaxll for "llong"
//! - \c piMaxf for "float"
//! - \c piMaxd for "double"
//!
//! Example:
//! \snippet piincludes.cpp max3
//! \~russian
//! Есть несколько макросов:
//! - \c piMaxs для "short"
//! - \c piMaxi для "int"
//! - \c piMaxl для "long"
//! - \c piMaxll для "llong"
//! - \c piMaxf для "float"
//! - \c piMaxd для "double"
//!
//! Пример:
//! \snippet piincludes.cpp max3
template<typename T> inline constexpr T piMax(const T & f, const T & s, const T & t) {return ((f > s && f > t) ? f : ((s > t) ? s : t));}
//! \~\brief //! \~\brief
//! \~english Templated function return clamped value //! \~english Templated function return clamped value
@@ -347,10 +716,7 @@ constexpr T piMax(const T & f, const T & s, const Args &... args) {
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp clamp //! \snippet piincludes.cpp clamp
template<typename T> template<typename T> inline constexpr T piClamp(const T & v, const T & min, const T & max) {return (v > max ? max : (v < min ? min : v));}
inline constexpr T piClamp(const T & v, const T & min, const T & max) {
return (v > max ? max : (v < min ? min : v));
}
//! \~\brief //! \~\brief
//! \~english Function inverse byte order in memory block ([1..N] -> [N..1]) //! \~english Function inverse byte order in memory block ([1..N] -> [N..1])
@@ -386,10 +752,7 @@ inline bool piCompare(const T & a, const T & b, const T & epsilon = std::numeric
//! \~\brief //! \~\brief
//! \~english Templated function that inverse byte order of value "v" //! \~english Templated function that inverse byte order of value "v"
//! \~russian Шаблонный метод, меняющий порядок байт в переменной "v" //! \~russian Шаблонный метод, меняющий порядок байт в переменной "v"
template<typename T> template<typename T> inline void piLetobe(T * v) {piLetobe(v, sizeof(T));}
inline void piLetobe(T * v) {
piLetobe(v, sizeof(T));
}
//! \~\brief //! \~\brief
//! \~english Templated function that returns "v" with inversed byte order //! \~english Templated function that returns "v" with inversed byte order
@@ -415,24 +778,12 @@ inline void piLetobe(T * v) {
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp letobe //! \snippet piincludes.cpp letobe
template<typename T> template<typename T> inline T piLetobe(const T & v) {T tv(v); piLetobe(&tv, sizeof(T)); return tv;}
inline T piLetobe(const T & v) {
T tv(v);
piLetobe(&tv, sizeof(T));
return tv;
}
// specialization // specialization
template<> template<> inline uint16_t piLetobe(const uint16_t & v) {return (v << 8) | (v >> 8);}
inline uint16_t piLetobe(const uint16_t & v) { template<> inline uint32_t piLetobe(const uint32_t & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
return (v << 8) | (v >> 8); template<> inline float piLetobe(const float & v) {
}
template<>
inline uint32_t piLetobe(const uint32_t & v) {
return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);
}
template<>
inline float piLetobe(const float & v) {
union _pletobe_f { union _pletobe_f {
_pletobe_f(const float &f_) {f = f_;} _pletobe_f(const float &f_) {f = f_;}
float f; float f;
@@ -485,98 +836,21 @@ inline uint piHashData(const uchar * data, uint len, uint seed = 0) {
} }
template<typename T> template<typename T> inline uint piHash(const T & v) {
inline uint piHash(const T & v) {
return 0; return 0;
} }
template<> template<> inline uint piHash(const char & v) {return (uint)v;}
inline uint piHash(const char & v) { template<> inline uint piHash(const uchar & v) {return (uint)v;}
return (uint)v; template<> inline uint piHash(const short & v) {return (uint)v;}
} template<> inline uint piHash(const ushort & v) {return (uint)v;}
template<> template<> inline uint piHash(const int & v) {return (uint)v;}
inline uint piHash(const uchar & v) { template<> inline uint piHash(const uint & v) {return (uint)v;}
return (uint)v; template<> inline uint piHash(const llong & v) {return piHashData((const uchar *)&v, sizeof(v));}
} template<> inline uint piHash(const ullong & v) {return piHashData((const uchar *)&v, sizeof(v));}
template<> template<> inline uint piHash(const float & v) {return (uint)v;}
inline uint piHash(const short & v) { template<> inline uint piHash(const double & v) {return piHashData((const uchar *)&v, sizeof(v));}
return (uint)v; template<> inline uint piHash(const ldouble & v) {return piHashData((const uchar *)&v, sizeof(v));}
}
template<>
inline uint piHash(const ushort & v) {
return (uint)v;
}
template<>
inline uint piHash(const int & v) {
return (uint)v;
}
template<>
inline uint piHash(const uint & v) {
return (uint)v;
}
template<>
inline uint piHash(const llong & v) {
return piHashData((const uchar *)&v, sizeof(v));
}
template<>
inline uint piHash(const ullong & v) {
return piHashData((const uchar *)&v, sizeof(v));
}
template<>
inline uint piHash(const float & v) {
return (uint)v;
}
template<>
inline uint piHash(const double & v) {
return piHashData((const uchar *)&v, sizeof(v));
}
template<>
inline uint piHash(const ldouble & v) {
return piHashData((const uchar *)&v, sizeof(v));
}
//! \~\brief
//! \~english Call \b delete on each "container" element.
//! \~russian Вызывает \b delete на каждый элемент "container".
template<typename T>
inline void piDeleteAll(const T & container) {
for (auto i: container) {
delete i;
}
}
//! \~\brief
//! \~english Call \b delete on each element of
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Вызывает \b delete на каждый элемент
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
template<typename T>
inline void piDeleteAll(std::initializer_list<T> container) {
for (auto i: container) {
delete i;
}
}
//! \~\brief
//! \~english Call \b delete on each "container" element and clear container.
//! \~russian Вызывает \b delete на каждый элемент "container" и очищает контейнер.
template<typename T>
inline void piDeleteAllAndClear(T & container) {
piDeleteAll(container);
container.clear();
}
//! \~\brief
//! \~english Call \b delete if "pointer" is not null and set it to null. Returns if deleted.
//! \~russian Вызывает \b delete на "pointer" если он не нулевой и устанавливает его в ноль. Возвращает было ли удаление.
template<typename T>
inline bool piDeleteSafety(T *& pointer) {
if (!pointer) return false;
delete pointer;
pointer = nullptr;
return true;
}
#define piRoundf piRound<float> #define piRoundf piRound<float>
#define piRoundd piRound<double> #define piRoundd piRound<double>
@@ -617,55 +891,4 @@ inline bool piDeleteSafety(T *& pointer) {
#define piLetobef piLetobe<float> #define piLetobef piLetobe<float>
//! \~\brief
//! \~english Class for executing a function upon scope exit
//! \~russian Класс для выполнения функции при выходе из области видимости
//! \~\details
//! \~english Example
//! \~russian Пример
//! \~\code
//! bool yourFunc() {
//! PIScopeExitCall error_call([]() { piCout << "Error!"; });
//! ...
//! if (!good0) {
//! ...
//! return false;
//! }
//! if (!good1) {
//! ...
//! return false;
//! }
//! ...
//! error_call.cancel();
//! return true;
//! }
//! \endcode
//! \~english In this example "Error!" will be printed on every \b false function return.
//! \~russian В данном примере будет выведен "Error!" при каждом \b false возврате из функции.
class PIP_EXPORT PIScopeExitCall {
public:
//! \~\brief
//! \~english Constructor that takes a function to execute
//! \~russian Конструктор, который принимает функцию для выполнения
explicit PIScopeExitCall(std::function<void()> f): func(f) {}
//! \~\brief
//! \~english Destructor that executes the function if it exists
//! \~russian Деструктор, который выполняет функцию, если она существует
~PIScopeExitCall() {
if (func) func();
}
//! \~\brief
//! \~english Method for canceling the function
//! \~russian Метод для отмены функции
void cancel() { func = nullptr; }
private:
NO_COPY_CLASS(PIScopeExitCall)
std::function<void()> func;
};
#endif // PIBASE_H #endif // PIBASE_H

View File

@@ -1,419 +0,0 @@
/*! \file pibase_macros.h
* \ingroup Core
* \~\brief
* \~english Base macros
* \~russian Базовые макросы
*
* \~\details
* \~english
* This file declares basic useful maros
* \~russian
* Этот файл объявляет основные вспомогательные макросы
*/
/*
PIP - Platform Independent Primitives
Base macros
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 PIBASE_MACROS_H
#define PIBASE_MACROS_H
#include "pip_defs.h"
#include "pip_version.h"
#include "piplatform.h"
//! \~english
//! Meta-information section for any entity.
//! Parsing by \a pip_cmg and can be accessed by \a PICodeInfo.
//! Contains sequence of key=value pairs, e.g.
//! \~russian
//! Секция метаинформации для любой сущности.
//! Парсится \a pip_cmg и доступна с помощью \a PICodeInfo.
//! Содержит набор пар ключ=значение, например
//! \~
//! PIMETA(id=12345,tag="my string")
#define PIMETA(...)
#ifdef DOXYGEN
//! \~\brief
//! \~english Major value of PIP version
//! \~russian Мажорная версия PIP
# define PIP_VERSION_MAJOR
//! \~\brief
//! \~english Minor value of PIP version
//! \~russian Минорная версия PIP
# define PIP_VERSION_MINOR
//! \~\brief
//! \~english Revision value of PIP version
//! \~russian Ревизия версии PIP
# define PIP_VERSION_REVISION
//! \~\brief
//! \~english Suffix of PIP version
//! \~russian Суффикс версии PIP
# define PIP_VERSION_SUFFIX
//! \~\brief
//! \~english Version of PIP in hex - 0x##(Major)##(Minor)##(Revision)
//! \~russian Версия PIP в hex - 0x##(Major)##(Minor)##(Revision)
# define PIP_VERSION
//! \~\brief
//! \~english Macro is defined when compile-time debug is enabled
//! \~russian Макрос объявлен когда включена compile-time отладка
# define PIP_DEBUG
//! \~\brief
//! \~english Macro is defined when operation system is any Windows
//! \~russian Макрос объявлен когда операционная система Windows
# define WINDOWS
//! \~\brief
//! \~english Macro is defined when operation system is QNX or Blackberry
//! \~russian Макрос объявлен когда операционная система QNX или Blackberry
# define QNX
//! \~\brief
//! \~english Macro is defined when operation system is Blackberry
//! \~russian Макрос объявлен когда операционная система Blackberry
# define BLACKBERRY
//! \~\brief
//! \~english Macro is defined when operation system is FreeBSD
//! \~russian Макрос объявлен когда операционная система FreeBSD
# define FREE_BSD
//! \~\brief
//! \~english Macro is defined when operation system is Mac OS
//! \~russian Макрос объявлен когда операционная система Mac OS
# define MAC_OS
//! \~\brief
//! \~english Macro is defined when operation system is Android
//! \~russian Макрос объявлен когда операционная система Android
# define ANDROID
//! \~\brief
//! \~english Macro is defined when operation system is any Linux
//! \~russian Макрос объявлен когда операционная система Linux
# define LINUX
//! \~\brief
//! \~english Macro is defined when operation system is FreeRTOS
//! \~russian Макрос объявлен когда операционная система FreeRTOS
# define FREERTOS
//! \~\brief
//! \~english Macro is defined when compiler is GCC or MinGW
//! \~russian Макрос объявлен когда компилятор GCC или MinGW
# define CC_GCC
//! \~\brief
//! \~english Macro is defined when PIP is decided that host is support language
//! \~russian Макрос объявлен когда PIP решил что система поддерживает локализацию
# define HAS_LOCALE
//! \~\brief
//! \~english Macro is defined when PIP is building for embedded systems
//! \~russian Макрос объявлен когда PIP собирается для встраиваемых систем
# define MICRO_PIP
//! \~\brief
//! \~english Macro is defined when compiler is Visual Studio
//! \~russian Макрос объявлен когда компилятор Visual Studio
# define CC_VC
//! \~\brief
//! \~english Macro is defined when compiler is AVR GCC
//! \~russian Макрос объявлен когда компилятор AVR GCC
# define CC_AVR_GCC
//! \~\brief
//! \~english Macro is defined when compiler is unknown
//! \~russian Макрос объявлен когда компилятор неизвестен
# define CC_OTHER
//! \~\brief
//! \~english Macro is defined when PIP can use "rt" library for \a PITimer::ThreadRT timers implementation
//! \~russian Макрос объявлен когда PIP может использовать библиотеку "rt" для \a PITimer::ThreadRT реализации таймера
# define PIP_TIMER_RT
//! \~\brief
//! \~english Macro to declare private section, "export" is optional
//! \~russian Макрос для объявления частной секции, "export" необязателен
# define PRIVATE_DECLARATION(export)
//! \~\brief
//! \~english Macro to start definition of private section
//! \~russian Макрос для начала реализации частной секции
# define PRIVATE_DEFINITION_START(Class)
//! \~\brief
//! \~english Macro to end definition of private section
//! \~russian Макрос для окончания реализации частной секции
# define PRIVATE_DEFINITION_END(Class)
//! \~\brief
//! \~english Macro to access private section by pointer
//! \~russian Макрос для доступа к частной секции
# define PRIVATE
//! \~\brief
//! \~english Macro to access private section by pointer without brakes ()
//! \~russian Макрос для доступа к частной секции без обрамляющих скобок ()
# define PRIVATEWB
//! \~\brief
//! \~english Macro to start static initializer
//! \~russian Макрос для начала статической инициализации
# define STATIC_INITIALIZER_BEGIN
//! \~\brief
//! \~english Macro to end static initializer
//! \~russian Макрос для окончания статической инициализации
# define STATIC_INITIALIZER_END
//! \~\brief
//! \~english Macro to remove class copy availability
//! \~russian Макрос для запрета копирования класса
# define NO_COPY_CLASS(Class)
//! \~\brief
//! \~english Macro to supress compiler warning about unused variable
//! \~russian Макрос для подавления предупреждения компилятора о неиспользуемой переменной
# define NO_UNUSED(x)
# undef MICRO_PIP
# undef FREERTOS
#endif // DOXYGEN
#ifdef WINDOWS
# ifdef CC_VC
# define SHUT_RDWR 2
# pragma comment(lib, "Ws2_32.lib")
# pragma comment(lib, "Iphlpapi.lib")
# pragma comment(lib, "Psapi.lib")
# ifdef ARCH_BITS_32
# define _X86_
# else
# define _IA64_
# endif
# else
# define SHUT_RDWR SD_BOTH
# endif
typedef int socklen_t;
extern long long __pi_perf_freq;
#endif
#ifndef DOXYGEN
# ifdef ANDROID
// # define tcdrain(fd) ioctl(fd, TCSBRK, 1)
// inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
// inline int mbtowc(wchar_t * w, const char * c, size_t) {*w = ((wchar_t * )&c)[0]; return 1;}
# endif
# ifdef MAC_OS
# define environ (*_NSGetEnviron())
typedef long time_t;
# endif
# ifdef LINUX
# define environ __environ
# endif
# ifdef FREE_BSD
extern char ** environ;
# endif
# ifndef NO_UNUSED
# define NO_UNUSED(x) (void)x
# endif
# ifndef assert
# define assert(x)
# define assertm(exp, msg)
# else
# define assertm(exp, msg) assert(((void)msg, exp))
# endif
# ifdef MICRO_PIP
# define __PIP_TYPENAME__(T) "?"
# else
# define __PIP_TYPENAME__(T) typeid(T).name()
# endif
# ifdef CC_GCC
# undef DEPRECATED
# undef DEPRECATEDM
# define DEPRECATED __attribute__((deprecated))
# define DEPRECATEDM(msg) __attribute__((deprecated(msg)))
# if CC_GCC_VERSION > 0x025F // > 2.95
# pragma GCC diagnostic warning "-Wdeprecated-declarations"
# ifdef LINUX
# define HAS_LOCALE
# endif
# ifdef MAC_OS
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
# pragma GCC diagnostic ignored "-Wc++11-extensions"
# endif
# endif
# ifdef ANDROID
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic ignored "-Wextra"
# pragma GCC diagnostic ignored "-Wc++11-extensions"
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
// # pragma GCC diagnostic ignored "-Wliteral-suffix"
# endif
# endif
# ifdef CC_VC
# undef DEPRECATED
# undef DEPRECATEDM
# define DEPRECATED __declspec(deprecated)
# define DEPRECATEDM(msg) __declspec(deprecated(msg))
# pragma warning(disable: 4018)
# pragma warning(disable: 4061)
# pragma warning(disable: 4100)
# pragma warning(disable: 4239)
# pragma warning(disable: 4242)
# pragma warning(disable: 4244)
# pragma warning(disable: 4251)
# pragma warning(disable: 4365)
# pragma warning(disable: 4512)
# pragma warning(disable: 4668)
# pragma warning(disable: 4710)
# pragma warning(disable: 4800)
# pragma warning(disable: 4820)
# pragma warning(disable: 4986)
# pragma warning(disable: 4996)
# ifdef ARCH_BITS_32
typedef long ssize_t;
# else
typedef long long ssize_t;
# endif
# endif
# ifdef CC_OTHER
# undef DEPRECATED
# undef DEPRECATEDM
# define DEPRECATED
# define DEPRECATEDM(msg)
# endif
#endif // DOXYGEN
// Private data macros
#ifndef DOXYGEN
# define PRIVATE_DECLARATION(e) \
struct __Private__; \
friend struct __Private__; \
struct e __PrivateInitializer__ { \
__PrivateInitializer__(); \
__PrivateInitializer__(const __PrivateInitializer__ & o); \
~__PrivateInitializer__(); \
__PrivateInitializer__ & operator=(const __PrivateInitializer__ & o); \
__Private__ * p; \
}; \
__PrivateInitializer__ __privateinitializer__;
# define PRIVATE_DEFINITION_START(c) struct c::__Private__ {
# define PRIVATE_DEFINITION_END(c) \
} \
; \
c::__PrivateInitializer__::__PrivateInitializer__() { \
p = new c::__Private__(); \
} \
c::__PrivateInitializer__::__PrivateInitializer__(const c::__PrivateInitializer__ &) { /*if (p) delete p;*/ \
p = new c::__Private__(); \
} \
c::__PrivateInitializer__::~__PrivateInitializer__() { \
delete p; \
p = 0; \
} \
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator=(const c::__PrivateInitializer__ &) { \
if (p) delete p; \
p = new c::__Private__(); \
return *this; \
}
# define PRIVATE (__privateinitializer__.p)
# define PRIVATEWB __privateinitializer__.p
#endif // DOXYGEN
#define NO_COPY_CLASS(name) \
name(const name &) = delete; \
name & operator=(const name &) = delete;
#define _PIP_ADD_COUNTER_WS(a, cnt, line) a##cnt##_##line
#define _PIP_ADD_COUNTER_WF(a, cnt, line) _PIP_ADD_COUNTER_WS(a, cnt, line)
#define _PIP_ADD_COUNTER(a) _PIP_ADD_COUNTER_WF(a, __COUNTER__, __LINE__)
#define STATIC_INITIALIZER_BEGIN \
class { \
class _Initializer_ { \
public: \
_Initializer_() {
#define STATIC_INITIALIZER_END \
} \
} \
_initializer_; \
} \
_PIP_ADD_COUNTER(_pip_initializer_);
//! \~\brief
//! \~english Minimal sleep in milliseconds for internal PIP using
//! \~russian Минимальное значание задержки в милисекундах для внутреннего использования в библиотеке PIP
//! \~\details
//! \~english Using in \a piMinSleep(), \a PIThread, \a PITimer::Pool. By default 1ms.
//! \~russian Используется в \a piMinSleep(), \a PIThread, \a PITimer::Pool. По умолчанию равна 1мс.
#ifndef PIP_MIN_MSLEEP
# ifndef MICRO_PIP
# define PIP_MIN_MSLEEP 1.
# else
# define PIP_MIN_MSLEEP 10.
# endif
#endif
//! \~\brief
//! \~english Macro used for infinite loop
//! \~russian Макрос для бесконечного цикла
#define FOREVER for (;;)
//! \~\brief
//! \~english Macro used for infinite wait
//! \~russian Макрос для бесконечного ожидания
#define FOREVER_WAIT FOREVER piMinSleep();
//! \~\brief
//! \~english Macro used for infinite wait
//! \~russian Макрос для бесконечного ожидания
#define WAIT_FOREVER FOREVER piMinSleep();
#endif // PIBASE_MACROS_H

View File

@@ -0,0 +1,44 @@
/*
PIP - Platform Independent Primitives
Bit array
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 "pibitarray.h"
#include "picout.h"
PICout operator <<(PICout s, const PIBitArray & ba) {
s.space();
s.setControl(0, true);
for (uint i = 0; i < ba.bitSize(); ++i) {
s << int(ba[i]);
if (i % 8 == 7) s << ' ';
}
s.restoreControl();
return s;
}
#ifdef PIP_STD_IOSTREAM
std::ostream &operator <<(std::ostream & s, const PIBitArray & ba) {
for (uint i = 0; i < ba.bitSize(); ++i) {
s << ba[i];
if (i % 8 == 7) s << ' ';
}
return s;
}
#endif

114
libs/main/core/pibitarray.h Normal file
View File

@@ -0,0 +1,114 @@
/*! \file pibitarray.h
* \~\brief
* \~english Bit array
* \~russian Битовый массив
*/
/*
PIP - Platform Independent Primitives
Bit array
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 PIBITARRAY_H
#define PIBITARRAY_H
#include "pivector.h"
class PIP_EXPORT PIBitArray {
friend PIByteArray & operator <<(PIByteArray & s, const PIBitArray & v);
friend PIByteArray & operator >>(PIByteArray & s, PIBitArray & v);
public:
PIBitArray(const int & size = 0) {resize(size);}
PIBitArray(uchar val) {resize(sizeof(val) * 8); data_[0] = val;}
PIBitArray(ushort val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(uint val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(ulong val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(ullong val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(const uchar * bytes, uint size) {resize(size * 8); memcpy(data(), bytes, size);}
uint bitSize() const {return size_;}
uint byteSize() const {return bytesInBits(size_);}
PIBitArray & resize(const uint & size) {size_ = size; data_.resize(bytesInBits(size_)); return *this;}
PIBitArray & clearBit(const uint & index) {data_[index / 8] &= ~(1 << (index % 8)); return *this;}
PIBitArray & setBit(const uint & index) {data_[index / 8] |= (1 << (index % 8)); return *this;}
PIBitArray & writeBit(const uint & index, const bool & value) {if (value) setBit(index); else clearBit(index); return *this;}
PIBitArray & writeBit(const uint & index, const uchar & value) {return writeBit(index, value > 0);}
PIBitArray & push_back(const bool & value) {resize(size_ + 1); writeBit(size_ - 1, value); return *this;}
PIBitArray & push_back(const uchar & value) {return push_back(value > 0);}
PIBitArray & insert(const uint & index, const bool & value) {
resize(size_ + 1);
uint fi = byteSize() - 1, si = index / 8, ti = index % 8;
uchar c = data_[si];
for (uint i = fi; i > si; --i) {
data_[i] <<= 1;
if ((0x80 & data_[i - 1]) == 0x80) data_[i] |= 1;
else data_[i] &= 0xFE;}
data_[si] &= (0xFF >> (7 - ti));
data_[si] |= ((c << 1) & (0xFF << (ti)));
if (value) data_[si] |= (1 << ti);
else data_[si] &= ~(1 << ti);
return *this;}
PIBitArray & insert(const uint & index, const uchar & value) {return insert(index, value > 0);}
PIBitArray & push_front(const bool & value) {return insert(0, value);}
PIBitArray & push_front(const uchar & value) {return push_front(value > 0);}
PIBitArray & pop_back() {return resize(size_ - 1);}
PIBitArray & pop_front() {
if (size_ == 0) return *this;
uint fi = byteSize() - 1;
for (uint i = 0; i < fi; ++i) {
data_[i] >>= 1;
if ((1 & data_[i + 1]) == 1) data_[i] |= 0x80;
else data_[i] &= 0x7F;}
data_[fi] >>= 1;
resize(size_ - 1);
return *this;}
PIBitArray & append(const PIBitArray & ba) {for (uint i = 0; i < ba.bitSize(); ++i) push_back(ba[i]); return *this;}
uchar * data() {return data_.data();}
uchar toUChar() {if (size_ == 0) return 0; return data_[0];}
ushort toUShort() {ushort t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
uint toUInt() {uint t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
ulong toULong() {ulong t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
ullong toULLong() {ullong t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
bool at(const uint & index) const {return (1 & (data_[index / 8] >> (index % 8))) == 1 ? true : false;}
bool operator [](const uint & index) const {return at(index);}
void operator +=(const PIBitArray & ba) {append(ba);}
bool operator ==(const PIBitArray & ba) const {if (bitSize() != ba.bitSize()) return false; for (uint i = 0; i < bitSize(); ++i) if (at(i) != ba[i]) return false; return true;}
bool operator !=(const PIBitArray & ba) const {return !(*this == ba);}
void operator =(const uchar & val) {resize(sizeof(val) * 8); data_[0] = val;}
void operator =(const ushort & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
void operator =(const uint & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
void operator =(const ulong & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
void operator =(const ullong & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
private:
static uint bytesInBits(const uint & bits) {return (bits + 7) / 8;}
PIVector<uchar> data_;
uint size_;
};
#ifdef PIP_STD_IOSTREAM
//std::ostream & operator <<(std::ostream & s, const PIBitArray & ba);
#endif
PICout operator <<(PICout s, const PIBitArray & ba);
#endif // PIBITARRAY_H

View File

@@ -18,10 +18,7 @@
*/ */
#include "pibytearray.h" #include "pibytearray.h"
#include "picrc.h"
#include "pistringlist.h" #include "pistringlist.h"
#include <iostream> #include <iostream>
//! \class PIByteArray pibytearray.h //! \class PIByteArray pibytearray.h
@@ -31,30 +28,53 @@
//! It can be constructed from any data and size. //! It can be constructed from any data and size.
//! You can use %PIByteArray as binary stream //! You can use %PIByteArray as binary stream
//! to serialize/deserialize any objects and data. //! to serialize/deserialize any objects and data.
//! See details \ref iostream. //! This class based on PIDeque<uchar> and provide some handle function
//! This class use PIDeque<uchar> and provide some handle function
//! to manipulate it. //! to manipulate it.
//! \~russian //! \~russian
//! %PIByteArray используется для хранения байтов. //! %PIByteArray используется для хранения байтов.
//! Он может быть сконструирован из любых даных. //! Он может быть сконструирован из любых даных.
//! Можно использовать %PIByteArray как потоковый объект //! Можно использовать %PIByteArray как потоковый объект
//! для сериализации/десериализации любых типов и данных. //! для сериализации/десериализации любых типов и данных.
//! Подробнее \ref iostream. //! Этот класс наследован от PIDeque<uchar> и предоставляет набор
//! Этот класс использует PIDeque<uchar> и предоставляет набор
//! удобных методов для работы с байтами. //! удобных методов для работы с байтами.
//! //!
//! \~english \section PIByteArray_sec0 Usage //! \~english \section PIByteArray_sec0 Usage
//! \~russian \section PIByteArray_sec0 Использование //! \~russian \section PIByteArray_sec0 Использование
//! \~english //! \~english
//! %PIByteArray subclass PIBinaryStream and can be used to store custom data and manipulate it. //! %PIByteArray can be used to store custom data and manipulate it. There are many
//! Store operators places data at the end of array, restore operators takes data from the beginning //! stream operators to store/restore common types to byte array. Store operators
//! places data at the end of array, restore operators takes data from the beginning
//! of array. //! of array.
//! In addition there are Hex and Base64 convertions. //! In addition there are Hex and Base64 convertions
//! \~russian //! \~russian
//! %PIByteArray наследован от PIBinaryStream и может быть использован для сохранения любых данных и работы с ними. //! %PIByteArray может быть использован для сохранения любых данных и работы с ними.
//! Он предоставляет множество операторов для сохранения/извлечения общих типов.
//! Операторы сохранения добавляют данные в конец массива, а операторы извлечения //! Операторы сохранения добавляют данные в конец массива, а операторы извлечения
//! берут данные из его начала. //! берут данные из его начала.
//! Также есть методы для преобразования в Hex и Base64. //!
//! \~english
//! One of the major usage of %PIByteArray is stream functions. You can form binary
//! packet from many types (also dynamic types, e.g. PIVector) with one line:
//! \~russian
//! Один из основных сценариев использования %PIByteArray - это потоковый объект.
//! Можно сформировать пакет бинарных данных из многих типов (также и контейнеров,
//! например, PIVector) в одну строку:
//! \~\snippet pibytearray.cpp 0
//!
//! \~english
//! Or you can descibe stream operator of your own type and store/restore vectors of
//! your type:
//! \~russian
//! Также можно описать операторы сохранения/извлечения для собственных типов:
//! \~\snippet pibytearray.cpp 1
//!
//! \~english
//! For store/restore custom data blocks there is PIByteArray::RawData class. Stream
//! operators of this class simply store/restore data block to/from byte array:
//! \~russian
//! Для сохранения/извлечения блоков произвольных данных используется класс PIByteArray::RawData.
//! Потоковые операторы для него просто сохраняют/извлекают блоки байтов:
//! \~\snippet pibytearray.cpp 2
//! //!
//! \~english \section PIByteArray_sec1 Attention //! \~english \section PIByteArray_sec1 Attention
//! \~russian \section PIByteArray_sec1 Внимание //! \~russian \section PIByteArray_sec1 Внимание
@@ -68,32 +88,56 @@
//! а не просто добавляет его содержимое в конец. Этот оператор полезен для управляемой //! а не просто добавляет его содержимое в конец. Этот оператор полезен для управляемой
//! упаковки произвольных данных в виде %PIByteArray. //! упаковки произвольных данных в виде %PIByteArray.
//! Для добавления содержимого одного байтового массива к другому используется //! Для добавления содержимого одного байтового массива к другому используется
//! метод \a append(). //! метов \a append().
//! \~\snippet pibytearray.cpp 3 //! \~\snippet pibytearray.cpp 3
//! //!
static const uchar base64Table[64] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, static const uchar base64Table[64] = {
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f}; 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f};
static const uchar base64InvTable[256] = { static const uchar base64InvTable[256] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x17, 0x18, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x0, 0x0, 0x3F,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3C, 0x3D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; 0x17, 0x18, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x31, 0x32, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
// clang-format off
struct base64HelpStruct { struct base64HelpStruct {
base64HelpStruct() {v = 0;} base64HelpStruct() {v = 0;}
inline void setBytes(const uchar * r, int size = 3) { inline void setBytes(const uchar * r, int size = 3) {
@@ -126,7 +170,6 @@ struct base64HelpStruct {
} }
uint v; uint v;
}; };
// clang-format on
PIByteArray &PIByteArray::convertToBase64() { PIByteArray &PIByteArray::convertToBase64() {
@@ -143,8 +186,7 @@ PIByteArray PIByteArray::toBase64() const {
if (isEmpty()) return PIByteArray(); if (isEmpty()) return PIByteArray();
base64HelpStruct hs; base64HelpStruct hs;
PIByteArray ret; PIByteArray ret;
const int sz = (size_s() / 3) * 3; int sz = (size_s() / 3) * 3, ri = -1;
int ri = -1;
uchar t[4]; uchar t[4];
ret.resize(((size_s() - 1) / 3 + 1) * 4); ret.resize(((size_s() - 1) / 3 + 1) * 4);
for (int i = 0; i < sz; i += 3) { for (int i = 0; i < sz; i += 3) {
@@ -155,7 +197,7 @@ PIByteArray PIByteArray::toBase64() const {
ret[++ri] = (t[2]); ret[++ri] = (t[2]);
ret[++ri] = (t[3]); ret[++ri] = (t[3]);
} }
const int der = size_s() % 3; int der = size_s() % 3;
switch (der) { switch (der) {
case 1: case 1:
hs.setBytes(data(sz), 1); hs.setBytes(data(sz), 1);
@@ -183,8 +225,7 @@ PIByteArray PIByteArray::fromBase64(const PIByteArray & base64) {
if (base64.isEmpty()) return PIByteArray(); if (base64.isEmpty()) return PIByteArray();
base64HelpStruct hs; base64HelpStruct hs;
PIByteArray ret; PIByteArray ret;
const int sz = base64.size_s(); int sz = base64.size_s(), ind = -1;
int ind = -1;
uchar t[4]; uchar t[4];
ret.resize(sz / 4 * 3); ret.resize(sz / 4 * 3);
for (int i = 0; i < sz; i += 4) { for (int i = 0; i < sz; i += 4) {
@@ -195,8 +236,7 @@ PIByteArray PIByteArray::fromBase64(const PIByteArray & base64) {
ret[++ind] = (t[2]); ret[++ind] = (t[2]);
} }
if (base64.back() == '=') ret.pop_back(); if (base64.back() == '=') ret.pop_back();
if (sz > 1) if (sz > 1) if (base64[sz - 2] == '=') ret.pop_back();
if (base64[sz - 2] == '=') ret.pop_back();
return ret; return ret;
} }
@@ -208,15 +248,14 @@ PIByteArray PIByteArray::fromBase64(const PIString & base64) {
PIByteArray & PIByteArray::compressRLE(uchar threshold) { PIByteArray & PIByteArray::compressRLE(uchar threshold) {
PIByteArray t; PIByteArray t;
uchar fb; uchar fb, clen, mlen = 255 - threshold;
uchar clen;
const uchar mlen = 255 - threshold;
for (uint i = 0; i < size();) { for (uint i = 0; i < size();) {
fb = at(i); fb = at(i);
clen = 1; clen = 1;
while (at(++i) == fb) { while (at(++i) == fb) {
++clen; ++clen;
if (clen == mlen) break; if (clen == mlen)
break;
} }
if (clen > 1) { if (clen > 1) {
t.push_back(threshold + clen); t.push_back(threshold + clen);
@@ -236,8 +275,7 @@ PIByteArray & PIByteArray::compressRLE(uchar threshold) {
PIByteArray & PIByteArray::decompressRLE(uchar threshold) { PIByteArray & PIByteArray::decompressRLE(uchar threshold) {
PIByteArray t; PIByteArray t;
uchar fb; uchar fb, clen;
uchar clen;
for (uint i = 0; i < size(); ++i) { for (uint i = 0; i < size(); ++i) {
fb = at(i); fb = at(i);
if (fb >= threshold) { if (fb >= threshold) {
@@ -269,7 +307,7 @@ PIByteArray & PIByteArray::decompressRLE(uchar threshold) {
//! \endcode //! \endcode
uchar PIByteArray::checksumPlain8(bool inverse) const { uchar PIByteArray::checksumPlain8(bool inverse) const {
uchar c = 0; uchar c = 0;
const int sz = size_s(); int sz = size_s();
for (int i = 0; i < sz; ++i) for (int i = 0; i < sz; ++i)
c += at(i); c += at(i);
if (inverse) c = ~(c + 1); if (inverse) c = ~(c + 1);
@@ -277,19 +315,6 @@ uchar PIByteArray::checksumPlain8(bool inverse) const {
} }
uchar PIByteArray::checksumCRC8() const {
return standardCRC_8().calculate(data(), size());
}
ushort PIByteArray::checksumCRC16() const {
return standardCRC_16().calculate(data(), size());
}
uint PIByteArray::checksumCRC32() const {
return standardCRC_32().calculate(data(), size());
}
//! \~\details //! \~\details
//! \~english //! \~english
//! This is sum of all bytes multiplied by index+1, if inverse then add 1 and inverse. //! This is sum of all bytes multiplied by index+1, if inverse then add 1 and inverse.
@@ -305,7 +330,7 @@ uint PIByteArray::checksumCRC32() const {
//! \endcode //! \endcode
uint PIByteArray::checksumPlain32(bool inverse) const { uint PIByteArray::checksumPlain32(bool inverse) const {
uint c = 0; uint c = 0;
const int sz = size_s(); int sz = size_s();
for (int i = 0; i < sz; ++i) for (int i = 0; i < sz; ++i)
c += at(i) * (i + 1); c += at(i) * (i + 1);
if (inverse) c = ~(c + 1); if (inverse) c = ~(c + 1);
@@ -320,7 +345,7 @@ uint PIByteArray::hash() const {
PIString PIByteArray::toString(int base) const { PIString PIByteArray::toString(int base) const {
PIString ret; PIString ret;
const int sz = size_s(); int sz = size_s();
for (int i = 0; i < sz; ++i) { for (int i = 0; i < sz; ++i) {
if (i > 0) ret += " "; if (i > 0) ret += " ";
if (base == 2) ret += "b"; if (base == 2) ret += "b";
@@ -338,17 +363,13 @@ PIString PIByteArray::toHex() const {
const uchar *d = data(); const uchar *d = data();
for (int i = 0; i < size_s(); ++i) { for (int i = 0; i < size_s(); ++i) {
int j = (d[i] >> 4) & 0xf; int j = (d[i] >> 4) & 0xf;
if (j <= 9) if (j <= 9) hexData[i*2] = (j + '0');
hexData[i * 2] = (j + '0'); else hexData[i*2] = (j + 'a' - 10);
else
hexData[i * 2] = (j + 'a' - 10);
j = d[i] & 0xf; j = d[i] & 0xf;
if (j <= 9) if (j <= 9) hexData[i*2+1] = (j + '0');
hexData[i * 2 + 1] = (j + '0'); else hexData[i*2+1] = (j + 'a' - 10);
else
hexData[i * 2 + 1] = (j + 'a' - 10);
} }
return PIString::fromAscii(hex); return PIString(hex);
} }
@@ -356,10 +377,10 @@ PIByteArray PIByteArray::fromUserInput(PIString str) {
PIByteArray ret; PIByteArray ret;
if (str.trim().isEmpty()) return ret; if (str.trim().isEmpty()) return ret;
str.replaceAll("\n", " ").replaceAll("\t", " ").replaceAll(" ", " "); str.replaceAll("\n", " ").replaceAll("\t", " ").replaceAll(" ", " ");
const PIStringList bl(str.split(" ")); PIStringList bl(str.split(" "));
bool ok(false); bool ok(false);
for (const auto & b: bl) { piForeachC (PIString & b, bl) {
const int bv = b.toInt(-1, &ok); int bv = b.toInt(-1, &ok);
if (ok) ret << uchar(bv); if (ok) ret << uchar(bv);
} }
return ret; return ret;
@@ -367,21 +388,17 @@ PIByteArray PIByteArray::fromUserInput(PIString str) {
PIByteArray PIByteArray::fromHex(PIString str) { PIByteArray PIByteArray::fromHex(PIString str) {
const PIByteArray hexEncoded = str.toByteArray(); PIByteArray hexEncoded = str.toByteArray();
PIByteArray res((hexEncoded.size() + 1)/ 2); PIByteArray res((hexEncoded.size() + 1)/ 2);
uchar *result = res.data() + res.size(); uchar *result = res.data() + res.size();
bool odd_digit = true; bool odd_digit = true;
for (int i = hexEncoded.size() - 1; i >= 0; --i) { for (int i = hexEncoded.size() - 1; i >= 0; --i) {
int ch = hexEncoded.at(i); int ch = hexEncoded.at(i);
int tmp; int tmp;
if (ch >= '0' && ch <= '9') if (ch >= '0' && ch <= '9') tmp = ch - '0';
tmp = ch - '0'; else if (ch >= 'a' && ch <= 'f') tmp = ch - 'a' + 10;
else if (ch >= 'a' && ch <= 'f') else if (ch >= 'A' && ch <= 'F') tmp = ch - 'A' + 10;
tmp = ch - 'a' + 10; else continue;
else if (ch >= 'A' && ch <= 'F')
tmp = ch - 'A' + 10;
else
continue;
if (odd_digit) { if (odd_digit) {
--result; --result;
*result = tmp; *result = tmp;
@@ -398,14 +415,14 @@ PIByteArray PIByteArray::fromHex(PIString str) {
PICout operator <<(PICout s, const PIByteArray & ba) { PICout operator <<(PICout s, const PIByteArray & ba) {
s.space(); s.space();
s.saveAndSetControls(0); s.setControl(0, true);
s << "{"; s << "{";
for (uint i = 0; i < ba.size(); ++i) { for (uint i = 0; i < ba.size(); ++i) {
s << ba[i]; s << ba[i];
if (i < ba.size() - 1) s << ", "; if (i < ba.size() - 1) s << ", ";
} }
s << "}"; s << "}";
s.restoreControls(); s.restoreControl();
return s; return s;
} }
@@ -421,3 +438,38 @@ std::ostream & operator<<(std::ostream & s, const PIByteArray & ba) {
return s; return s;
} }
#endif #endif
PIByteArray & operator >>(PIByteArray & s, PIByteArray & v) {
if (s.size_s() < 4) {
s.clear();
v.clear();
return s;
}
assert(s.size_s() >= 4);
int sz = 0;
s >> sz;
if (sz > s.size_s()) {
piCout << "[PIByteArray] Warning: operator >> wants too much data, discard!" << sz << s.size_s();
s.clear();
v.clear();
return s;
}
v.resize(sz);
if (sz > 0) {
memcpy(v.data(), s.data(), sz);
s.remove(0, sz);
}
return s;
}
PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) {
s << int(v.size_s());
int os = s.size_s();
if (v.size_s() > 0) {
s.enlarge(v.size_s());
memcpy(s.data(os), v.data(), v.size());
}
return s;
}

View File

@@ -0,0 +1,712 @@
/*! \file pibytearray.h
* \ingroup Core
* \~\brief
* \~english Byte array
* \~russian Байтовый массив
*/
/*
PIP - Platform Independent Primitives
Byte array
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIBYTEARRAY_H
#define PIBYTEARRAY_H
#include "pichar.h"
#include "pibitarray.h"
#include "pimap.h"
#include "pivector2d.h"
#include <stdio.h>
class PIString;
class PIByteArray;
//! \ingroup Core
//! \~\brief
//! \~english The %PIByteArray class provides an array of bytes.
//! \~russian Класс %PIByteArray представляет собой массив байтов.
class PIP_EXPORT PIByteArray: public PIDeque<uchar>
{
public:
//! \~english Constructs an empty byte array
//! \~russian Создает пустой байтовый массив
PIByteArray() {;}
//! \~english Constructs copy of byte array "o"
//! \~russian Создает копию байтового массива "o"
PIByteArray(const PIByteArray & o): PIDeque<uchar>(o) {}
//! \~english Constructs copy of byte array "o"
//! \~russian Создает копию байтового массива "o"
PIByteArray(const PIDeque<uchar> & o): PIDeque<uchar>(o) {}
PIByteArray(PIByteArray && o): PIDeque<uchar>(std::move(o)) {}
//! \~english Constructs 0-filled byte array with size "size"
//! \~russian Создает заполненный "0" байтовый массив размером "size"
PIByteArray(const uint size) {resize(size);}
//! \~english Constructs byte array from data "data" and size "size"
//! \~russian Создает байтовый массив из данных по указателю "data" размером "size"
PIByteArray(const void * data, const uint size): PIDeque<uchar>((const uchar*)data, size_t(size)) {}
//! \~english Constructs byte array with size "size" filled by "t"
//! \~russian Создает заполненный "t" байтовый массив размером "size"
PIByteArray(const uint size, uchar t): PIDeque<uchar>(size, t) {}
//! \~english Help struct to store/restore custom blocks of data to/from PIByteArray
//! \~russian Вспомогательная структура для сохранения/извлечения произвольного блока данных в/из байтового массива
struct RawData {
friend PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v);
friend PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v);
public:
//! \~english Constructs data block
//! \~russian Создает блок данных
RawData(void * data = 0, int size = 0) {d = data; s = size;}
RawData(const RawData & o) {d = o.d; s = o.s;}
//! \~english Constructs data block
//! \~russian Создает блок данных
RawData(const void * data, const int size) {d = const_cast<void * >(data); s = size;}
RawData & operator =(const RawData & o) {d = o.d; s = o.s; return *this;}
private:
void * d;
int s;
};
//! \~english Return resized byte array
//! \~russian Возвращает копию байтового массива с измененным размером
PIByteArray resized(uint new_size) const {PIByteArray ret(new_size); memcpy(ret.data(), data(), new_size); return ret;}
//! \~english Return sub-array starts from "index" and has "count" or less bytes
//! \~russian Возвращает подмассив с данными от индекса "index" и размером не более "count"
PIByteArray getRange(size_t index, size_t count) const {
return PIDeque<uchar>::getRange(index, count);
}
//! \~english Convert data to Base 64 and return this byte array
//! \~russian Преобразует данные в Base 64 и возвращает текущий массив
PIByteArray & convertToBase64();
//! \~english Convert data from Base 64 and return this byte array
//! \~russian Преобразует данные из Base 64 и возвращает текущий массив
PIByteArray & convertFromBase64();
//! \~english Return converted to Base 64 data
//! \~russian Возвращает копию байтового массива, преобразованного в Base 64
PIByteArray toBase64() const;
PIByteArray & compressRLE(uchar threshold = 192);
PIByteArray & decompressRLE(uchar threshold = 192);
PIByteArray compressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.compressRLE(threshold); return ba;}
PIByteArray decompressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.decompressRLE(threshold); return ba;}
//! \~english Return string representation of data, each byte in "base" base, separated by spaces
//! \~russian Возвращает текстовое представление байтового массива, каждый байт в "base" системе, с пробелами
PIString toString(int base = 16) const;
//! \~english
//! Returns a hex encoded copy of the byte array, without spaces.
//! The hex encoding uses the numbers 0-9 and the letters a-f.
//! \~russian
//! Возвращает шестнадцатеричное представление массива, без пробелов.
//! Оно использует цифры 0-9 и буквы a-f.
PIString toHex() const;
//! \~english Add to the end data "data" with size "size"
//! \~russian Добавляет в конец массива данные по указателю "data" размером "size"
PIByteArray & append(const void * data_, int size_) {uint ps = size(); enlarge(size_); memcpy(data(ps), data_, size_); return *this;}
//! \~english Add to the end byte array "data"
//! \~russian Добавляет в конец массива содержимое массива "data"
PIByteArray & append(const PIByteArray & data_) {uint ps = size(); enlarge(data_.size_s()); memcpy(data(ps), data_.data(), data_.size()); return *this;}
//! \~english Add to the end "t"
//! \~russian Добавляет в конец массива байт "t"
PIByteArray & append(uchar t) {push_back(t); return *this;}
//! \~english Returns 8-bit checksum
//! \~russian Возвращает 8-битную контрольную сумму
uchar checksumPlain8(bool inverse = true) const;
//! \~english Returns 32-bit checksum
//! \~russian Возвращает 32-битную контрольную сумму
uint checksumPlain32(bool inverse = true) const;
//! \~english Returns hash of content
//! \~russian Возвращает хэш содержимого
uint hash() const;
void operator =(const PIDeque<uchar> & d) {resize(d.size()); memcpy(data(), d.data(), d.size());}
PIByteArray & operator =(const PIByteArray & o) {if (this == &o) return *this; clear(); append(o); return *this;}
PIByteArray & operator =(PIByteArray && o) {swap(o); return *this;}
static PIByteArray fromUserInput(PIString str);
static PIByteArray fromHex(PIString str);
//! \~english Return converted from Base 64 data
//! \~russian Возвращает массив из Base 64 представления
static PIByteArray fromBase64(const PIByteArray & base64);
static PIByteArray fromBase64(const PIString & base64);
class StreamRef {
public:
StreamRef(PIByteArray & s): ba(s) {}
operator PIByteArray&() {return ba;}
private:
PIByteArray & ba;
};
};
//! \relatesalso PIByteArray
//! \~english Byte arrays compare operator
//! \~russian Оператор сравнения
inline bool operator <(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() == v1.size()) {
if (v0.isEmpty()) return false;
return memcmp(v0.data(), v1.data(), v0.size()) < 0;
}
return v0.size() < v1.size();
}
//! \relatesalso PIByteArray
//! \~english Byte arrays compare operator
//! \~russian Оператор сравнения
inline bool operator >(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() == v1.size()) {
if (v0.isEmpty()) return false;
return memcmp(v0.data(), v1.data(), v0.size()) > 0;
}
return v0.size() > v1.size();
}
//! \relatesalso PIByteArray
//! \~english Byte arrays compare operator
//! \~russian Оператор сравнения
inline bool operator ==(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() == v1.size()) {
if (v0.isEmpty()) return true;
return memcmp(v0.data(), v1.data(), v0.size()) == 0;
}
return false;
}
//! \relatesalso PIByteArray
//! \~english Byte arrays compare operator
//! \~russian Оператор сравнения
inline bool operator !=(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() == v1.size()) {
if (v0.isEmpty()) return false;
return memcmp(v0.data(), v1.data(), v0.size()) != 0;
}
return true;
}
#ifdef PIP_STD_IOSTREAM
//! \relatesalso PIByteArray \brief Output to std::ostream operator
inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba);
#endif
//! \relatesalso PIByteArray
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
PIP_EXPORT PICout operator <<(PICout s, const PIByteArray & ba);
// store operators for basic types
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const bool v) {s.push_back(v); return s;}
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const char v) {s.push_back(v); return s;}
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const uchar v) {s.push_back(v); return s;}
//! \relatesalso PIByteArray
//! \~english Store operator for any trivial copyable type
//! \~russian Оператор сохранения для тривиальных типов
template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray::StreamRef operator <<(PIByteArray & s, const T & v) {
int os = s.size_s();
s.enlarge(sizeof(v));
memcpy(s.data(os), &v, sizeof(v));
return s;
}
//! \relatesalso PIByteArray
//! \~english Store operator, see \ref PIByteArray_sec1 for details
//! \~russian Оператор сохранения, подробнее в \ref PIByteArray_sec1
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v);
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {
int os = s.size_s();
if (v.s > 0) {
s.enlarge(v.s);
memcpy(s.data(os), v.d, v.s);
}
return s;
}
//! \relatesalso PIByteArray
//! \~english Store operator for PIVector of any trivial copyable type
//! \~russian Оператор сохранения для PIVector тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
s << int(v.size_s());
int os = s.size_s();
if (v.size_s() > 0) {
s.enlarge(v.size_s()*sizeof(T));
memcpy(s.data(os), v.data(), v.size_s()*sizeof(T));
}
return s;
}
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
s << int(v.size_s());
for (uint i = 0; i < v.size(); ++i) s << v[i];
return s;
}
//! \relatesalso PIByteArray
//! \~english Store operator for PIDeque of any trivial copyable type
//! \~russian Оператор сохранения для PIDeque тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
s << int(v.size_s());
int os = s.size_s();
if (v.size_s() > 0) {
s.enlarge(v.size_s()*sizeof(T));
memcpy(s.data(os), v.data(), v.size_s()*sizeof(T));
}
return s;
}
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
s << int(v.size_s());
for (uint i = 0; i < v.size(); ++i) s << v[i];
return s;
}
//! \relatesalso PIByteArray
//! \~english Store operator for PIVector2D of any trivial copyable type
//! \~russian Оператор сохранения для PIVector2D тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
s << int(v.rows()) << int(v.cols());
int os = s.size_s();
if (v.size_s() > 0) {
s.enlarge(v.size_s()*sizeof(T));
memcpy(s.data(os), v.data(), v.size_s()*sizeof(T));
}
return s;
}
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
s << int(v.rows()) << int(v.cols()) << v.toPlainVector();
return s;
}
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const PIBitArray & v) {s << v.size_ << v.data_; return s;}
//! \relatesalso PIPair
//! \~english Store operator
//! \~russian Оператор сохранения
template<typename Type0, typename Type1>
inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;}
// restore operators for basic types
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, bool & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, char & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
//! \relatesalso PIByteArray
//! \~english Restore operator for any trivial copyable type
//! \~russian Оператор извлечения для тривиальных типов
template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray::StreamRef operator >>(PIByteArray & s, T & v) {
if (s.size() < sizeof(v)) {
printf("error with %s\n", __PIP_TYPENAME__(T));
assert(s.size() >= sizeof(v));
}
memcpy((void*)(&v), s.data(), sizeof(v));
s.remove(0, sizeof(v));
return s;
}
//! \relatesalso PIByteArray
//! \~english Restore operator, see \ref PIByteArray_sec1 for details
//! \~russian Оператор извлечения, подробнее в \ref PIByteArray_sec1
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PIByteArray & v);
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {
if (s.size_s() < v.s) {
printf("error with RawData %d < %d\n", (int)s.size_s(), v.s);
assert(s.size_s() >= v.s);
}
if (v.s > 0) {
memcpy((void*)(v.d), s.data(), v.s);
s.remove(0, v.s);
}
return s;
}
//! \relatesalso PIByteArray
//! \~english Restore operator for PIVector of any trivial copyable type
//! \~russian Оператор извлечения для PIVector тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) {
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
v._resizeRaw(sz);
if (sz > 0) {
memcpy(v.data(), s.data(), sz*sizeof(T));
s.remove(0, sz*sizeof(T));
}
return s;
}
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) {
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
v.resize(sz);
for (int i = 0; i < sz; ++i) s >> v[i];
return s;
}
//! \relatesalso PIByteArray
//! \~english Restore operator for PIDeque of any trivial copyable type
//! \~russian Оператор извлечения для PIDeque тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) {
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
v._resizeRaw(sz);
if (sz > 0) {
memcpy(v.data(), s.data(), sz*sizeof(T));
s.remove(0, sz*sizeof(T));
}
return s;
}
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) {
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
v.resize(sz);
for (int i = 0; i < sz; ++i) s >> v[i];
return s;
}
//! \relatesalso PIByteArray
//! \~english Restore operator for PIVector2D of any trivial copyable type
//! \~russian Оператор извлечения для PIVector2D тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) {
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 8);
}
int r, c; s >> r >> c;
v._resizeRaw(r, c);
int sz = r*c;
if (sz > 0) {
memcpy(v.data(), s.data(), sz*sizeof(T));
s.remove(0, sz*sizeof(T));
}
return s;
}
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) {
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 8);
}
int r,c;
PIVector<T> tmp;
s >> r >> c >> tmp;
v = PIVector2D<T>(r, c, tmp);
return s;
}
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, PIBitArray & v) {assert(s.size_s() >= 8); s >> v.size_ >> v.data_; return s;}
//! \relatesalso PIPair
//! \~english Restore operator
//! \~russian Оператор извлечения
template<typename Type0, typename Type1>
inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;}
// store operators for complex types
//! \relatesalso PIByteArray
//! \~english Store operator for PIVector of any compound type
//! \~russian Оператор сохранения для PIVector сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
s << int(v.size_s());
for (uint i = 0; i < v.size(); ++i) s << v[i];
return s;
}
//! \relatesalso PIByteArray
//! \~english Store operator for PIDeque of any compound type
//! \~russian Оператор сохранения для PIDeque сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
s << int(v.size_s());
for (uint i = 0; i < v.size(); ++i) s << v[i];
return s;
}
//! \relatesalso PIByteArray
//! \~english Store operator for PIVector2D of any compound type
//! \~russian Оператор сохранения для PIVector2D сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
s << int(v.rows()) << int(v.cols()) << v.toPlainVector();
return s;
}
// restore operators for complex types
//! \relatesalso PIByteArray
//! \~english Restore operator for PIVector of any compound type
//! \~russian Оператор извлечения для PIVector сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) {
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
v.resize(sz);
for (int i = 0; i < sz; ++i) s >> v[i];
return s;
}
//! \relatesalso PIByteArray
//! \~english Restore operator for PIDeque of any compound type
//! \~russian Оператор извлечения для PIDeque сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) {
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
v.resize(sz);
for (int i = 0; i < sz; ++i) s >> v[i];
return s;
}
//! \relatesalso PIByteArray
//! \~english Restore operator for PIVector2D of any compound type
//! \~russian Оператор извлечения для PIVector2D сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) {
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 8);
}
int r,c;
PIVector<T> tmp;
s >> r >> c >> tmp;
v = PIVector2D<T>(r, c, tmp);
return s;
}
// other types
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
template <typename Key, typename T>
inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v) {
// s << int(v.pim_index.size_s());
// for (uint i = 0; i < v.size(); ++i)
// s << int(v.pim_index[i].index) << v.pim_index[i].key;
s << v.pim_content;
return s;
}
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
template <typename Key, typename T>
inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v) {
if (s.size_s() < 4) {
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
// int sz; s >> sz; v.pim_index.resize(sz);
// int ind = 0;
// for (int i = 0; i < sz; ++i) {
// s >> ind >> v.pim_index[i].key;
// v.pim_index[i].index = ind;
// }
s >> v.pim_content;
// if (v.pim_content.size_s() != v.pim_index.size_s()) {
// piCout << "Warning: loaded invalid PIMap, clear";
// v.clear();
// }
return s;
}
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const T & ) {
static_assert(std::is_trivially_copyable<T>::value, "[PIByteArray] Error: using undeclared operator << for complex type!");
return s;
}
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, T & ) {
static_assert(std::is_trivially_copyable<T>::value, "[PIByteArray] Error: using undeclared operator >> for complex type!");
return s;
}
//! \relatesalso PIByteArray
//! \~english Returns PIByteArray::hash() of "ba"
//! \~russian Возвращает PIByteArray::hash() от "ba"
template<> inline uint piHash(const PIByteArray & ba) {return ba.hash();}
//! \relatesalso PIByteArray
//! \~english Swap contents betwee "f" and "s"
//! \~russian Меняет содержимое массивов "f" и "s"
template<> inline void piSwap(PIByteArray & f, PIByteArray & s) {f.swap(s);}
//! \relatesalso PIByteArray
//! \~english Store "value" to bytearray and returns it
//! \~russian Сохраняет "value" в байтовый массив и возвращает его
template <typename T> PIByteArray piSerialize(const T & value) {
PIByteArray ret;
ret << value;
return ret;
}
//! \relatesalso PIByteArray
//! \~english Restore type "T" from bytearray "data" and returns it
//! \~russian Извлекает тип "T" из байтового массива "data" и возвращает его
template <typename T> T piDeserialize(const PIByteArray & data) {
T ret;
if (!data.isEmpty()) {
PIByteArray ba(data);
ba >> ret;
}
return ret;
}
#endif // PIBYTEARRAY_H

View File

@@ -87,10 +87,11 @@ ushort charFromCodepage(const char * c, int size, const char * codepage, int * t
int charCompare(const PIChar & f, const PIChar & s) { int charCompare(const PIChar & f, const PIChar & s) {
if (f.isAscii() && s.isAscii()) return strncmp(f.toCharPtr(), s.toCharPtr(), 1); if (f.isAscii() && s.isAscii())
return strncmp(f.toCharPtr(), s.toCharPtr(), 1);
return return
#ifdef PIP_ICU #ifdef PIP_ICU
u_strCompare((const UChar *)f.toWCharPtr(), 1, (const UChar *)s.toWCharPtr(), 1, 0); u_strCompare((const UChar*)f.toWCharPtr(), 1, (const UChar*)s.toWCharPtr(), 1, FALSE);
#else #else
# ifdef WINDOWS # ifdef WINDOWS
CompareStringW(LOCALE_USER_DEFAULT, 0, (PCNZWCH)f.toWCharPtr(), 1, (PCNZWCH)s.toWCharPtr(), 1) - 2; CompareStringW(LOCALE_USER_DEFAULT, 0, (PCNZWCH)f.toWCharPtr(), 1, (PCNZWCH)s.toWCharPtr(), 1) - 2;
@@ -111,6 +112,13 @@ bool winIsCharType(const ushort * ch, int type) {
} }
PIChar::PIChar(const char * c, int * bytes) {
ch = charFromCodepage(c, 4, __syslocname__, bytes);
}
PIChar PIChar::fromConsole(char c) { PIChar PIChar::fromConsole(char c) {
PIChar ret; PIChar ret;
ret.ch = charFromCodepage(&c, 1, __sysoemname__); ret.ch = charFromCodepage(&c, 1, __sysoemname__);
@@ -125,21 +133,10 @@ PIChar PIChar::fromSystem(char c) {
} }
PIChar PIChar::fromSystem(const char * c) {
PIChar ret;
int l = 0;
while (c[l] != '\0' && l < 4)
++l;
ret.ch = charFromCodepage(c, l, __syslocname__);
return ret;
}
PIChar PIChar::fromUTF8(const char * c) { PIChar PIChar::fromUTF8(const char * c) {
PIChar ret; PIChar ret;
int l = 0; int l = 0;
while (c[l] != '\0' && l < 4) while (c[l] != '\0') ++l;
++l;
ret.ch = charFromCodepage(c, l, __utf8name__); ret.ch = charFromCodepage(c, l, __utf8name__);
return ret; return ret;
} }
@@ -334,7 +331,8 @@ PIChar PIChar::toUpper() const {
#else #else
# ifdef WINDOWS # ifdef WINDOWS
ushort wc = 0; ushort wc = 0;
if (LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, (LPCWSTR)&ch, 1, (LPWSTR)&wc, 1) == 1) return PIChar(wc); if (LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, (LPCWSTR)&ch, 1, (LPWSTR)&wc, 1) == 1)
return PIChar(wc);
# endif # endif
#endif #endif
return PIChar((ushort)towupper(ch)); return PIChar((ushort)towupper(ch));
@@ -351,7 +349,8 @@ PIChar PIChar::toLower() const {
#else #else
# ifdef WINDOWS # ifdef WINDOWS
ushort wc = 0; ushort wc = 0;
if (LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, (LPCWSTR)&ch, 1, (LPWSTR)&wc, 1) == 1) return PIChar(wc); if (LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, (LPCWSTR)&ch, 1, (LPWSTR)&wc, 1) == 1)
return PIChar(wc);
# endif # endif
#endif #endif
return PIChar((ushort)towlower(ch)); return PIChar((ushort)towlower(ch));
@@ -360,9 +359,8 @@ PIChar PIChar::toLower() const {
PICout operator <<(PICout s, const PIChar & v) { PICout operator <<(PICout s, const PIChar & v) {
s.space(); s.space();
s.saveAndSetControls(0); s.setControl(0, true);
if (v.isAscii()) if (v.isAscii()) s << char(v.ch);
s << char(v.ch);
else { else {
#ifdef PIP_ICU #ifdef PIP_ICU
UErrorCode e((UErrorCode)0); UErrorCode e((UErrorCode)0);
@@ -382,6 +380,6 @@ PICout operator<<(PICout s, const PIChar & v) {
s << PIString(v); s << PIString(v);
#endif #endif
} }
s.restoreControls(); s.restoreControl();
return s; return s;
} }

View File

@@ -1,5 +1,5 @@
/*! \file pichar.h /*! \file pichar.h
* \ingroup Text * \ingroup Core
* \~\brief * \~\brief
* \~english Single string character * \~english Single string character
* \~russian Один символ строки * \~russian Один символ строки
@@ -32,18 +32,18 @@ extern PIP_EXPORT char * __syslocname__;
extern PIP_EXPORT char * __sysoemname__; extern PIP_EXPORT char * __sysoemname__;
extern PIP_EXPORT char * __utf8name__; extern PIP_EXPORT char * __utf8name__;
//! \ingroup Text //! \ingroup Core
//! \~\brief //! \~\brief
//! \~english %PIChar represents a single character. //! \~english %PIChar represents a single character.
//! \~russian %PIChar представляет собой один символ строки. //! \~russian %PIChar представляет собой один символ строки.
class PIP_EXPORT PIChar { class PIP_EXPORT PIChar
{
friend class PIString; friend class PIString;
friend PIP_EXPORT PICout operator<<(PICout s, const PIChar & v); friend PICout PIP_EXPORT operator <<(PICout s, const PIChar & v);
public: public:
//! \~english Contructs Ascii symbol //! \~english Contructs Ascii symbol
//! \~russian Создает символ Ascii //! \~russian Создает символ Ascii
PIChar(char c) { ch = c; } PIChar(char c) {ch = c; ch &= 0xFF;}
//! \~english Contructs ascii symbol //! \~english Contructs ascii symbol
//! \~russian Создает символ Ascii //! \~russian Создает символ Ascii
@@ -57,23 +57,17 @@ public:
//! \~russian Создает 2-байтный символ из `wchar_t` //! \~russian Создает 2-байтный символ из `wchar_t`
PIChar(wchar_t c) {ch = c;} PIChar(wchar_t c) {ch = c;}
//! \~english Contructs 2-bytes symbol from `char16_t` //! \~english Contructs symbol from system locale and no more than 4 bytes of string
//! \~russian Создает 2-байтный символ из `char16_t` //! \~russian Создает символ из системной локали не более 4 байт длины
PIChar(char16_t c) { ch = c; } PIChar(const char * c, int * bytes = 0);
//! \~english Copy operator //! \~english Copy operator
//! \~russian Оператор присваивания //! \~russian Оператор присваивания
PIChar & operator=(const char v) { PIChar & operator =(const char v) {ch = v; return *this;}
ch = v;
return *this;
}
//! \~english Copy operator //! \~english Copy operator
//! \~russian Оператор присваивания //! \~russian Оператор присваивания
PIChar & operator=(const wchar_t v) { PIChar & operator =(const wchar_t v) {ch = v; return *this;}
ch = v;
return *this;
}
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
@@ -81,7 +75,7 @@ public:
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
bool operator!=(const PIChar & o) const { return !(*this == o); } bool operator !=(const PIChar & o) const {return !(o == *this);}
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
@@ -177,91 +171,95 @@ public:
//! \~russian Возвращает символ из системной кодировки //! \~russian Возвращает символ из системной кодировки
static PIChar fromSystem(char c); static PIChar fromSystem(char c);
//! \~english Returns symbol from system codepage
//! \~russian Возвращает символ из системной кодировки
static PIChar fromSystem(const char * c);
//! \~english Returns symbol from UTF8 codepage //! \~english Returns symbol from UTF8 codepage
//! \~russian Возвращает символ из UTF8 кодировки //! \~russian Возвращает символ из UTF8 кодировки
static PIChar fromUTF8(const char * c); static PIChar fromUTF8(const char * c);
private: private:
ushort ch; ushort ch;
}; };
//! \relatesalso PIChar //! \relatesalso PIChar
//! \~english Output operator to \a PICout //! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout //! \~russian Оператор вывода в \a PICout
PIP_EXPORT PICout operator<<(PICout s, const PIChar & v); PICout PIP_EXPORT operator <<(PICout s, const PIChar & v);
//! \relatesalso PIChar //! \relatesalso PIChar
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
inline bool operator==(const char v, const PIChar & c) { inline bool operator ==(const char v, const PIChar & c) {return (PIChar(v) == c);}
return (PIChar(v) == c);
}
//! \relatesalso PIChar //! \relatesalso PIChar
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
inline bool operator>(const char v, const PIChar & c) { inline bool operator >(const char v, const PIChar & c) {return (PIChar(v) > c);}
return (PIChar(v) > c);
}
//! \relatesalso PIChar //! \relatesalso PIChar
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
inline bool operator<(const char v, const PIChar & c) { inline bool operator <(const char v, const PIChar & c) {return (PIChar(v) < c);}
return (PIChar(v) < c);
}
//! \relatesalso PIChar //! \relatesalso PIChar
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
inline bool operator>=(const char v, const PIChar & c) { inline bool operator >=(const char v, const PIChar & c) {return (PIChar(v) >= c);}
return (PIChar(v) >= c);
}
//! \relatesalso PIChar //! \relatesalso PIChar
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
inline bool operator<=(const char v, const PIChar & c) { inline bool operator <=(const char v, const PIChar & c) {return (PIChar(v) <= c);}
return (PIChar(v) <= c);
}
//! \relatesalso PIChar //! \relatesalso PIChar
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
inline bool operator==(ushort v, const PIChar & c) { inline bool operator ==(const char * v, const PIChar & c) {return (PIChar(v) == c);}
return (PIChar(v) == c);
}
//! \relatesalso PIChar //! \relatesalso PIChar
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
inline bool operator>(ushort v, const PIChar & c) { inline bool operator >(const char * v, const PIChar & c) {return (PIChar(v) > c);}
return (PIChar(v) > c);
}
//! \relatesalso PIChar //! \relatesalso PIChar
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
inline bool operator<(ushort v, const PIChar & c) { inline bool operator <(const char * v, const PIChar & c) {return (PIChar(v) < c);}
return (PIChar(v) < c);
}
//! \relatesalso PIChar //! \relatesalso PIChar
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
inline bool operator>=(ushort v, const PIChar & c) { inline bool operator >=(const char * v, const PIChar & c) {return (PIChar(v) >= c);}
return (PIChar(v) >= c);
}
//! \relatesalso PIChar //! \relatesalso PIChar
//! \~english Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения //! \~russian Оператор сравнения
inline bool operator<=(ushort v, const PIChar & c) { inline bool operator <=(const char * v, const PIChar & c) {return (PIChar(v) <= c);}
return (PIChar(v) <= c);
}
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator ==(const int v, const PIChar & c) {return (PIChar((ushort)v) == c);}
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >(const int v, const PIChar & c) {return (PIChar((ushort)v) > c);}
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <(const int v, const PIChar & c) {return (PIChar((ushort)v) < c);}
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >=(const int v, const PIChar & c) {return (PIChar((ushort)v) >= c);}
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <=(const int v, const PIChar & c) {return (PIChar((ushort)v) <= c);}
#endif // PICHAR_H #endif // PICHAR_H

View File

@@ -110,12 +110,14 @@ PIByteArray PIChunkStream::data() const {
int PIChunkStream::read() { int PIChunkStream::read() {
switch (version_) { switch (version_) {
case Version_1: (*data_) >> last_id >> last_data; break; case Version_1:
(*data_) >> last_id >> last_data;
break;
case Version_2: case Version_2:
last_id = readVInt(*data_); last_id = readVInt(*data_);
last_data.resize(readVInt(*data_)); last_data.resize(readVInt(*data_));
//piCout << last_id << last_data.size(); //piCout << last_id << last_data.size();
(*data_) >> PIMemoryBlock(last_data.data(), last_data.size_s()); (*data_) >> PIByteArray::RawData(last_data.data(), last_data.size_s());
break; break;
default: break; default: break;
} }
@@ -123,12 +125,15 @@ int PIChunkStream::read() {
} }
int PIChunkStream::peekVInt(Version version_, uchar * data_, int sz, uint & ret) { int PIChunkStream::peekVInt(Version version_, PIByteArray * data_, int pos, PIByteArray & hdr, uint & ret) {
switch (version_) { switch (version_) {
case Version_1: memcpy(&ret, data_, 4); return 4; case Version_1:
memcpy(&ret, data_->data(pos), 4);
return 4;
case Version_2: { case Version_2: {
PIByteArray hdr(data_, piMini(5, sz)); hdr.resize(4);
hdr.resize(5); hdr.fill(uchar(0));
memcpy(hdr.data(), data_->data(pos), piMini(4, data_->size_s() - pos));
uchar hsz = 0; uchar hsz = 0;
ret = readVInt(hdr, &hsz); ret = readVInt(hdr, &hsz);
return hsz; return hsz;
@@ -148,17 +153,14 @@ void PIChunkStream::replaceChunk(int id, const PIByteArray & v) {
pos.length = v.size_s(); pos.length = v.size_s();
if (size_mod != 0) { if (size_mod != 0) {
auto it = data_map.makeIterator(); auto it = data_map.makeIterator();
while (it.next()) { while (it.next())
if (it.value().start > pos.start) { if (it.valueRef().start > pos.start)
it.value().start += size_mod; it.valueRef().start += size_mod;
} if (size_mod > 0)
}
if (size_mod > 0) {
data_->insert(pos.start, PIByteArray(size_mod)); data_->insert(pos.start, PIByteArray(size_mod));
} else { else
data_->remove(pos.start, -size_mod); data_->remove(pos.start, -size_mod);
} }
}
memcpy(data_->data(pos.start - pos.size_bytes), nsba.data(), nsba.size()); memcpy(data_->data(pos.start - pos.size_bytes), nsba.data(), nsba.size());
pos.start += nsba.size_s() - pos.size_bytes; pos.start += nsba.size_s() - pos.size_bytes;
memcpy(data_->data(pos.start), v.data(), pos.length); memcpy(data_->data(pos.start), v.data(), pos.length);
@@ -170,9 +172,10 @@ void PIChunkStream::readAll() {
if (!data_) return; if (!data_) return;
int pos = 0, sz = data_->size_s(), hsz = 0; int pos = 0, sz = data_->size_s(), hsz = 0;
uint csz = 0, cid = 0; uint csz = 0, cid = 0;
PIByteArray hdr;
while (pos < sz) { while (pos < sz) {
pos += peekVInt((Version)version_, data_->data(pos), data_->size_s() - pos, cid); pos += peekVInt((Version)version_, data_, pos, hdr, cid);
hsz = peekVInt((Version)version_, data_->data(pos), data_->size_s() - pos, csz); hsz = peekVInt((Version)version_, data_, pos, hdr, csz);
pos += hsz; pos += hsz;
data_map[cid] = CacheEntry(pos, csz, hsz); data_map[cid] = CacheEntry(pos, csz, hsz);
pos += csz; pos += csz;
@@ -180,7 +183,20 @@ void PIChunkStream::readAll() {
} }
PIChunkStream::~PIChunkStream() {} PIChunkStream::~PIChunkStream() {
}
bool PIChunkStream::extract(PIByteArray & data, bool read_all) {
if (data.size_s() < 4) return false;
data >> tmp_data;
if (tmp_data.size_s() < 4) return false;
data_ = &tmp_data;
_init();
if (read_all)
readAll();
return true;
}
void PIChunkStream::_init() { void PIChunkStream::_init() {
@@ -192,41 +208,27 @@ void PIChunkStream::_init() {
if ((v & 0x80) == 0x80) { if ((v & 0x80) == 0x80) {
v &= 0x7f; v &= 0x7f;
switch (v) { switch (v) {
case 2: case 2: version_ = (uchar)Version_2; data_->pop_front(); first_byte_taken = true; break;
version_ = (uchar)Version_2;
data_->pop_front();
first_byte_taken = true;
break;
default: version_ = Version_1; break; default: version_ = Version_1; break;
} }
} else { } else
version_ = Version_1; version_ = Version_1;
} }
} }
}
uint PIChunkStream::readVInt(PIByteArray & s, uchar * bytes_cnt) { uint PIChunkStream::readVInt(PIByteArray & s, uchar * bytes_cnt) {
if (s.isEmpty()) return 0; if (s.isEmpty()) return 0;
uchar bytes[4]; uchar bytes[4]; s >> bytes[0];
uchar abc; uchar abc = 0;
s >> bytes[0];
if (bytes[0] == 0xf0) {
abc = 3;
for (int i = 0; i < 4; ++i)
s >> bytes[i];
if (bytes_cnt) *bytes_cnt = 5;
} else {
for (abc = 0; abc < 3; ++abc) { for (abc = 0; abc < 3; ++abc) {
uchar mask = (0x80 >> abc); uchar mask = (0x80 >> abc);
if ((bytes[0] & mask) == mask) { if ((bytes[0] & mask) == mask) {
bytes[0] &= (mask - 1); bytes[0] &= (mask - 1);
s >> bytes[abc + 1]; s >> bytes[abc + 1];
} else } else break;
break;
} }
if (bytes_cnt) *bytes_cnt = (abc + 1); if (bytes_cnt) *bytes_cnt = (abc + 1);
}
uint ret = 0; uint ret = 0;
for (int i = 0; i <= abc; ++i) { for (int i = 0; i <= abc; ++i) {
ret += (bytes[i] << (8 * ((int)abc - i))); ret += (bytes[i] << (8 * ((int)abc - i)));
@@ -236,15 +238,18 @@ uint PIChunkStream::readVInt(PIByteArray & s, uchar * bytes_cnt) {
void PIChunkStream::writeVInt(PIByteArray & s, uint val) { void PIChunkStream::writeVInt(PIByteArray & s, uint val) {
if (val > 0xfffffff) return;
if (val <= 0x7f) { if (val <= 0x7f) {
s << uchar(val); s << uchar(val);
} else if (val <= 0x3fff) { return;
}
if (val <= 0x3fff) {
s << uchar((val >> 8) | 0x80) << uchar(val & 0xff); s << uchar((val >> 8) | 0x80) << uchar(val & 0xff);
} else if (val <= 0x1fffff) { return;
}
if (val <= 0x1fffff) {
s << uchar((val >> 16) | 0xc0) << uchar((val >> 8) & 0xff) << uchar(val & 0xff); s << uchar((val >> 16) | 0xc0) << uchar((val >> 8) & 0xff) << uchar(val & 0xff);
} else if (val <= 0xfffffff) { return;
}
s << uchar((val >> 24) | 0xe0) << uchar((val >> 16) & 0xff) << uchar((val >> 8) & 0xff) << uchar(val & 0xff); s << uchar((val >> 24) | 0xe0) << uchar((val >> 16) & 0xff) << uchar((val >> 8) & 0xff) << uchar(val & 0xff);
} else {
s << uchar(0xf0) << uchar((val >> 24) & 0xff) << uchar((val >> 16) & 0xff) << uchar((val >> 8) & 0xff) << uchar(val & 0xff);
}
} }

View File

@@ -1,5 +1,5 @@
/*! \file pichunkstream.h /*! \file pichunkstream.h
* \ingroup Serialization * \ingroup Core
* \~\brief * \~\brief
* \~english Binary markup de/serializator stream * \~english Binary markup de/serializator stream
* \~russian Бинарный поток для де/сериализации с разметкой * \~russian Бинарный поток для де/сериализации с разметкой
@@ -29,12 +29,14 @@
#include "pibytearray.h" #include "pibytearray.h"
//! \ingroup Serialization //! \ingroup Core
//! \~\brief //! \~\brief
//! \~english Class for binary de/serialization. //! \~english Class for binary de/serialization.
//! \~russian Класс для бинарной де/сериализации. //! \~russian Класс для бинарной де/сериализации.
class PIP_EXPORT PIChunkStream { class PIP_EXPORT PIChunkStream
{
public: public:
//! \~english //! \~english
//! Version of data packing. Read-access %PIChunkStream automatic detect version, but write-access //! Version of data packing. Read-access %PIChunkStream automatic detect version, but write-access
//! %PIChunkStream by default write in new version, be careful! //! %PIChunkStream by default write in new version, be careful!
@@ -75,36 +77,21 @@ public:
//! \~english Returns chunk with ID "id" and value "data" for write to stream //! \~english Returns chunk with ID "id" and value "data" for write to stream
//! \~russian Возвращает чанк с ID "id" и значением "data" для записи в поток //! \~russian Возвращает чанк с ID "id" и значением "data" для записи в поток
template<typename T> template <typename T> static ChunkConst<T> chunk(int id, const T & data) {return ChunkConst<T>(id, data);}
static ChunkConst<T> chunk(int id, const T & data) {
return ChunkConst<T>(id, data);
}
//! \~english Add to this stream chunk with ID "id" and value "data" //! \~english Add to this stream chunk with ID "id" and value "data"
//! \~russian Добавляет в этот поток чанк с ID "id" и значением "data" //! \~russian Добавляет в этот поток чанк с ID "id" и значением "data"
template<typename T> template <typename T> PIChunkStream & add(int id, const T & data) {*this << ChunkConst<T>(id, data); return *this;}
PIChunkStream & add(int id, const T & data) {
*this << ChunkConst<T>(id, data);
return *this;
}
//! \~english //! \~english
//! Extract %PIByteArray from "stream" and set it current stream. //! Extract %PIByteArray from "data" and set it current stream.
//! If "read_all" then call \a readAll() after extract. //! If "read_all" then call \a readAll() after extract.
//! Returns if has data to read. //! Returns if has data to read.
//! \~russian //! \~russian
//! Извлекает %PIByteArray из "stream" и инициализирует им поток. //! Извлекает %PIByteArray из "data" и инициализирует им поток.
//! Если указан "read_all", то вызывает \a readAll() после инициализации. //! Если указан "read_all", то вызывает \a readAll() после инициализации.
//! Возвращает если ли данные для чтения. //! Возвращает если ли данные для чтения.
template<typename T> bool extract(PIByteArray & data, bool read_all = false);
bool extract(PIBinaryStream<T> & stream, bool read_all = false) {
stream >> tmp_data;
if (stream.wasReadError() || tmp_data.size_s() < 4) return false;
data_ = &tmp_data;
_init();
if (read_all) readAll();
return true;
}
void setSource(const PIByteArray & data); void setSource(const PIByteArray & data);
void setSource(PIByteArray * data); void setSource(PIByteArray * data);
@@ -137,19 +124,12 @@ public:
//! \~english Returns value of last readed chunk //! \~english Returns value of last readed chunk
//! \~russian Возвращает значение последнего прочитанного чанка //! \~russian Возвращает значение последнего прочитанного чанка
template <typename T> template <typename T>
T getData() const { T getData() const {T ret; PIByteArray s(last_data); s >> ret; return ret;}
T ret{};
PIByteArray s(last_data);
s >> ret;
return ret;
}
//! \~english Place value of last readed chunk into \"v\" //! \~english Place value of last readed chunk into \"v\"
//! \~russian Записывает значение последнего прочитанного чанка в \"v\" //! \~russian Записывает значение последнего прочитанного чанка в \"v\"
template <typename T> template <typename T>
void get(T & v) const { void get(T & v) const {v = getData<T>();}
v = getData<T>();
}
//! \~english Place value of chunk with ID \"id\" into \"v\". You should call \a readAll() before using this function! //! \~english Place value of chunk with ID \"id\" into \"v\". You should call \a readAll() before using this function!
//! \~russian Записывает значение чанка с ID \"id\" в \"v\". Необходимо вызвать \a readAll() перед использованием этого метода! //! \~russian Записывает значение чанка с ID \"id\" в \"v\". Необходимо вызвать \a readAll() перед использованием этого метода!
@@ -158,7 +138,8 @@ public:
CacheEntry pos = data_map.value(id); CacheEntry pos = data_map.value(id);
if (pos.start < 0 || pos.length == 0) return *this; if (pos.start < 0 || pos.length == 0) return *this;
PIByteArray ba(data_->data(pos.start), pos.length); PIByteArray ba(data_->data(pos.start), pos.length);
if (!ba.isEmpty()) ba >> v; if (!ba.isEmpty())
ba >> v;
return *this; return *this;
} }
@@ -184,7 +165,7 @@ private:
static uint readVInt(PIByteArray & s, uchar * bytes = 0); static uint readVInt(PIByteArray & s, uchar * bytes = 0);
static void writeVInt(PIByteArray & s, uint val); static void writeVInt(PIByteArray & s, uint val);
static int peekVInt(Version version_, uchar * data_, int sz, uint & ret); static int peekVInt(Version version_, PIByteArray * data_, int pos, PIByteArray & hdr, uint & ret);
void replaceChunk(int id, const PIByteArray & v); void replaceChunk(int id, const PIByteArray & v);
int last_id; int last_id;
@@ -193,10 +174,8 @@ private:
PIMap<int, CacheEntry> data_map; PIMap<int, CacheEntry> data_map;
bool first_byte_taken; bool first_byte_taken;
template<typename T> template <typename T> friend PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::Chunk<T> & c);
friend PIChunkStream & operator<<(PIChunkStream & s, const PIChunkStream::Chunk<T> & c); template <typename T> friend PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::ChunkConst<T> & c);
template<typename T>
friend PIChunkStream & operator<<(PIChunkStream & s, const PIChunkStream::ChunkConst<T> & c);
}; };
template <typename T> template <typename T>
@@ -204,9 +183,12 @@ PIChunkStream & operator<<(PIChunkStream & s, const PIChunkStream::Chunk<T> & c)
PIByteArray ba; PIByteArray ba;
ba << c.data; ba << c.data;
switch (s.version_) { switch (s.version_) {
case PIChunkStream::Version_1: (*(s.data_)) << c.id << ba; break; case PIChunkStream::Version_1:
(*(s.data_)) << c.id << ba;
break;
case PIChunkStream::Version_2: case PIChunkStream::Version_2:
if (s.data_->isEmpty()) (*(s.data_)) << uchar(uchar(s.version_) | 0x80); if (s.data_->isEmpty())
(*(s.data_)) << uchar(uchar(s.version_) | 0x80);
PIChunkStream::writeVInt(*(s.data_), c.id); PIChunkStream::writeVInt(*(s.data_), c.id);
PIChunkStream::writeVInt(*(s.data_), ba.size()); PIChunkStream::writeVInt(*(s.data_), ba.size());
s.data_->append(ba); s.data_->append(ba);
@@ -220,9 +202,12 @@ PIChunkStream & operator<<(PIChunkStream & s, const PIChunkStream::ChunkConst<T>
PIByteArray ba; PIByteArray ba;
ba << c.data; ba << c.data;
switch (s.version_) { switch (s.version_) {
case PIChunkStream::Version_1: (*(s.data_)) << c.id << ba; break; case PIChunkStream::Version_1:
(*(s.data_)) << c.id << ba;
break;
case PIChunkStream::Version_2: case PIChunkStream::Version_2:
if (s.data_->isEmpty()) (*(s.data_)) << uchar(uchar(s.version_) | 0x80); if (s.data_->isEmpty())
(*(s.data_)) << uchar(uchar(s.version_) | 0x80);
PIChunkStream::writeVInt(*(s.data_), c.id); PIChunkStream::writeVInt(*(s.data_), c.id);
PIChunkStream::writeVInt(*(s.data_), ba.size()); PIChunkStream::writeVInt(*(s.data_), ba.size());
s.data_->append(ba); s.data_->append(ba);

View File

@@ -18,7 +18,6 @@
*/ */
#include "picli.h" #include "picli.h"
#include "pisysteminfo.h" #include "pisysteminfo.h"
@@ -36,7 +35,7 @@
//! Этот класс предоставляет удобный механизм для разбора аргументов командной строки. //! Этот класс предоставляет удобный механизм для разбора аргументов командной строки.
//! Сперва необходимо добавить аргументы в %PICLI с помощью методов \a addArgument(). //! Сперва необходимо добавить аргументы в %PICLI с помощью методов \a addArgument().
//! Далее можно проверять аргументы на наличие в командной строке методом \a hasArgument(), //! Далее можно проверять аргументы на наличие в командной строке методом \a hasArgument(),
//! а также получать их значения при помощи \a argumentValue(). //! а также получить их значения при помощи \a argumentValue().
//! //!
//! \~english \section PICLI_sec1 Example //! \~english \section PICLI_sec1 Example
//! \~russian \section PICLI_sec1 Пример //! \~russian \section PICLI_sec1 Пример
@@ -53,12 +52,8 @@
//! piCout << "Value =" << cli.argumentValue("Value"); //! piCout << "Value =" << cli.argumentValue("Value");
//! return 0; //! return 0;
//! } //! }
//! \endcode
//! //!
//! \~english These executions are similar: //! These executions are similar:
//! \~russian Эти вызовы будут идентичны:
//!
//! \~\code
//! a.out -cd -v 10 //! a.out -cd -v 10
//! a.out --value 10 -dc //! a.out --value 10 -dc
//! a.out -c -v 10 -d //! a.out -c -v 10 -d
@@ -76,7 +71,8 @@ PICLI::PICLI(int argc, char * argv[]) {
_count_mand = 0; _count_mand = 0;
for (int i = 0; i < argc; ++i) for (int i = 0; i < argc; ++i)
_args_raw << argv[i]; _args_raw << argv[i];
if (argc > 0) PISystemInfo::instance()->execCommand = argv[0]; if (argc > 0)
PISystemInfo::instance()->execCommand = argv[0];
} }

View File

@@ -26,147 +26,77 @@
#ifndef PICLI_H #ifndef PICLI_H
#define PICLI_H #define PICLI_H
#include "piset.h"
#include "pistringlist.h" #include "pistringlist.h"
#include "piset.h"
//! \ingroup Core //! \ingroup Core
//! \~\brief //! \~\brief
//! \~english Command-Line parser. //! \~english Command-Line parser.
//! \~russian Парсер командной строки. //! \~russian Парсер командной строки.
class PIP_EXPORT PICLI { class PIP_EXPORT PICLI
{
public: public:
//! \~english Constructs %PICLI from "argc" and "argv" from "int main()" method.
//! \~russian Создает %PICLI из "argc" и "argv" из метода "int main()". //! \~english Constructor
//! \~russian Конструктор
PICLI(int argc, char * argv[]); PICLI(int argc, char * argv[]);
//! \~english Add argument with name "name", short key = name first letter and full key = name. //! \~english Add argument with name "name", short key = name first letter and full key = name
//! \~russian Добавляет аргумент с именем "name", коротким ключом = первой букве имени и полным ключом = имени. //! \~russian Добавляет аргумент с именем "name", коротким ключом = первой букве имени и полным ключом = имени
void addArgument(const PIString & name, bool value = false) { void addArgument(const PIString & name, bool value = false) {_args << Argument(name, name[0], name, value); needParse = true;}
_args << Argument(name, name[0], name, value);
needParse = true;
}
//! \~english Add argument with name "name", short key = "shortKey" and full key = name. //! \~english Add argument with name "name", short key = "shortKey" and full key = name
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени. //! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false) { void addArgument(const PIString & name, const PIChar & shortKey, bool value = false) {_args << Argument(name, shortKey, name, value); needParse = true;}
_args << Argument(name, shortKey, name, value);
needParse = true;
}
//! \~english Add argument with name "name", short key = "shortKey" and full key = name. //! \~english Add argument with name "name", short key = "shortKey" and full key = name
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени. //! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени
void addArgument(const PIString & name, const char * shortKey, bool value = false) { void addArgument(const PIString & name, const char * shortKey, bool value = false) {_args << Argument(name, PIChar(shortKey), name, value); needParse = true;}
_args << Argument(name, PIChar::fromUTF8(shortKey), name, value);
needParse = true;
}
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey". //! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey"
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey". //! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey"
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false) { void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, shortKey, fullKey, value); needParse = true;}
_args << Argument(name, shortKey, fullKey, value);
needParse = true;
}
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey". //! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey"
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey". //! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey"
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false) { void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, PIChar(shortKey), fullKey, value); needParse = true;}
_args << Argument(name, PIChar::fromUTF8(shortKey), fullKey, value);
needParse = true;
}
//! \~english Returns unparsed command-line argument by index "index". Index 0 is program execute command. //! \~english Returns unparsed command-line argument by index "index". Index 0 is program execute command
//! \~russian Возвращает исходный аргумент командной строки по индексу "index". Индекс 0 это команда вызова программы. //! \~russian Возвращает исходный аргумент командной строки по индексу "index". Индекс 0 это команда вызова программы
PIString rawArgument(int index) { PIString rawArgument(int index) {parse(); return _args_raw[index];}
parse(); PIString mandatoryArgument(int index) {parse(); return _args_mand[index];}
return _args_raw[index]; PIString optionalArgument(int index) {parse(); return _args_opt[index];}
}
PIString mandatoryArgument(int index) {
parse();
return _args_mand[index];
}
PIString optionalArgument(int index) {
parse();
return _args_opt[index];
}
//! \~english Returns unparsed command-line arguments. //! \~english Returns unparsed command-line arguments
//! \~russian Возвращает исходные аргументы командной строки. //! \~russian Возвращает исходные аргументы командной строки
const PIStringList & rawArguments() { const PIStringList & rawArguments() {parse(); return _args_raw;}
parse(); const PIStringList & mandatoryArguments() {parse(); return _args_mand;}
return _args_raw; const PIStringList & optionalArguments() {parse(); return _args_opt;}
}
const PIStringList & mandatoryArguments() {
parse();
return _args_mand;
}
const PIStringList & optionalArguments() {
parse();
return _args_opt;
}
//! \~english Returns program execute command without arguments. //! \~english Returns program execute command without arguments
//! \~russian Возвращает команду вызова программы без аргументов. //! \~russian Возвращает команду вызова программы без аргументов
PIString programCommand() { PIString programCommand() {parse(); return _args_raw.size() > 0 ? _args_raw.front() : PIString();}
parse();
return _args_raw.size() > 0 ? _args_raw.front() : PIString();
}
//! \~english Returns if argument "name" found. //! \~english Returns if argument "name" found
//! \~russian Возвращает найден ли аргумент "name". //! \~russian Возвращает найден ли аргумент "name"
bool hasArgument(const PIString & name) { bool hasArgument(const PIString & name) {parse(); piForeach (Argument & i, _args) if (i.name == name && i.found) return true; return false;}
parse();
piForeach(Argument & i, _args)
if (i.name == name && i.found) return true;
return false;
}
//! \~english Returns argument "name" value, or empty string if this is no value. //! \~english Returns argument "name" value, or empty string if this is no value
//! \~russian Возвращает значение аргумента "name" или пустую строку, если значения нет. //! \~russian Возвращает значение аргумента "name" или пустую строку, если значения нет
PIString argumentValue(const PIString & name) { PIString argumentValue(const PIString & name) {parse(); piForeach (Argument &i, _args) if (i.name == name && i.found) return i.value; return PIString();}
parse(); PIString argumentShortKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.short_key; return PIString();}
piForeach(Argument & i, _args) PIString argumentFullKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.full_key; return PIString();}
if (i.name == name && i.found) return i.value;
return PIString();
}
//! \~english Returns short key of argument "name", or empty string if this is no argument.
//! \~russian Возвращает короткий ключ аргумента "name" или пустую строку, если аргумента нет.
PIString argumentShortKey(const PIString & name) {
piForeach(Argument & i, _args)
if (i.name == name) return PIString(i.short_key);
return PIString();
}
//! \~english Returns full key of argument "name", or empty string if this is no argument.
//! \~russian Возвращает полный ключ аргумента "name" или пустую строку, если аргумента нет.
PIString argumentFullKey(const PIString & name) {
piForeach(Argument & i, _args)
if (i.name == name) return i.full_key;
return PIString();
}
const PIString & shortKeyPrefix() const {return _prefix_short;} const PIString & shortKeyPrefix() const {return _prefix_short;}
const PIString & fullKeyPrefix() const {return _prefix_full;} const PIString & fullKeyPrefix() const {return _prefix_full;}
int mandatoryArgumentsCount() const {return _count_mand;} int mandatoryArgumentsCount() const {return _count_mand;}
int optionalArgumentsCount() const {return _count_opt;} int optionalArgumentsCount() const {return _count_opt;}
void setShortKeyPrefix(const PIString & prefix) { void setShortKeyPrefix(const PIString & prefix) {_prefix_short = prefix; needParse = true;}
_prefix_short = prefix; void setFullKeyPrefix(const PIString & prefix) {_prefix_full = prefix; needParse = true;}
needParse = true; void setMandatoryArgumentsCount(const int count) {_count_mand = count; needParse = true;}
} void setOptionalArgumentsCount(const int count) {_count_opt = count; needParse = true;}
void setFullKeyPrefix(const PIString & prefix) {
_prefix_full = prefix;
needParse = true;
}
void setMandatoryArgumentsCount(const int count) {
_count_mand = count;
needParse = true;
}
void setOptionalArgumentsCount(const int count) {
_count_opt = count;
needParse = true;
}
bool debug() const {return debug_;} bool debug() const {return debug_;}
void setDebug(bool debug) {debug_ = debug;} void setDebug(bool debug) {debug_ = debug;}
@@ -176,13 +106,7 @@ public:
private: private:
struct Argument { struct Argument {
Argument() {has_value = found = false;} Argument() {has_value = found = false;}
Argument(const PIString & n, const PIChar & s, const PIString & f, bool v) { Argument(const PIString & n, const PIChar & s, const PIString & f, bool v) {name = n; short_key = s; full_key = f; has_value = v; found = false;}
name = n;
short_key = s;
full_key = f;
has_value = v;
found = false;
}
PIString name; PIString name;
PIChar short_key; PIChar short_key;
PIString full_key; PIString full_key;
@@ -198,6 +122,7 @@ private:
PIVector<Argument> _args; PIVector<Argument> _args;
int _count_mand, _count_opt; int _count_mand, _count_opt;
bool needParse, debug_; bool needParse, debug_;
}; };
#endif // PICLI_H #endif // PICLI_H

View File

@@ -49,7 +49,8 @@ PIStringList PICollection::groups() {
PIVector<const PIObject * > PICollection::groupElements(const PIString & group) { PIVector<const PIObject * > PICollection::groupElements(const PIString & group) {
PIVector<PICollection::Group> & cg(_groups()); PIVector<PICollection::Group> & cg(_groups());
piForeachC (Group & g, cg) piForeachC (Group & g, cg)
if (g.name == group) return g.elements; if (g.name == group)
return g.elements;
return PIVector<const PIObject * >(); return PIVector<const PIObject * >();
} }
@@ -61,7 +62,8 @@ bool PICollection::addToGroup(const PIString & group, const PIObject * element)
piForeach (Group & g, cg) piForeach (Group & g, cg)
if (g.name == group) { if (g.name == group) {
for (int i = 0; i < g.elements.size_s(); ++i) for (int i = 0; i < g.elements.size_s(); ++i)
if (PIString(g.elements[i]->className()) == n) return false; if (PIString(g.elements[i]->className()) == n)
return false;
g.elements << element; g.elements << element;
//piCout << "new group" << group << ", ok"; //piCout << "new group" << group << ", ok";
return true; return true;
@@ -81,7 +83,9 @@ PIVector<PICollection::Group> & PICollection::_groups() {
PICollection::CollectionAdder::CollectionAdder(const PIString & group, const PIObject * element, const PIString & name, bool own) { PICollection::CollectionAdder::CollectionAdder(const PIString & group, const PIObject * element, const PIString & name, bool own) {
if (!element) return; if (!element) return;
if (name.isNotEmpty()) const_cast<PIObject *>(element)->setName(name); if (name.isNotEmpty())
const_cast<PIObject * >(element)->setName(name);
bool added = PICollection::addToGroup(group, element); bool added = PICollection::addToGroup(group, element);
if (!added && own) delete element; if (!added && own)
delete element;
} }

View File

@@ -104,9 +104,9 @@
//! \~\brief //! \~\brief
//! \~english Helper to collect and retrieve classes to groups. //! \~english Helper to collect and retrieve classes to groups.
//! \~russian Помощник для создания и получения классов в группы. //! \~russian Помощник для создания и получения классов в группы.
class PIP_EXPORT PICollection { class PIP_EXPORT PICollection
{
friend class __PICollectionInitializer; friend class __PICollectionInitializer;
public: public:
PICollection() {;} PICollection() {;}
@@ -133,6 +133,7 @@ protected:
}; };
static PIVector<Group> & _groups(); static PIVector<Group> & _groups();
}; };
#endif // PICOLLECTION_H #endif // PICOLLECTION_H

View File

@@ -17,7 +17,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piconstchars.h" #include "piconstchars.h"
#include "pistring.h" #include "pistring.h"
@@ -43,13 +42,6 @@
//! //!
bool PIConstChars::contains(char c) const {
for (int i = 0; i < (int)len; ++i)
if (str[i] == c) return true;
return false;
}
bool PIConstChars::startsWith(const PIConstChars & str) const { bool PIConstChars::startsWith(const PIConstChars & str) const {
if (size() < str.size()) return false; if (size() < str.size()) return false;
return str == left(str.size()); return str == left(str.size());
@@ -84,7 +76,8 @@ PIConstChars PIConstChars::mid(const int start, const int len) const {
if (l < 0) { if (l < 0) {
return PIConstChars(str + s, (int)size() - s); return PIConstChars(str + s, (int)size() - s);
} else { } else {
if (l > (int)size() - s) l = (int)size() - s; if (l > (int)size() - s)
l = (int)size() - s;
return PIConstChars(str + s, l); return PIConstChars(str + s, l);
} }
return PIConstChars(""); return PIConstChars("");

View File

@@ -1,5 +1,5 @@
/*! \file piconstchars.h /*! \file piconstchars.h
* \ingroup Text * \ingroup Core
* \brief * \brief
* \~english C-String class * \~english C-String class
* \~russian Класс C-строки * \~russian Класс C-строки
@@ -29,12 +29,13 @@
#include "picout.h" #include "picout.h"
//! \ingroup Text //! \ingroup Core
//! \~\brief //! \~\brief
//! \~english C-String class. //! \~english C-String class.
//! \~russian Класс C-строки. //! \~russian Класс C-строки.
class PIP_EXPORT PIConstChars { class PIP_EXPORT PIConstChars {
public: public:
//! \~english Contructs an null string. //! \~english Contructs an null string.
//! \~russian Создает нулевую строку. //! \~russian Создает нулевую строку.
PIConstChars() {} PIConstChars() {}
@@ -85,10 +86,6 @@ public:
//! \~russian Возвращает \c true если строка непустая, т.е. длина > 0. //! \~russian Возвращает \c true если строка непустая, т.е. длина > 0.
inline bool isNotEmpty() const {return len > 0;} inline bool isNotEmpty() const {return len > 0;}
//! \~english Returns \c true if string contains character "c".
//! \~russian Возвращает \c true если строка содержит символ "c".
bool contains(char c) const;
//! \~english Returns characters length of string. //! \~english Returns characters length of string.
//! \~russian Возвращает длину строки в символах. //! \~russian Возвращает длину строки в символах.
inline size_t length() const {return len;} inline size_t length() const {return len;}
@@ -209,7 +206,8 @@ public:
if ( isNull() && s.isNull()) return false; if ( isNull() && s.isNull()) return false;
if ( isNull() && !s.isNull()) return true ; if ( isNull() && !s.isNull()) return true ;
if (!isNull() && s.isNull()) return false; if (!isNull() && s.isNull()) return false;
if (size() == s.size()) return strcmp(str, s.str) < 0; if (size() == s.size())
return strcmp(str, s.str) < 0;
return size() < s.size(); return size() < s.size();
} }
@@ -219,7 +217,8 @@ public:
if ( isNull() && s.isNull()) return false; if ( isNull() && s.isNull()) return false;
if ( isNull() && !s.isNull()) return false; if ( isNull() && !s.isNull()) return false;
if (!isNull() && s.isNull()) return true ; if (!isNull() && s.isNull()) return true ;
if (size() == s.size()) return strcmp(str, s.str) > 0; if (size() == s.size())
return strcmp(str, s.str) > 0;
return size() > s.size(); return size() > s.size();
} }
@@ -257,10 +256,7 @@ inline PICout operator<<(PICout s, const PIConstChars & v) {
} }
template<> template<> inline uint piHash(const PIConstChars & s) {return s.hash();}
inline uint piHash(const PIConstChars & s) {
return s.hash();
}
#endif // PICONSTCHARS_H #endif // PICONSTCHARS_H

View File

@@ -51,12 +51,11 @@
#ifndef PICOREMODULE_H #ifndef PICOREMODULE_H
#define PICOREMODULE_H #define PICOREMODULE_H
#include "pichunkstream.h"
#include "picli.h"
#include "picollection.h" #include "picollection.h"
#include "pijson.h"
#include "piobject.h" #include "piobject.h"
#include "pipropertystorage.h"
#include "pitime.h" #include "pitime.h"
#include "picli.h"
#include "pichunkstream.h"
#include "pipropertystorage.h"
#endif // PICOREMODULE_H #endif // PICOREMODULE_H

View File

@@ -16,21 +16,20 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picout.h"
#include "pibytearray.h"
#include "piincludes_p.h" #include "piincludes_p.h"
#include "piobject.h" #include "picout.h"
#include "pibytearray.h"
#include "pistack.h" #include "pistack.h"
#include "piobject.h"
#include "pistring_std.h" #include "pistring_std.h"
#ifdef HAS_LOCALE #ifdef HAS_LOCALE
# include <codecvt>
# include <locale> # include <locale>
# include <codecvt>
#endif #endif
#ifdef WINDOWS #ifdef WINDOWS
# include <wincon.h>
# include <windows.h> # include <windows.h>
# include <wingdi.h> # include <wingdi.h>
# include <wincon.h>
# define COMMON_LVB_UNDERSCORE 0x8000 # define COMMON_LVB_UNDERSCORE 0x8000
#endif #endif
@@ -107,13 +106,13 @@
class NotifierObject: public PIObject { class NotifierObject: public PIObject {
PIOBJECT(NotifierObject) PIOBJECT(NotifierObject)
public: public:
NotifierObject() {} NotifierObject() {}
EVENT2(finished, int, id, PIString *, buffer); EVENT2(finished, int, id, PIString*, buffer)
}; };
PICout::Notifier::Notifier() { PICout::Notifier::Notifier() {
o = new NotifierObject(); o = new NotifierObject();
} }
@@ -130,16 +129,12 @@ PIObject * PICout::Notifier::object() {
} }
using namespace PICoutManipulators; using namespace PICoutManipulators;
PIMutex & PICout::__mutex__() { PIMutex & PICout::__mutex__() {static PIMutex * ret = new PIMutex(); return *ret;}
static PIMutex * ret = new PIMutex(); PIString & PICout::__string__() {static PIString * ret = new PIString(); return *ret;}
return *ret;
}
PIString & PICout::__string__() {
static PIString * ret = new PIString();
return *ret;
}
PICout::OutputDevices PICout::devs = PICout::StdOut; PICout::OutputDevices PICout::devs = PICout::StdOut;
@@ -159,26 +154,27 @@ DWORD PICout::__Private__::smode = 0;
#endif #endif
PICout::PICout(int controls): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(controls) { PICout::PICout(int controls): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(controls) {
buffer_ = nullptr;
init(); init();
} }
PICout::PICout(bool active): fo_(true), cc_(false), fc_(false), act_(active), cnb_(10), co_(PICoutManipulators::DefaultControls) { PICout::PICout(bool active): fo_(true), cc_(false), fc_(false), act_(active), cnb_(10), co_(PICoutManipulators::DefaultControls) {
buffer_ = nullptr; buffer_ = nullptr;
if (act_) init(); if (act_)
init();
} }
PICout::PICout(const PICout & other) PICout::PICout(PIString * buffer, int id, PIFlags<PICoutManipulators::PICoutControl> controls): fo_(true), cc_(false),
: fo_(other.fo_) fc_(false), act_(true), cnb_(10), co_(controls) {
, cc_(true) init();
, fc_(false) buffer_ = buffer;
, act_(other.act_) id_ = id;
, cnb_(other.cnb_) }
, attr_(other.attr_)
, id_(other.id_)
, buffer_(other.buffer_) PICout::PICout(const PICout & other): fo_(other.fo_), cc_(true), fc_(false), act_(other.act_), cnb_(other.cnb_), attr_(other.attr_),
, co_(other.co_) {} id_(other.id_), buffer_(other.buffer_), co_(other.co_) {
}
PICout::~PICout() { PICout::~PICout() {
@@ -186,16 +182,14 @@ PICout::~PICout() {
if (fc_) applyFormat(PICoutManipulators::Default); if (fc_) applyFormat(PICoutManipulators::Default);
if (cc_) return; if (cc_) return;
newLine(); newLine();
if ((co_ & NoLock) != NoLock) { if ((co_ & NoLock) != NoLock)
PICout::__mutex__().unlock(); PICout::__mutex__().unlock();
} if (buffer_)
if (buffer_) {
((NotifierObject*)Notifier::object())->finished(id_, buffer_); ((NotifierObject*)Notifier::object())->finished(id_, buffer_);
} }
}
PICout & PICout::operator<<(PICoutAction v) { PICout PICout::operator <<(const PICoutAction v) {
if (!act_) return *this; if (!act_) return *this;
#ifdef WINDOWS #ifdef WINDOWS
CONSOLE_SCREEN_BUFFER_INFO sbi; CONSOLE_SCREEN_BUFFER_INFO sbi;
@@ -204,9 +198,8 @@ PICout & PICout::operator<<(PICoutAction v) {
#endif #endif
switch (v) { switch (v) {
case PICoutManipulators::Flush: case PICoutManipulators::Flush:
if (!buffer_ && isOutputDeviceActive(StdOut)) { if (!buffer_ && isOutputDeviceActive(StdOut))
std::cout << std::flush; std::cout << std::flush;
}
break; break;
case PICoutManipulators::Backspace: case PICoutManipulators::Backspace:
if (isOutputDeviceActive(StdOut)) { if (isOutputDeviceActive(StdOut)) {
@@ -274,15 +267,15 @@ PICout & PICout::operator<<(PICoutAction v) {
#endif #endif
} }
break; break;
case PICoutManipulators::SaveContol: saveControls(); break; case PICoutManipulators::SaveContol: saveControl(); break;
case PICoutManipulators::RestoreControl: restoreControls(); break; case PICoutManipulators::RestoreControl: restoreControl(); break;
default: break; default: break;
}; };
return *this; return *this;
} }
PICout & PICout::operator<<(PICoutManipulators::PICoutFormat v) { PICout PICout::operator <<(const PICoutManipulators::PICoutFormat v) {
switch (v) { switch (v) {
case PICoutManipulators::Bin: cnb_ = 2; break; case PICoutManipulators::Bin: cnb_ = 2; break;
case PICoutManipulators::Oct: cnb_ = 8; break; case PICoutManipulators::Oct: cnb_ = 8; break;
@@ -294,7 +287,7 @@ PICout & PICout::operator<<(PICoutManipulators::PICoutFormat v) {
} }
PICout & PICout::operator<<(PIFlags<PICoutManipulators::PICoutFormat> v) { PICout PICout::operator <<(const PIFlags<PICoutManipulators::PICoutFormat> & v) {
if (v[PICoutManipulators::Bin]) cnb_ = 2; if (v[PICoutManipulators::Bin]) cnb_ = 2;
if (v[PICoutManipulators::Oct]) cnb_ = 8; if (v[PICoutManipulators::Oct]) cnb_ = 8;
if (v[PICoutManipulators::Dec]) cnb_ = 10; if (v[PICoutManipulators::Dec]) cnb_ = 10;
@@ -324,175 +317,121 @@ PICout & PICout::operator<<(PIFlags<PICoutManipulators::PICoutFormat> v) {
return *this; return *this;
} }
#define PIINTCOUT(v) \
{ \ #define PICOUTTOTARGET(v) { \
if (!act_) return *this; \
space(); \
if (cnb_ == 10) { \
if (buffer_) {\ if (buffer_) {\
(*buffer_) += PIString::fromNumber(v); \ (*buffer_) << (v);\
} else {\ } else {\
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v);\ if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v);\
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() += PIString::fromNumber(v); \ if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() << (v);\
}\ }\
} else \ }
write(PIString::fromNumber(v, cnb_)); \
#define PINUMERICCOUT(v) { \
if (!act_) return *this; \
space(); \
if (cnb_ == 10) PICOUTTOTARGET(v) \
else write(PIString::fromNumber(v, cnb_)); \
return *this; \ return *this; \
} }
#define PIFLOATCOUT(v) \
{ \
if (buffer_) { \
(*buffer_) += PIString::fromNumber(v, 'g'); \
} else { \
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v); \
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() += PIString::fromNumber(v, 'g'); \
} \
} \
return *this;
PICout PICout::operator <<(const char * v) {if (!act_ || !v) return *this; if (v[0] == '\0') return *this; space(); quote(); PICOUTTOTARGET(v) quote(); return *this;}
PICout & PICout::operator<<(const PIString & v) { PICout PICout::operator <<(const bool v) {if (!act_) return *this; space(); if (v) PICOUTTOTARGET("true") else PICOUTTOTARGET("false") return *this;}
space();
quote();
write(v);
quote();
return *this;
}
PICout & PICout::operator<<(const char * v) { PICout PICout::operator <<(const char v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
if (!act_ || !v) return *this;
if (v[0] == '\0') return *this;
space();
quote();
write(v);
quote();
return *this;
}
PICout & PICout::operator<<(bool v) { PICout PICout::operator <<(const uchar v) {PINUMERICCOUT(ushort(v))}
PICout PICout::operator <<(const short int v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const ushort v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const int v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const uint v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const long v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const ulong v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const llong v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const ullong v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const float v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
PICout PICout::operator <<(const double v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
PICout PICout::operator <<(const void * v) {if (!act_) return *this; space(); PICOUTTOTARGET("0x") write(PIString::fromNumber(ullong(v), 16)); return *this;}
PICout PICout::operator <<(const PIObject * v) {
if (!act_) return *this; if (!act_) return *this;
space(); space();
if (v) if (v == 0) PICOUTTOTARGET("PIObject*(0x0)")
write("true");
else
write("false");
return *this;
}
PICout & PICout::operator<<(char v) {
if (!act_) return *this;
space();
write(v);
return *this;
}
PICout & PICout::operator<<(uchar v){PIINTCOUT(ushort(v))}
PICout & PICout::operator<<(short int v){PIINTCOUT(v)}
PICout & PICout::operator<<(ushort v){PIINTCOUT(v)}
PICout & PICout::operator<<(int v){PIINTCOUT(v)}
PICout & PICout::operator<<(uint v){PIINTCOUT(v)}
PICout & PICout::operator<<(long v){PIINTCOUT(v)}
PICout & PICout::operator<<(ulong v){PIINTCOUT(v)}
PICout & PICout::operator<<(llong v){PIINTCOUT(v)}
PICout & PICout::operator<<(ullong v){PIINTCOUT(v)}
PICout & PICout::operator<<(float v) {
if (!act_) return *this;
space();
PIFLOATCOUT(v)
}
PICout & PICout::operator<<(double v) {
if (!act_) return *this;
space();
PIFLOATCOUT(v)
}
PICout & PICout::operator<<(ldouble v) {
if (!act_) return *this;
space();
PIFLOATCOUT(v)
}
PICout & PICout::operator<<(const void * v) {
if (!act_) return *this;
space();
write("0x" + PIString::fromNumber(ullong(v), 16));
return *this;
}
PICout & PICout::operator<<(const PIObject * v) {
if (!act_) return *this;
space();
if (v == 0)
write("PIObject*(0x0)");
else { else {
write(v->className()); PICOUTTOTARGET(v->className())
write("*(0x" + PIString::fromNumber(ullong(v), 16) + ", \"" + v->name() + "\")"); PICOUTTOTARGET("*(0x")
write(PIString::fromNumber(ullong(v), 16));
PICOUTTOTARGET(", \"")
write(v->name());
PICOUTTOTARGET("\")")
} }
return *this; return *this;
} }
PICout & PICout::operator<<(PICoutSpecialChar v) { PICout PICout::operator <<(const PICoutSpecialChar v) {
if (!act_) return *this; if (!act_) return *this;
switch (v) { switch (v) {
case Null: case Null:
if (buffer_) { if (buffer_) {
(*buffer_) += PIChar(); (*buffer_) << PIChar();
} else { } else {
if (isOutputDeviceActive(StdOut)) std::cout << char(0); if (isOutputDeviceActive(StdOut)) std::cout << char(0);
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIChar(); if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar();
} }
break; break;
case NewLine: case NewLine:
if (buffer_) { if (buffer_) {
(*buffer_) += "\n"; (*buffer_) << "\n";
} else { } else {
if (isOutputDeviceActive(StdOut)) std::cout << '\n'; if (isOutputDeviceActive(StdOut)) std::cout << '\n';
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\n"; if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\n";
} }
fo_ = true; fo_ = true;
break; break;
case Tab: case Tab:
if (buffer_) { if (buffer_) {
(*buffer_) += "\t"; (*buffer_) << "\t";
} else { } else {
if (isOutputDeviceActive(StdOut)) std::cout << '\t'; if (isOutputDeviceActive(StdOut)) std::cout << '\t';
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\t"; if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\t";
} }
break; break;
case Esc: case Esc:
#ifdef CC_VC #ifdef CC_VC
if (buffer_) { if (buffer_) {
(*buffer_) += PIChar(27); (*buffer_) << PIChar(27);
} else { } else {
if (isOutputDeviceActive(StdOut)) std::cout << char(27); if (isOutputDeviceActive(StdOut)) std::cout << char(27);
if (isOutputDeviceActive(Buffer)) PICout::__string__() += PIChar(27); if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar(27);
} }
#else #else
if (buffer_) { if (buffer_) {
(*buffer_) += "\e"; (*buffer_) << "\e";
} else { } else {
if (isOutputDeviceActive(StdOut)) std::cout << '\e'; if (isOutputDeviceActive(StdOut)) std::cout << '\e';
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\e"; if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\e";
} }
#endif #endif
break; break;
case Quote: case Quote:
if (buffer_) { if (buffer_) {
(*buffer_) += "\""; (*buffer_) << "\"";
} else { } else {
if (isOutputDeviceActive(StdOut)) std::cout << '"'; if (isOutputDeviceActive(StdOut)) std::cout << '"';
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\""; if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\"";
} }
break; break;
}; };
@@ -500,14 +439,14 @@ PICout & PICout::operator<<(PICoutSpecialChar v) {
} }
PICout & PICout::saveControls() { PICout & PICout::saveControl() {
if (!act_) return *this; if (!act_) return *this;
PRIVATE->cos_.push(co_); PRIVATE->cos_.push(co_);
return *this; return *this;
} }
PICout & PICout::restoreControls() { PICout & PICout::restoreControl() {
if (!act_) return *this; if (!act_) return *this;
if (!PRIVATE->cos_.isEmpty()) { if (!PRIVATE->cos_.isEmpty()) {
co_ = PRIVATE->cos_.top(); co_ = PRIVATE->cos_.top();
@@ -517,6 +456,9 @@ PICout & PICout::restoreControls() {
} }
#undef PICOUTTOTARGET
#undef PINUMERICCOUT
//! \details //! \details
//! \~english //! \~english
//! If it is not a first output and control \a AddSpaces is set space character is put //! If it is not a first output and control \a AddSpaces is set space character is put
@@ -527,10 +469,10 @@ PICout & PICout::space() {
if (!act_) return *this; if (!act_) return *this;
if (!fo_ && co_[AddSpaces]) { if (!fo_ && co_[AddSpaces]) {
if (buffer_) { if (buffer_) {
(*buffer_) += " "; (*buffer_) << " ";
} else { } else {
if (isOutputDeviceActive(StdOut)) std::cout << ' '; if (isOutputDeviceActive(StdOut)) std::cout << ' ';
if (isOutputDeviceActive(Buffer)) PICout::__string__() += " "; if (isOutputDeviceActive(Buffer)) PICout::__string__() << " ";
} }
} }
fo_ = false; fo_ = false;
@@ -547,10 +489,10 @@ PICout & PICout::quote() {
if (!act_) return *this; if (!act_) return *this;
if (co_[AddQuotes]) { if (co_[AddQuotes]) {
if (buffer_) { if (buffer_) {
(*buffer_) += "\""; (*buffer_) << "\"";
} else { } else {
if (isOutputDeviceActive(StdOut)) std::cout << '"'; if (isOutputDeviceActive(StdOut)) std::cout << '"';
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\""; if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\"";
} }
} }
fo_ = false; fo_ = false;
@@ -567,10 +509,10 @@ PICout & PICout::newLine() {
if (!act_) return *this; if (!act_) return *this;
if (co_[AddNewLine]) { if (co_[AddNewLine]) {
if (buffer_) { if (buffer_) {
(*buffer_) += "\n"; (*buffer_) << "\n";
} else { } else {
if (isOutputDeviceActive(StdOut)) std::cout << std::endl; if (isOutputDeviceActive(StdOut)) std::cout << std::endl;
if (isOutputDeviceActive(Buffer)) PICout::__string__() += "\n"; if (isOutputDeviceActive(Buffer)) PICout::__string__() << "\n";
} }
} }
fo_ = false; fo_ = false;
@@ -578,18 +520,6 @@ PICout & PICout::newLine() {
} }
PICout & PICout::write(char c) {
if (!act_) return *this;
if (buffer_) {
buffer_->append(c);
} else {
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << c;
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(c);
}
return *this;
}
PICout & PICout::write(const char * str) { PICout & PICout::write(const char * str) {
if (!act_ || !str) return *this; if (!act_ || !str) return *this;
return write(str, strlen(str)); return write(str, strlen(str));
@@ -613,7 +543,8 @@ PICout & PICout::write(const PIString & s) {
if (buffer_) { if (buffer_) {
buffer_->append(s); buffer_->append(s);
} else { } else {
if (PICout::isOutputDeviceActive(PICout::StdOut)) stdoutPIString(s); if (PICout::isOutputDeviceActive(PICout::StdOut))
stdoutPIString(s);
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(s); if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(s);
} }
return *this; return *this;
@@ -623,11 +554,9 @@ PICout & PICout::write(const PIString & s) {
void PICout::stdoutPIString(const PIString & s) { void PICout::stdoutPIString(const PIString & s) {
#ifdef HAS_LOCALE #ifdef HAS_LOCALE
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> utf8conv; std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> utf8conv;
std::cout << utf8conv.to_bytes((char16_t *)&(const_cast<PIString &>(s).front()), std::cout << utf8conv.to_bytes((char16_t*)&(const_cast<PIString&>(s).front()), (char16_t*)&(const_cast<PIString&>(s).front()) + s.size());
(char16_t *)&(const_cast<PIString &>(s).front()) + s.size());
#else #else
for (PIChar c: s) for (PIChar c: s) std::wcout.put(c.toWChar());
std::wcout.put(c.toWChar());
#endif #endif
} }
@@ -642,11 +571,11 @@ void PICout::init() {
} }
attr_ = __Private__::dattr; attr_ = __Private__::dattr;
#endif #endif
buffer_ = nullptr;
id_ = 0; id_ = 0;
if ((co_ & NoLock) != NoLock) { if ((co_ & NoLock) != NoLock)
PICout::__mutex__().lock(); PICout::__mutex__().lock();
} }
}
void PICout::applyFormat(PICoutFormat f) { void PICout::applyFormat(PICoutFormat f) {
@@ -657,10 +586,7 @@ void PICout::applyFormat(PICoutFormat f) {
static int mask_fore = ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); static int mask_fore = ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
static int mask_back = ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); static int mask_back = ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
switch (f) { switch (f) {
case Bin: case Bin: case Oct: case Dec: case Hex: break;
case Oct:
case Dec:
case Hex: break;
case PICoutManipulators::Bold: attr_ |= FOREGROUND_INTENSITY; break; case PICoutManipulators::Bold: attr_ |= FOREGROUND_INTENSITY; break;
case PICoutManipulators::Underline: attr_ |= COMMON_LVB_UNDERSCORE; break; case PICoutManipulators::Underline: attr_ |= COMMON_LVB_UNDERSCORE; break;
case PICoutManipulators::Black: attr_ = (attr_ & mask_fore); break; case PICoutManipulators::Black: attr_ = (attr_ & mask_fore); break;
@@ -685,10 +611,7 @@ void PICout::applyFormat(PICoutFormat f) {
SetConsoleTextAttribute(__Private__::hOut, attr_); SetConsoleTextAttribute(__Private__::hOut, attr_);
#else #else
switch (f) { switch (f) {
case Bin: case Bin: case Oct: case Dec: case Hex: break;
case Oct:
case Dec:
case Hex: break;
case PICoutManipulators::Bold: printf("\e[1m"); break; case PICoutManipulators::Bold: printf("\e[1m"); break;
case PICoutManipulators::Faint: printf("\e[2m"); break; case PICoutManipulators::Faint: printf("\e[2m"); break;
case PICoutManipulators::Italic: printf("\e[3m"); break; case PICoutManipulators::Italic: printf("\e[3m"); break;
@@ -717,17 +640,24 @@ void PICout::applyFormat(PICoutFormat f) {
} }
PIString PICout::getBuffer() { bool PICout::setBufferActive(bool on, bool clear) {
PIMutexLocker ml(PICout::__mutex__()); PIMutexLocker ml(PICout::__mutex__());
PIString ret = PICout::__string__(); bool ret = isBufferActive();
if (clear) PICout::__string__().clear();
setOutputDevice(Buffer, on);
return ret; return ret;
} }
PIString PICout::getBufferAndClear() { bool PICout::isBufferActive() {
return isOutputDeviceActive(Buffer);
}
PIString PICout::buffer(bool clear) {
PIMutexLocker ml(PICout::__mutex__()); PIMutexLocker ml(PICout::__mutex__());
PIString ret = PICout::__string__(); PIString ret = PICout::__string__();
PICout::__string__().clear(); if (clear) PICout::__string__().clear();
return ret; return ret;
} }
@@ -753,11 +683,3 @@ void PICout::setOutputDevices(PICout::OutputDevices d) {
bool PICout::isOutputDeviceActive(PICout::OutputDevice d) { bool PICout::isOutputDeviceActive(PICout::OutputDevice d) {
return devs[d]; return devs[d];
} }
PICout PICout::withExternalBuffer(PIString * buffer, int id, PIFlags<PICoutManipulators::PICoutControl> controls) {
PICout c(controls);
c.buffer_ = buffer;
c.id_ = id;
return c;
}

View File

@@ -41,9 +41,7 @@
#else #else
# define piCout PICout(piDebug) # define piCout PICout(piDebug)
# define piCoutObj \ # define piCoutObj PICout(piDebug && debug()) << (PIStringAscii("[") + className() + (name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
PICout(piDebug && debug()) << (PIStringAscii("[") + className() + \
(name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
#endif #endif
@@ -75,8 +73,7 @@ enum PICoutAction {
ClearLine /*! \~english Clear current line \~russian Очистить текущую строку */, ClearLine /*! \~english Clear current line \~russian Очистить текущую строку */,
ClearScreen /*! \~english Clear the screen \~russian Очистить экран */, ClearScreen /*! \~english Clear the screen \~russian Очистить экран */,
SaveContol /*! \~english Save control flags, equivalent to \a saveControl() \~russian Сохранить флаги, аналогично \a saveControl() */, SaveContol /*! \~english Save control flags, equivalent to \a saveControl() \~russian Сохранить флаги, аналогично \a saveControl() */,
RestoreControl /*! \~english Restore control flags, equivalent to \a restoreControl() \~russian Восстановить флаги, аналогично \a RestoreControl /*! \~english Restore control flags, equivalent to \a restoreControl() \~russian Восстановить флаги, аналогично \a restoreControl() */
restoreControl() */
}; };
//! \~english Enum contains control of PICout //! \~english Enum contains control of PICout
@@ -123,7 +120,9 @@ enum PICoutFormat {
}; };
typedef PIFlags<PICoutControl> PICoutControls; typedef PIFlags<PICoutControl> PICoutControls;
} // namespace PICoutManipulators }
//! \ingroup Core //! \ingroup Core
@@ -132,6 +131,7 @@ typedef PIFlags<PICoutControl> PICoutControls;
//! \~russian Универсальный вывод в консоль. //! \~russian Универсальный вывод в консоль.
class PIP_EXPORT PICout { class PIP_EXPORT PICout {
public: public:
//! \~english Default constructor with default features (AddSpaces and AddNewLine) //! \~english Default constructor with default features (AddSpaces and AddNewLine)
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine) //! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine)
PICout(int controls = PICoutManipulators::DefaultControls); PICout(int controls = PICoutManipulators::DefaultControls);
@@ -140,6 +140,10 @@ public:
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine), но если не \"active\" то будет неактивным //! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine), но если не \"active\" то будет неактивным
PICout(bool active); PICout(bool active);
//! \~english Construct with external buffer and ID "id". See \a Notifier for details
//! \~russian Конструктор с внешним буфером и ID "id". Подробнее \a Notifier
PICout(PIString * buffer, int id = 0, PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces | PICoutManipulators::AddNewLine);
PICout(const PICout & other); PICout(const PICout & other);
~PICout(); ~PICout();
@@ -154,7 +158,6 @@ public:
//! \~english Object that emit events from %PICout //! \~english Object that emit events from %PICout
//! \~russian Объект, который посылает события от %PICout //! \~russian Объект, который посылает события от %PICout
static PIObject * object(); static PIObject * object();
private: private:
Notifier(); Notifier();
PIObject * o; PIObject * o;
@@ -173,123 +176,104 @@ public:
//! \~english Output operator for strings with <tt>"const char * "</tt> type //! \~english Output operator for strings with <tt>"const char * "</tt> type
//! \~russian Оператор вывода для строк <tt>"const char * "</tt> //! \~russian Оператор вывода для строк <tt>"const char * "</tt>
PICout & operator<<(const char * v); PICout operator <<(const char * v);
//! \~english Output operator for \a PIString // ! Output operator for strings with <tt>"std::string"</tt> type
//! \~russian Оператор вывода для \a PIString //PICout operator <<(const std::string & v);
PICout & operator<<(const PIString & v);
//! \~english Output operator for boolean values //! \~english Output operator for boolean values
//! \~russian Оператор вывода для логических значений //! \~russian Оператор вывода для логических значений
PICout & operator<<(bool v); PICout operator <<(const bool v);
//! \~english Output operator for <tt>"char"</tt> values //! \~english Output operator for <tt>"char"</tt> values
//! \~russian Оператор вывода для <tt>"char"</tt> значений //! \~russian Оператор вывода для <tt>"char"</tt> значений
PICout & operator<<(char v); PICout operator <<(const char v);
//! \~english Output operator for <tt>"unsigned char"</tt> values //! \~english Output operator for <tt>"unsigned char"</tt> values
//! \~russian Оператор вывода для <tt>"unsigned char"</tt> значений //! \~russian Оператор вывода для <tt>"unsigned char"</tt> значений
PICout & operator<<(uchar v); PICout operator <<(const uchar v);
//! \~english Output operator for <tt>"short"</tt> values //! \~english Output operator for <tt>"short"</tt> values
//! \~russian Оператор вывода для <tt>"short"</tt> значений //! \~russian Оператор вывода для <tt>"short"</tt> значений
PICout & operator<<(short v); PICout operator <<(const short v);
//! \~english Output operator for <tt>"unsigned short"</tt> values //! \~english Output operator for <tt>"unsigned short"</tt> values
//! \~russian Оператор вывода для <tt>"unsigned short"</tt> значений //! \~russian Оператор вывода для <tt>"unsigned short"</tt> значений
PICout & operator<<(ushort v); PICout operator <<(const ushort v);
//! \~english Output operator for <tt>"int"</tt> values //! \~english Output operator for <tt>"int"</tt> values
//! \~russian Оператор вывода для <tt>"int"</tt> значений //! \~russian Оператор вывода для <tt>"int"</tt> значений
PICout & operator<<(int v); PICout operator <<(const int v);
//! \~english Output operator for <tt>"unsigned int"</tt> values //! \~english Output operator for <tt>"unsigned int"</tt> values
//! \~russian Оператор вывода для <tt>"unsigned int"</tt> значений //! \~russian Оператор вывода для <tt>"unsigned int"</tt> значений
PICout & operator<<(uint v); PICout operator <<(const uint v);
//! \~english Output operator for <tt>"long"</tt> values //! \~english Output operator for <tt>"long"</tt> values
//! \~russian Оператор вывода для <tt>"long"</tt> значений //! \~russian Оператор вывода для <tt>"long"</tt> значений
PICout & operator<<(long v); PICout operator <<(const long v);
//! \~english Output operator for <tt>"unsigned long"</tt> values //! \~english Output operator for <tt>"unsigned long"</tt> values
//! \~russian Оператор вывода для <tt>"unsigned long"</tt> значений //! \~russian Оператор вывода для <tt>"unsigned long"</tt> значений
PICout & operator<<(ulong v); PICout operator <<(const ulong v);
//! \~english Output operator for <tt>"long long"</tt> values //! \~english Output operator for <tt>"long long"</tt> values
//! \~russian Оператор вывода для <tt>"long long"</tt> значений //! \~russian Оператор вывода для <tt>"long long"</tt> значений
PICout & operator<<(llong v); PICout operator <<(const llong v);
//! \~english Output operator for <tt>"unsigned long long"</tt> values //! \~english Output operator for <tt>"unsigned long long"</tt> values
//! \~russian Оператор вывода для <tt>"unsigned long long"</tt> значений //! \~russian Оператор вывода для <tt>"unsigned long long"</tt> значений
PICout & operator<<(ullong v); PICout operator <<(const ullong v);
//! \~english Output operator for <tt>"float"</tt> values //! \~english Output operator for <tt>"float"</tt> values
//! \~russian Оператор вывода для <tt>"float"</tt> значений //! \~russian Оператор вывода для <tt>"float"</tt> значений
PICout & operator<<(float v); PICout operator <<(const float v);
//! \~english Output operator for <tt>"double"</tt> values //! \~english Output operator for <tt>"double"</tt> values
//! \~russian Оператор вывода для <tt>"double"</tt> значений //! \~russian Оператор вывода для <tt>"double"</tt> значений
PICout & operator<<(double v); PICout operator <<(const double v);
//! \~english Output operator for <tt>"ldouble"</tt> values
//! \~russian Оператор вывода для <tt>"ldouble"</tt> значений
PICout & operator<<(ldouble v);
//! \~english Output operator for pointers //! \~english Output operator for pointers
//! \~russian Оператор вывода для указателей //! \~russian Оператор вывода для указателей
PICout & operator<<(const void * v); PICout operator <<(const void * v);
//! \~english Output operator for PIObject and ancestors //! \~english Output operator for PIObject and ancestors
//! \~russian Оператор вывода для PIObject и наследников //! \~russian Оператор вывода для PIObject и наследников
PICout & operator<<(const PIObject * v); PICout operator <<(const PIObject * v);
//! \~english Output operator for \a PICoutSpecialChar values //! \~english Output operator for \a PICoutSpecialChar values
//! \~russian Оператор вывода для \a PICoutSpecialChar //! \~russian Оператор вывода для \a PICoutSpecialChar
PICout & operator<<(PICoutManipulators::PICoutSpecialChar v); PICout operator <<(const PICoutManipulators::PICoutSpecialChar v);
//! \~english Output operator for \a PIFlags<PICoutFormat> values //! \~english Output operator for \a PIFlags<PICoutFormat> values
//! \~russian Оператор вывода для \a PIFlags<PICoutFormat> //! \~russian Оператор вывода для \a PIFlags<PICoutFormat>
PICout & operator<<(PIFlags<PICoutManipulators::PICoutFormat> v); PICout operator <<(const PIFlags<PICoutManipulators::PICoutFormat> & v);
//! \~english Output operator for \a PICoutFormat values //! \~english Output operator for \a PICoutFormat values
//! \~russian Оператор вывода для \a PICoutFormat //! \~russian Оператор вывода для \a PICoutFormat
PICout & operator<<(PICoutManipulators::PICoutFormat v); PICout operator <<(const PICoutManipulators::PICoutFormat v);
//! \~english Do some action //! \~english Do some action
//! \~russian Делает действие //! \~russian Делает действие
PICout & operator<<(PICoutManipulators::PICoutAction v); PICout operator <<(const PICoutManipulators::PICoutAction v);
//! \~english Set control flag "c" is "on" state //! \~english Set control flag "c" is "on" state
//! \~russian Установить флаг "c" в "on" состояние //! \~russian Установить флаг "c" в "on" состояние
PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true) { PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true) {co_.setFlag(c, on); return *this;}
co_.setFlag(c, on);
return *this;
}
//! \~english Set control flags "c" //! \~english Set control flags "c" and if "save" exec \a saveControl()
//! \~russian Установить флаги "c" //! \~russian Установить флаг "c" и если "save" то выполнить \a saveControl()
PICout & setControls(PICoutManipulators::PICoutControls c) { PICout & setControl(PICoutManipulators::PICoutControls c, bool save = false) {if (save) saveControl(); co_ = c; return *this;}
co_ = c;
return *this;
}
//! \~english Exec \a saveControls() and set control flags to "c"
//! \~russian Иыполнить \a saveControls() и Установить флаги "c"
PICout & saveAndSetControls(PICoutManipulators::PICoutControls c) {
saveControls();
co_ = c;
return *this;
}
//! \~english Save control flags to internal stack //! \~english Save control flags to internal stack
//! \~russian Сохраняет состояние флагов во внутренний стек //! \~russian Сохраняет состояние флагов во внутренний стек
//! \~\sa \a restoreControl() //! \~\sa \a restoreControl()
PICout & saveControls(); PICout & saveControl();
//! \~english Restore control flags from internal stack //! \~english Restore control flags from internal stack
//! \~russian Восстанавливает состояние флагов из внутреннего стека //! \~russian Восстанавливает состояние флагов из внутреннего стека
//! \~\sa \a saveControl() //! \~\sa \a saveControl()
PICout & restoreControls(); PICout & restoreControl();
//! \~english Conditional put space character to output //! \~english Conditional put space character to output
//! \~russian Условно добавляет пробел //! \~russian Условно добавляет пробел
@@ -303,10 +287,6 @@ public:
//! \~russian Условно добавляет новую строку //! \~russian Условно добавляет новую строку
PICout & newLine(); PICout & newLine();
//! \~english Write char
//! \~russian Пишет символ
PICout & write(char c);
//! \~english Write raw data //! \~english Write raw data
//! \~russian Пишет сырые символы //! \~russian Пишет сырые символы
PICout & write(const char * str); PICout & write(const char * str);
@@ -323,13 +303,17 @@ public:
//! \~russian Вывод \a PIString в stdout //! \~russian Вывод \a PIString в stdout
static void stdoutPIString(const PIString & s); static void stdoutPIString(const PIString & s);
//! \~english Returns internal PIString buffer //! \~english Set output device to \a PICout::Buffer and if "clear" clear it
//! \~russian Возвращает внутренний PIString буфер //! \~russian Устанавливает устройство вывода на \a PICout::Buffer и если "clear" то очищает его
static PIString getBuffer(); static bool setBufferActive(bool on, bool clear = false);
//! \~english Returns internal PIString buffer and clear it //! \~english Equivalent to \a isOutputDeviceActive(OutputDevice)
//! \~russian Возвращает внутренний PIString буфер и очищает его //! \~russian Аналог \a isOutputDeviceActive(OutputDevice)
static PIString getBufferAndClear(); static bool isBufferActive();
//! \~english Returns internal PIString buffer and if "clear" clear it
//! \~russian Возвращает внутренний PIString буфер и если "clear" то очищает его
static PIString buffer(bool clear = false);
//! \~english Clear internal PIString buffer //! \~english Clear internal PIString buffer
//! \~russian Очищает внутренний PIString буфер //! \~russian Очищает внутренний PIString буфер
@@ -340,34 +324,14 @@ public:
//! \~russian Устройство вывода "d" устанавливается в "on". Возвращает было ли устройство активно //! \~russian Устройство вывода "d" устанавливается в "on". Возвращает было ли устройство активно
static bool setOutputDevice(OutputDevice d, bool on = true); static bool setOutputDevice(OutputDevice d, bool on = true);
//! \~english Turn on output device "d". Returns if it was enabled
//! \~russian Включает устройство вывода "d". Возвращает было ли устройство активно
static bool enableOutputDevice(OutputDevice d) { return setOutputDevice(d, true); }
//! \~english Turn off output device "d". Returns if it was enabled
//! \~russian Выключает устройство вывода "d". Возвращает было ли устройство активно
static bool disableOutputDevice(OutputDevice d) { return setOutputDevice(d, false); }
//! \~english Set output to devices to "d" //! \~english Set output to devices to "d"
//! \~russian Устанавливает устройства вывода "d" //! \~russian Устанавливает устройства вывода "d"
static void setOutputDevices(OutputDevices d); static void setOutputDevices(OutputDevices d);
//! \~english Returns current output devices
//! \~russian Возвращает текущие устройства вывода
static OutputDevices currentOutputDevices() { return devs; }
//! \~english Returns if output device "d" is active //! \~english Returns if output device "d" is active
//! \~russian Возвращает активно ли устройство вывода "d" //! \~russian Возвращает активно ли устройство вывода "d"
static bool isOutputDeviceActive(OutputDevice d); static bool isOutputDeviceActive(OutputDevice d);
//! \~english Construct with external buffer and ID "id". See \a Notifier for details
//! \~russian Конструктор с внешним буфером и ID "id". Подробнее \a Notifier
static PICout withExternalBuffer(PIString * buffer,
int id = 0,
PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces |
PICoutManipulators::AddNewLine);
static PIMutex & __mutex__(); static PIMutex & __mutex__();
static PIString & __string__(); static PIString & __string__();

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