Merge remote-tracking branch 'upstream/for-core-4.0.x' into jmj_bsip64
This commit is contained in:
commit
dbf4b99e3e
103 changed files with 2170 additions and 3907 deletions
159
CMakeLists.txt
159
CMakeLists.txt
|
|
@ -1,12 +1,17 @@
|
||||||
#
|
#
|
||||||
# Defines fc library target.
|
# Defines fc library target.
|
||||||
|
|
||||||
|
CMAKE_MINIMUM_REQUIRED( VERSION 3.2 FATAL_ERROR )
|
||||||
PROJECT( fc )
|
PROJECT( fc )
|
||||||
CMAKE_MINIMUM_REQUIRED( VERSION 3.1 )
|
|
||||||
|
|
||||||
set( CMAKE_CXX_STANDARD 14 )
|
set( CMAKE_CXX_STANDARD 14 )
|
||||||
SET( CMAKE_CXX_STANDARD_REQUIRED ON )
|
SET( CMAKE_CXX_STANDARD_REQUIRED ON )
|
||||||
set( CMAKE_CXX_EXTENSIONS OFF )
|
|
||||||
|
if( "${CMAKE_CXX_COMPILER_ID}" MATCHES "^(Apple)?Clang|GNU$" )
|
||||||
|
set( CMAKE_CXX_EXTENSIONS ON ) # for __int128 support
|
||||||
|
else( "${CMAKE_CXX_COMPILER_ID}" MATCHES "^(Apple)?Clang|GNU$" )
|
||||||
|
set( CMAKE_CXX_EXTENSIONS OFF )
|
||||||
|
endif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "^(Apple)?Clang|GNU$" )
|
||||||
|
|
||||||
MESSAGE(STATUS "Configuring project fc located in: ${CMAKE_CURRENT_SOURCE_DIR}")
|
MESSAGE(STATUS "Configuring project fc located in: ${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
SET( CMAKE_AUTOMOC OFF )
|
SET( CMAKE_AUTOMOC OFF )
|
||||||
|
|
@ -20,7 +25,6 @@ INCLUDE( VersionMacros )
|
||||||
INCLUDE( SetupTargetMacros )
|
INCLUDE( SetupTargetMacros )
|
||||||
INCLUDE(GetGitRevisionDescription)
|
INCLUDE(GetGitRevisionDescription)
|
||||||
INCLUDE(CheckLibraryExists)
|
INCLUDE(CheckLibraryExists)
|
||||||
INCLUDE(CheckLibcxxAtomic)
|
|
||||||
|
|
||||||
get_git_head_revision(GIT_REFSPEC FC_GIT_REVISION_SHA)
|
get_git_head_revision(GIT_REFSPEC FC_GIT_REVISION_SHA)
|
||||||
get_git_unix_timestamp(FC_GIT_REVISION_UNIX_TIMESTAMP)
|
get_git_unix_timestamp(FC_GIT_REVISION_UNIX_TIMESTAMP)
|
||||||
|
|
@ -36,15 +40,13 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
set(platformBitness 64)
|
set(platformBitness 64)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
SET (ORIGINAL_LIB_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
|
||||||
|
|
||||||
SET(BOOST_COMPONENTS)
|
SET(BOOST_COMPONENTS)
|
||||||
LIST(APPEND BOOST_COMPONENTS thread date_time filesystem system program_options chrono unit_test_framework context iostreams regex)
|
LIST(APPEND BOOST_COMPONENTS coroutine thread date_time filesystem system program_options chrono unit_test_framework context iostreams regex)
|
||||||
# boost::endian is also required, but FindBoost can't handle header-only libs
|
# boost::endian is also required, but FindBoost can't handle header-only libs
|
||||||
SET( Boost_USE_STATIC_LIBS ON CACHE STRING "ON or OFF" )
|
SET( Boost_USE_STATIC_LIBS ON CACHE STRING "ON or OFF" )
|
||||||
|
|
||||||
# Configure secp256k1-zkp
|
# Configure secp256k1-zkp
|
||||||
if ( MSVC )
|
if ( WIN32 )
|
||||||
# autoconf won't work here, hard code the defines
|
# autoconf won't work here, hard code the defines
|
||||||
set( SECP256K1_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp" )
|
set( SECP256K1_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp" )
|
||||||
|
|
||||||
|
|
@ -60,18 +62,9 @@ if ( MSVC )
|
||||||
USE_SCALAR_8X32
|
USE_SCALAR_8X32
|
||||||
USE_SCALAR_INV_BUILTIN )
|
USE_SCALAR_INV_BUILTIN )
|
||||||
set_target_properties( secp256k1 PROPERTIES COMPILE_DEFINITIONS "${SECP256K1_BUILD_DEFINES}" LINKER_LANGUAGE C )
|
set_target_properties( secp256k1 PROPERTIES COMPILE_DEFINITIONS "${SECP256K1_BUILD_DEFINES}" LINKER_LANGUAGE C )
|
||||||
else ( MSVC )
|
else ( WIN32 )
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
if ( MINGW )
|
|
||||||
ExternalProject_Add( project_secp256k1
|
|
||||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp
|
|
||||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp
|
|
||||||
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp --with-bignum=no --host=x86_64-w64-mingw32
|
|
||||||
BUILD_COMMAND make
|
|
||||||
INSTALL_COMMAND true
|
|
||||||
BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp/src/project_secp256k1-build/.libs/libsecp256k1.a
|
|
||||||
)
|
|
||||||
else ( MINGW )
|
|
||||||
ExternalProject_Add( project_secp256k1
|
ExternalProject_Add( project_secp256k1
|
||||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp
|
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp
|
||||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp
|
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp
|
||||||
|
|
@ -80,7 +73,7 @@ else ( MSVC )
|
||||||
INSTALL_COMMAND true
|
INSTALL_COMMAND true
|
||||||
BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp/src/project_secp256k1-build/.libs/libsecp256k1.a
|
BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp/src/project_secp256k1-build/.libs/libsecp256k1.a
|
||||||
)
|
)
|
||||||
endif ( MINGW )
|
|
||||||
ExternalProject_Add_Step(project_secp256k1 autogen
|
ExternalProject_Add_Step(project_secp256k1 autogen
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp
|
||||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp/autogen.sh
|
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp/autogen.sh
|
||||||
|
|
@ -94,25 +87,13 @@ else ( MSVC )
|
||||||
set_property(TARGET secp256k1 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp/include)
|
set_property(TARGET secp256k1 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp/include)
|
||||||
add_dependencies(secp256k1 project_secp256k1)
|
add_dependencies(secp256k1 project_secp256k1)
|
||||||
install( FILES ${binary_dir}/.libs/libsecp256k1${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib/cryptonomex )
|
install( FILES ${binary_dir}/.libs/libsecp256k1${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib/cryptonomex )
|
||||||
endif ( MSVC )
|
endif ( WIN32 )
|
||||||
# End configure secp256k1-zkp
|
# End configure secp256k1-zkp
|
||||||
|
|
||||||
# Configure editline
|
# Configure editline
|
||||||
if ( MSVC )
|
if ( NOT WIN32 )
|
||||||
# # autoconf won't work here, hard code the defines
|
|
||||||
# set( EDITLINE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline" )
|
|
||||||
#
|
|
||||||
# file( GLOB EDITLINE_SOURCES "${EDITLINE_DIR}/src/editline.c" )
|
|
||||||
# add_library( editline ${EDITLINE_SOURCES} )
|
|
||||||
#
|
|
||||||
# target_include_directories( editline PRIVATE "${EDITLINE_DIR}" PUBLIC "${EDITLINE_DIR}/include" )
|
|
||||||
#
|
|
||||||
# set_target_properties( editline PROPERTIES COMPILE_DEFINITIONS LINKER_LANGUAGE C )
|
|
||||||
else ( MSVC )
|
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
if ( MINGW )
|
|
||||||
# Editline is not avalible in MINGW
|
|
||||||
else ( MINGW )
|
|
||||||
ExternalProject_Add( project_editline
|
ExternalProject_Add( project_editline
|
||||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline
|
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline
|
||||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline
|
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline
|
||||||
|
|
@ -120,7 +101,8 @@ else ( MSVC )
|
||||||
BUILD_COMMAND make
|
BUILD_COMMAND make
|
||||||
INSTALL_COMMAND true
|
INSTALL_COMMAND true
|
||||||
BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline/src/project_editline-build/src/.libs/libeditline.a
|
BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline/src/project_editline-build/src/.libs/libeditline.a
|
||||||
)
|
)
|
||||||
|
|
||||||
ExternalProject_Add_Step(project_editline autogen
|
ExternalProject_Add_Step(project_editline autogen
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline
|
||||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/autogen.sh
|
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/autogen.sh
|
||||||
|
|
@ -132,8 +114,7 @@ else ( MSVC )
|
||||||
set_property(TARGET editline PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/include)
|
set_property(TARGET editline PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/include)
|
||||||
add_dependencies(editline project_editline)
|
add_dependencies(editline project_editline)
|
||||||
install( FILES ${binary_dir}/src/.libs/libeditline${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib/cryptonomex )
|
install( FILES ${binary_dir}/src/.libs/libeditline${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib/cryptonomex )
|
||||||
endif ( MINGW )
|
endif ( NOT WIN32 )
|
||||||
endif ( MSVC )
|
|
||||||
# End configure editline
|
# End configure editline
|
||||||
|
|
||||||
IF( WIN32 )
|
IF( WIN32 )
|
||||||
|
|
@ -142,42 +123,31 @@ IF( WIN32 )
|
||||||
set( RPCRT4 rpcrt4 )
|
set( RPCRT4 rpcrt4 )
|
||||||
|
|
||||||
#boost
|
#boost
|
||||||
SET(BOOST_ROOT $ENV{BOOST_ROOT})
|
if ($ENV{BOOST_ROOT})
|
||||||
# set(Boost_USE_DEBUG_PYTHON ON)
|
SET(BOOST_ROOT $ENV{BOOST_ROOT})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(Boost_USE_DEBUG_PYTHON ON)
|
||||||
set(Boost_USE_MULTITHREADED ON)
|
set(Boost_USE_MULTITHREADED ON)
|
||||||
set(BOOST_ALL_DYN_LINK OFF) # force dynamic linking for all libraries
|
set(BOOST_ALL_DYN_LINK OFF) # force dynamic linking for all libraries
|
||||||
|
|
||||||
FIND_PACKAGE(Boost 1.53 REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
LIST(APPEND PLATFORM_SPECIFIC_LIBS ws2_32 crypt32 mswsock userenv)
|
||||||
# For Boost 1.53 on windows, coroutine was not in BOOST_LIBRARYDIR and do not need it to build, but if boost versin >= 1.54, find coroutine otherwise will cause link errors
|
|
||||||
IF(NOT "${Boost_VERSION}" MATCHES "1.53(.*)")
|
|
||||||
SET(BOOST_LIBRARIES_TEMP ${Boost_LIBRARIES})
|
|
||||||
FIND_PACKAGE(Boost 1.54 REQUIRED COMPONENTS coroutine)
|
|
||||||
LIST(APPEND BOOST_COMPONENTS coroutine)
|
|
||||||
SET(Boost_LIBRARIES ${BOOST_LIBRARIES_TEMP} ${Boost_LIBRARIES})
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
LIST(APPEND PLATFORM_SPECIFIC_LIBS wsock32.lib ws2_32.lib userenv.lib)
|
|
||||||
# iphlpapi.lib
|
# iphlpapi.lib
|
||||||
|
|
||||||
ELSE(WIN32)
|
|
||||||
MESSAGE(STATUS "Configuring fc to build on Unix/Apple")
|
|
||||||
|
|
||||||
LIST(APPEND BOOST_COMPONENTS coroutine)
|
|
||||||
|
|
||||||
FIND_PACKAGE(Boost 1.53 REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
|
||||||
|
|
||||||
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so")
|
|
||||||
|
|
||||||
IF(NOT APPLE)
|
|
||||||
# Linux or other unix
|
|
||||||
SET(rt_library rt )
|
|
||||||
SET(pthread_library pthread)
|
|
||||||
ENDIF(NOT APPLE)
|
|
||||||
ENDIF(WIN32)
|
ENDIF(WIN32)
|
||||||
|
|
||||||
|
set(Boost_DIR "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/Boost")
|
||||||
|
FIND_PACKAGE(Boost CONFIG COMPONENTS ${BOOST_COMPONENTS} )
|
||||||
|
|
||||||
|
IF(NOT WIN32)
|
||||||
|
MESSAGE(STATUS "Configuring fc to build on Unix/Apple")
|
||||||
|
|
||||||
IF(NOT "$ENV{OPENSSL_ROOT_DIR}" STREQUAL "")
|
IF(NOT APPLE AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
|
||||||
|
SET(rt_library rt )
|
||||||
|
ENDIF(NOT APPLE AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
|
||||||
|
ENDIF(NOT WIN32)
|
||||||
|
|
||||||
|
IF($ENV{OPENSSL_ROOT_DIR})
|
||||||
set(OPENSSL_ROOT_DIR $ENV{OPENSSL_ROOT_DIR} )
|
set(OPENSSL_ROOT_DIR $ENV{OPENSSL_ROOT_DIR} )
|
||||||
set(OPENSSL_INCLUDE_DIR ${OPENSSL_ROOT_DIR}/include)
|
set(OPENSSL_INCLUDE_DIR ${OPENSSL_ROOT_DIR}/include)
|
||||||
message(STATUS "Setting up OpenSSL root and include vars to ${OPENSSL_ROOT_DIR}, ${OPENSSL_INCLUDE_DIR}")
|
message(STATUS "Setting up OpenSSL root and include vars to ${OPENSSL_ROOT_DIR}, ${OPENSSL_INCLUDE_DIR}")
|
||||||
|
|
@ -189,13 +159,10 @@ ENDIF( LIBCXX_HAVE_CXX_ATOMICS_WITH_LIB )
|
||||||
|
|
||||||
find_package(OpenSSL REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
|
|
||||||
set( CMAKE_FIND_LIBRARY_SUFFIXES ${ORIGINAL_LIB_SUFFIXES} )
|
|
||||||
|
|
||||||
option( UNITY_BUILD OFF )
|
option( UNITY_BUILD OFF )
|
||||||
|
|
||||||
set( fc_sources
|
set( fc_sources
|
||||||
src/uint128.cpp
|
src/popcount.cpp
|
||||||
src/real128.cpp
|
|
||||||
src/variant.cpp
|
src/variant.cpp
|
||||||
src/exception.cpp
|
src/exception.cpp
|
||||||
src/variant_object.cpp
|
src/variant_object.cpp
|
||||||
|
|
@ -211,7 +178,6 @@ set( fc_sources
|
||||||
src/thread/non_preemptable_scope_check.cpp
|
src/thread/non_preemptable_scope_check.cpp
|
||||||
src/asio.cpp
|
src/asio.cpp
|
||||||
src/string.cpp
|
src/string.cpp
|
||||||
src/shared_ptr.cpp
|
|
||||||
src/stacktrace.cpp
|
src/stacktrace.cpp
|
||||||
src/time.cpp
|
src/time.cpp
|
||||||
src/utf8.cpp
|
src/utf8.cpp
|
||||||
|
|
@ -226,7 +192,6 @@ set( fc_sources
|
||||||
src/interprocess/signals.cpp
|
src/interprocess/signals.cpp
|
||||||
src/interprocess/file_mapping.cpp
|
src/interprocess/file_mapping.cpp
|
||||||
src/rpc/cli.cpp
|
src/rpc/cli.cpp
|
||||||
src/rpc/http_api.cpp
|
|
||||||
src/rpc/state.cpp
|
src/rpc/state.cpp
|
||||||
src/rpc/websocket_api.cpp
|
src/rpc/websocket_api.cpp
|
||||||
src/log/log_message.cpp
|
src/log/log_message.cpp
|
||||||
|
|
@ -259,7 +224,6 @@ set( fc_sources
|
||||||
src/network/tcp_socket.cpp
|
src/network/tcp_socket.cpp
|
||||||
src/network/udp_socket.cpp
|
src/network/udp_socket.cpp
|
||||||
src/network/http/http_connection.cpp
|
src/network/http/http_connection.cpp
|
||||||
src/network/http/http_server.cpp
|
|
||||||
src/network/http/websocket.cpp
|
src/network/http/websocket.cpp
|
||||||
src/network/ip.cpp
|
src/network/ip.cpp
|
||||||
src/network/rate_limiting.cpp
|
src/network/rate_limiting.cpp
|
||||||
|
|
@ -284,12 +248,11 @@ setup_library( fc SOURCES ${sources} LIBRARY_TYPE STATIC )
|
||||||
install( DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" DESTINATION include )
|
install( DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" DESTINATION include )
|
||||||
|
|
||||||
# begin editline stuff
|
# begin editline stuff
|
||||||
if(NOT (MSVC OR MINGW))
|
|
||||||
target_compile_definitions (fc PRIVATE HAVE_EDITLINE)
|
|
||||||
set(editline_libraries editline)
|
|
||||||
endif(NOT (MSVC OR MINGW))
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_compile_definitions( fc PRIVATE _CRT_NONSTDC_NO_DEPRECATE )
|
target_compile_definitions( fc PRIVATE _CRT_NONSTDC_NO_DEPRECATE )
|
||||||
|
else(WIN32)
|
||||||
|
target_compile_definitions( fc PRIVATE HAVE_EDITLINE )
|
||||||
|
set( editline_libraries editline )
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
# end editline stuff
|
# end editline stuff
|
||||||
|
|
||||||
|
|
@ -341,6 +304,7 @@ ENDIF(APPLE)
|
||||||
|
|
||||||
if( ZLIB_FOUND )
|
if( ZLIB_FOUND )
|
||||||
MESSAGE( STATUS "zlib found" )
|
MESSAGE( STATUS "zlib found" )
|
||||||
|
target_include_directories(fc PUBLIC ${ZLIB_INCLUDE_DIRS})
|
||||||
add_definitions( -DHAS_ZLIB )
|
add_definitions( -DHAS_ZLIB )
|
||||||
else()
|
else()
|
||||||
MESSAGE( STATUS "zlib not found" )
|
MESSAGE( STATUS "zlib not found" )
|
||||||
|
|
@ -384,9 +348,11 @@ target_link_libraries( fc PUBLIC ${LINK_USR_LOCAL_LIB} ${OPENSSL_LIBRARIES} ${Z
|
||||||
${PLATFORM_SPECIFIC_LIBS} ${RPCRT4} ${CMAKE_DL_LIBS} ${rt_library}
|
${PLATFORM_SPECIFIC_LIBS} ${RPCRT4} ${CMAKE_DL_LIBS} ${rt_library}
|
||||||
${editline_libraries} secp256k1 ${CMAKE_REQUIRED_LIBRARIES} )
|
${editline_libraries} secp256k1 ${CMAKE_REQUIRED_LIBRARIES} )
|
||||||
|
|
||||||
if(MSVC)
|
if(WIN32 AND MSVC)
|
||||||
set_source_files_properties( src/network/http/websocket.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
|
set_source_files_properties( src/network/http/websocket.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
|
||||||
endif(MSVC)
|
elseif(WIN32 AND MINGW)
|
||||||
|
set_source_files_properties( src/network/http/websocket.cpp PROPERTIES LINK_FLAGS "-mbig-obj" )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
IF(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY MATCHES "\\.(a|lib)$")
|
IF(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY MATCHES "\\.(a|lib)$")
|
||||||
|
|
@ -401,18 +367,10 @@ include_directories( vendor/websocketpp )
|
||||||
|
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
|
||||||
if(WIN32)
|
if(MSVC)
|
||||||
# add addtional import library on windows platform
|
# add addtional import library on windows platform
|
||||||
target_link_libraries( fc PUBLIC crypt32.lib)
|
target_link_libraries( fc PUBLIC crypt32.lib)
|
||||||
|
|
||||||
# now generate a list of the DLLs we're using to use during the install process
|
|
||||||
include (ParseLibraryList)
|
|
||||||
PARSE_LIBRARY_LIST(${Boost_LIBRARIES}
|
|
||||||
FOUND parseOk
|
|
||||||
DEBUG Boost_LIBRARIES_DEBUG
|
|
||||||
OPT Boost_LIBRARIES_RELEASE
|
|
||||||
GENERAL Boost_LIBRARIES_GENERAL)
|
|
||||||
|
|
||||||
#Variable will hold list of .pdb files generated for libraries the 'fc' module is linked to
|
#Variable will hold list of .pdb files generated for libraries the 'fc' module is linked to
|
||||||
set(INTERFACE_LINK_PDB_RELEASE)
|
set(INTERFACE_LINK_PDB_RELEASE)
|
||||||
|
|
||||||
|
|
@ -481,31 +439,8 @@ if(WIN32)
|
||||||
set_property(TARGET fc PROPERTY SHARED_LIBRARIES_DEBUG ${SHARED_LIBRARIES_DEBUG})
|
set_property(TARGET fc PROPERTY SHARED_LIBRARIES_DEBUG ${SHARED_LIBRARIES_DEBUG})
|
||||||
set_property(TARGET fc PROPERTY SHARED_LIBRARIES_RELEASE ${SHARED_LIBRARIES_RELEASE})
|
set_property(TARGET fc PROPERTY SHARED_LIBRARIES_RELEASE ${SHARED_LIBRARIES_RELEASE})
|
||||||
|
|
||||||
endif(WIN32)
|
endif(MSVC)
|
||||||
|
|
||||||
SET(OPENSSL_CONF_TARGET )
|
INCLUDE(CheckLibcxxAtomic)
|
||||||
IF(DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
|
||||||
SET (OPENSSL_CONF_TARGET ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
|
||||||
ELSE()
|
|
||||||
SET (OPENSSL_CONF_TARGET ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
IF(WIN32)
|
|
||||||
IF("${OPENSSL_ROOT_DIR}" STREQUAL "")
|
|
||||||
get_filename_component(OPENSSL_ROOT_DIR "${OPENSSL_INCLUDE_DIR}/.." REALPATH)
|
|
||||||
ENDIF()
|
|
||||||
IF("${OPENSSL_CONF_SOURCE}" STREQUAL "")
|
|
||||||
SET(OPENSSL_CONF_SOURCE "${OPENSSL_ROOT_DIR}/ssl/openssl.cnf")
|
|
||||||
IF(MINGW)
|
|
||||||
SET(OPENSSL_CONF_SOURCE "${OPENSSL_ROOT_DIR}/openssl.cnf")
|
|
||||||
ENDIF(MINGW)
|
|
||||||
ENDIF()
|
|
||||||
SET(POST_BUILD_STEP_COMMANDS ${POST_BUILD_STEP_COMMANDS}
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${OPENSSL_CONF_SOURCE}" "${OPENSSL_CONF_TARGET}/openssl.cnf")
|
|
||||||
ENDIF(WIN32)
|
|
||||||
|
|
||||||
ADD_CUSTOM_COMMAND(TARGET fc POST_BUILD ${POST_BUILD_STEP_COMMANDS}
|
|
||||||
COMMENT "Copying OpenSSL/ssl/openssl.cnf into target directory."
|
|
||||||
)
|
|
||||||
|
|
||||||
MESSAGE(STATUS "Finished fc module configuration...")
|
MESSAGE(STATUS "Finished fc module configuration...")
|
||||||
|
|
|
||||||
18
CMakeModules/Boost/BoostConfig.cmake
Normal file
18
CMakeModules/Boost/BoostConfig.cmake
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# This overrides `find_package(Boost ... CONFIG ... )` calls
|
||||||
|
# - calls the CMake's built-in `FindBoost.cmake` and adds `pthread` library dependency
|
||||||
|
|
||||||
|
MESSAGE(STATUS "Using custom FindBoost config")
|
||||||
|
|
||||||
|
find_package(Boost 1.58 REQUIRED COMPONENTS ${Boost_FIND_COMPONENTS})
|
||||||
|
|
||||||
|
# Inject `pthread` dependency to Boost if needed
|
||||||
|
if (UNIX AND NOT CYGWIN)
|
||||||
|
list(FIND Boost_FIND_COMPONENTS thread _using_boost_thread)
|
||||||
|
if (_using_boost_thread GREATER -1)
|
||||||
|
find_library(BOOST_THREAD_LIBRARY NAMES pthread DOC "The threading library used by boost-thread")
|
||||||
|
if (BOOST_THREAD_LIBRARY)
|
||||||
|
MESSAGE(STATUS "Adding Boost thread lib dependency: ${BOOST_THREAD_LIBRARY}")
|
||||||
|
list(APPEND Boost_LIBRARIES ${BOOST_THREAD_LIBRARY})
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
@ -18,11 +18,15 @@ function(check_cxx_atomics varname)
|
||||||
if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage)
|
if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage)
|
||||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters")
|
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(OLD_CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES})
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIRS})
|
||||||
|
|
||||||
check_cxx_source_compiles("
|
check_cxx_source_compiles("
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <boost/lockfree/queue.hpp>
|
#include <boost/lockfree/queue.hpp>
|
||||||
|
|
||||||
boost::lockfree::queue<uint32_t*> q;
|
boost::lockfree::queue<uint32_t*,boost::lockfree::capacity<5>> q;
|
||||||
int main(int, char**) {
|
int main(int, char**) {
|
||||||
uint32_t* a;
|
uint32_t* a;
|
||||||
uint32_t* b;
|
uint32_t* b;
|
||||||
|
|
@ -31,6 +35,7 @@ int main(int, char**) {
|
||||||
}
|
}
|
||||||
" ${varname})
|
" ${varname})
|
||||||
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
|
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES ${OLD_CMAKE_REQUIRED_INCLUDES})
|
||||||
endfunction(check_cxx_atomics)
|
endfunction(check_cxx_atomics)
|
||||||
|
|
||||||
# Perform the check for 64bit atomics without libatomic.
|
# Perform the check for 64bit atomics without libatomic.
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,145 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <fc/crypto/base64.hpp>
|
|
||||||
#include <fc/variant.hpp>
|
|
||||||
#include <fc/reflect/reflect.hpp>
|
|
||||||
|
|
||||||
namespace fc {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a fixed size array that is easier for templates to specialize
|
|
||||||
* against or overload than T[N].
|
|
||||||
*/
|
|
||||||
template<typename T, size_t N>
|
|
||||||
class array {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Checked indexing (when in debug build) that also simplifies dereferencing
|
|
||||||
* when you have an array<T,N>*.
|
|
||||||
*/
|
|
||||||
///@{
|
|
||||||
T& at( size_t pos ) { assert( pos < N); return data[pos]; }
|
|
||||||
const T& at( size_t pos )const { assert( pos < N); return data[pos]; }
|
|
||||||
///@}
|
|
||||||
|
|
||||||
T& operator[]( size_t pos ) { assert( pos < N); return data[pos]; }
|
|
||||||
const T& operator[]( size_t pos )const { assert( pos < N); return data[pos]; }
|
|
||||||
|
|
||||||
|
|
||||||
const T* begin()const { return &data[0]; }
|
|
||||||
const T* end()const { return &data[N]; }
|
|
||||||
|
|
||||||
T* begin() { return &data[0]; }
|
|
||||||
T* end() { return &data[N]; }
|
|
||||||
|
|
||||||
size_t size()const { return N; }
|
|
||||||
|
|
||||||
T data[N];
|
|
||||||
};
|
|
||||||
|
|
||||||
/** provided for default 0 init */
|
|
||||||
template<size_t N>
|
|
||||||
class array<unsigned char,N>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef unsigned char T;
|
|
||||||
array(){ memset( data, 0, sizeof(data) ); }
|
|
||||||
/**
|
|
||||||
* Checked indexing (when in debug build) that also simplifies dereferencing
|
|
||||||
* when you have an array<T,N>*.
|
|
||||||
*/
|
|
||||||
///@{
|
|
||||||
T& at( size_t pos ) { assert( pos < N); return data[pos]; }
|
|
||||||
const T& at( size_t pos )const { assert( pos < N); return data[pos]; }
|
|
||||||
///@}
|
|
||||||
|
|
||||||
T* begin() { return &data[0]; }
|
|
||||||
const T* begin()const { return &data[0]; }
|
|
||||||
const T* end()const { return &data[N]; }
|
|
||||||
|
|
||||||
size_t size()const { return N; }
|
|
||||||
|
|
||||||
T data[N];
|
|
||||||
};
|
|
||||||
|
|
||||||
/** provided for default 0 init */
|
|
||||||
template<size_t N>
|
|
||||||
class array<char,N>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef char T;
|
|
||||||
array(){ memset( data, 0, sizeof(data) ); }
|
|
||||||
/**
|
|
||||||
* Checked indexing (when in debug build) that also simplifies dereferencing
|
|
||||||
* when you have an array<T,N>*.
|
|
||||||
*/
|
|
||||||
///@{
|
|
||||||
T& at( size_t pos ) { assert( pos < N); return data[pos]; }
|
|
||||||
const T& at( size_t pos )const { assert( pos < N); return data[pos]; }
|
|
||||||
///@}
|
|
||||||
|
|
||||||
T* begin() { return &data[0]; }
|
|
||||||
const T* begin()const { return &data[0]; }
|
|
||||||
const T* end()const { return &data[N]; }
|
|
||||||
|
|
||||||
size_t size()const { return N; }
|
|
||||||
|
|
||||||
T data[N];
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, size_t N>
|
|
||||||
bool operator == ( const array<T,N>& a, const array<T,N>& b )
|
|
||||||
{ return 0 == memcmp( a.data, b.data, N*sizeof(T) ); }
|
|
||||||
template<typename T, size_t N>
|
|
||||||
bool operator < ( const array<T,N>& a, const array<T,N>& b )
|
|
||||||
{ return memcmp( a.data, b.data, N*sizeof(T) ) < 0 ; }
|
|
||||||
|
|
||||||
template<typename T, size_t N>
|
|
||||||
bool operator > ( const array<T,N>& a, const array<T,N>& b )
|
|
||||||
{ return memcmp( a.data, b.data, N*sizeof(T) ) > 0 ; }
|
|
||||||
|
|
||||||
template<typename T, size_t N>
|
|
||||||
bool operator != ( const array<T,N>& a, const array<T,N>& b )
|
|
||||||
{ return 0 != memcmp( a.data, b.data, N*sizeof(T) ); }
|
|
||||||
|
|
||||||
template<typename T, size_t N>
|
|
||||||
void to_variant( const array<T,N>& bi, variant& v, uint32_t max_depth = 1 )
|
|
||||||
{
|
|
||||||
to_variant( std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, 1 );
|
|
||||||
}
|
|
||||||
template<typename T, size_t N>
|
|
||||||
void from_variant( const variant& v, array<T,N>& bi, uint32_t max_depth = 1 )
|
|
||||||
{
|
|
||||||
std::vector<char> ve = v.as< std::vector<char> >( 1 );
|
|
||||||
if( ve.size() )
|
|
||||||
{
|
|
||||||
memcpy(&bi, ve.data(), std::min<size_t>(ve.size(),sizeof(bi)) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memset( &bi, char(0), sizeof(bi) );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T,size_t N> struct get_typename< fc::array<T,N> >
|
|
||||||
{
|
|
||||||
static const char* name()
|
|
||||||
{
|
|
||||||
static std::string _name = std::string("fc::array<")+std::string(fc::get_typename<T>::name())+","+ fc::to_string(N) + ">";
|
|
||||||
return _name.c_str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <fc/crypto/city.hpp>
|
|
||||||
namespace std
|
|
||||||
{
|
|
||||||
template<typename T, size_t N>
|
|
||||||
struct hash<fc::array<T,N> >
|
|
||||||
{
|
|
||||||
size_t operator()( const fc::array<T,N>& e )const
|
|
||||||
{
|
|
||||||
return fc::city_hash_size_t( (char*)&e, sizeof(e) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -102,7 +102,7 @@ namespace asio {
|
||||||
*/
|
*/
|
||||||
template<typename AsyncReadStream, typename MutableBufferSequence>
|
template<typename AsyncReadStream, typename MutableBufferSequence>
|
||||||
size_t read( AsyncReadStream& s, const MutableBufferSequence& buf ) {
|
size_t read( AsyncReadStream& s, const MutableBufferSequence& buf ) {
|
||||||
promise<size_t>::ptr p(new promise<size_t>("fc::asio::read"));
|
promise<size_t>::ptr p = promise<size_t>::create("fc::asio::read");
|
||||||
boost::asio::async_read( s, buf, detail::read_write_handler(p) );
|
boost::asio::async_read( s, buf, detail::read_write_handler(p) );
|
||||||
return p->wait();
|
return p->wait();
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +122,7 @@ namespace asio {
|
||||||
template<typename AsyncReadStream, typename MutableBufferSequence>
|
template<typename AsyncReadStream, typename MutableBufferSequence>
|
||||||
future<size_t> read_some(AsyncReadStream& s, const MutableBufferSequence& buf)
|
future<size_t> read_some(AsyncReadStream& s, const MutableBufferSequence& buf)
|
||||||
{
|
{
|
||||||
promise<size_t>::ptr completion_promise(new promise<size_t>("fc::asio::async_read_some"));
|
promise<size_t>::ptr completion_promise = promise<size_t>::create("fc::asio::async_read_some");
|
||||||
s.async_read_some(buf, detail::read_write_handler(completion_promise));
|
s.async_read_some(buf, detail::read_write_handler(completion_promise));
|
||||||
return completion_promise;//->wait();
|
return completion_promise;//->wait();
|
||||||
}
|
}
|
||||||
|
|
@ -130,7 +130,7 @@ namespace asio {
|
||||||
template<typename AsyncReadStream>
|
template<typename AsyncReadStream>
|
||||||
future<size_t> read_some(AsyncReadStream& s, char* buffer, size_t length, size_t offset = 0)
|
future<size_t> read_some(AsyncReadStream& s, char* buffer, size_t length, size_t offset = 0)
|
||||||
{
|
{
|
||||||
promise<size_t>::ptr completion_promise(new promise<size_t>("fc::asio::async_read_some"));
|
promise<size_t>::ptr completion_promise = promise<size_t>::create("fc::asio::async_read_some");
|
||||||
s.async_read_some(boost::asio::buffer(buffer + offset, length),
|
s.async_read_some(boost::asio::buffer(buffer + offset, length),
|
||||||
detail::read_write_handler(completion_promise));
|
detail::read_write_handler(completion_promise));
|
||||||
return completion_promise;//->wait();
|
return completion_promise;//->wait();
|
||||||
|
|
@ -139,7 +139,7 @@ namespace asio {
|
||||||
template<typename AsyncReadStream>
|
template<typename AsyncReadStream>
|
||||||
future<size_t> read_some(AsyncReadStream& s, const std::shared_ptr<char>& buffer, size_t length, size_t offset)
|
future<size_t> read_some(AsyncReadStream& s, const std::shared_ptr<char>& buffer, size_t length, size_t offset)
|
||||||
{
|
{
|
||||||
promise<size_t>::ptr completion_promise(new promise<size_t>("fc::asio::async_read_some"));
|
promise<size_t>::ptr completion_promise = promise<size_t>::create("fc::asio::async_read_some");
|
||||||
s.async_read_some(boost::asio::buffer(buffer.get() + offset, length),
|
s.async_read_some(boost::asio::buffer(buffer.get() + offset, length),
|
||||||
detail::read_write_handler_with_buffer(completion_promise, buffer));
|
detail::read_write_handler_with_buffer(completion_promise, buffer));
|
||||||
return completion_promise;//->wait();
|
return completion_promise;//->wait();
|
||||||
|
|
@ -179,7 +179,7 @@ namespace asio {
|
||||||
*/
|
*/
|
||||||
template<typename AsyncWriteStream, typename ConstBufferSequence>
|
template<typename AsyncWriteStream, typename ConstBufferSequence>
|
||||||
size_t write( AsyncWriteStream& s, const ConstBufferSequence& buf ) {
|
size_t write( AsyncWriteStream& s, const ConstBufferSequence& buf ) {
|
||||||
promise<size_t>::ptr p(new promise<size_t>("fc::asio::write"));
|
promise<size_t>::ptr p = promise<size_t>::create("fc::asio::write");
|
||||||
boost::asio::async_write(s, buf, detail::read_write_handler(p));
|
boost::asio::async_write(s, buf, detail::read_write_handler(p));
|
||||||
return p->wait();
|
return p->wait();
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +191,7 @@ namespace asio {
|
||||||
*/
|
*/
|
||||||
template<typename AsyncWriteStream, typename ConstBufferSequence>
|
template<typename AsyncWriteStream, typename ConstBufferSequence>
|
||||||
future<size_t> write_some( AsyncWriteStream& s, const ConstBufferSequence& buf ) {
|
future<size_t> write_some( AsyncWriteStream& s, const ConstBufferSequence& buf ) {
|
||||||
promise<size_t>::ptr p(new promise<size_t>("fc::asio::write_some"));
|
promise<size_t>::ptr p = promise<size_t>::create("fc::asio::write_some");
|
||||||
s.async_write_some( buf, detail::read_write_handler(p));
|
s.async_write_some( buf, detail::read_write_handler(p));
|
||||||
return p; //->wait();
|
return p; //->wait();
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +199,7 @@ namespace asio {
|
||||||
template<typename AsyncWriteStream>
|
template<typename AsyncWriteStream>
|
||||||
future<size_t> write_some( AsyncWriteStream& s, const char* buffer,
|
future<size_t> write_some( AsyncWriteStream& s, const char* buffer,
|
||||||
size_t length, size_t offset = 0) {
|
size_t length, size_t offset = 0) {
|
||||||
promise<size_t>::ptr p(new promise<size_t>("fc::asio::write_some"));
|
promise<size_t>::ptr p = promise<size_t>::create("fc::asio::write_some");
|
||||||
s.async_write_some( boost::asio::buffer(buffer + offset, length), detail::read_write_handler(p));
|
s.async_write_some( boost::asio::buffer(buffer + offset, length), detail::read_write_handler(p));
|
||||||
return p; //->wait();
|
return p; //->wait();
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +207,7 @@ namespace asio {
|
||||||
template<typename AsyncWriteStream>
|
template<typename AsyncWriteStream>
|
||||||
future<size_t> write_some( AsyncWriteStream& s, const std::shared_ptr<const char>& buffer,
|
future<size_t> write_some( AsyncWriteStream& s, const std::shared_ptr<const char>& buffer,
|
||||||
size_t length, size_t offset ) {
|
size_t length, size_t offset ) {
|
||||||
promise<size_t>::ptr p(new promise<size_t>("fc::asio::write_some"));
|
promise<size_t>::ptr p = promise<size_t>::create("fc::asio::write_some");
|
||||||
s.async_write_some( boost::asio::buffer(buffer.get() + offset, length), detail::read_write_handler_with_buffer(p, buffer));
|
s.async_write_some( boost::asio::buffer(buffer.get() + offset, length), detail::read_write_handler_with_buffer(p, buffer));
|
||||||
return p; //->wait();
|
return p; //->wait();
|
||||||
}
|
}
|
||||||
|
|
@ -249,8 +249,7 @@ namespace asio {
|
||||||
*/
|
*/
|
||||||
template<typename SocketType, typename AcceptorType>
|
template<typename SocketType, typename AcceptorType>
|
||||||
void accept( AcceptorType& acc, SocketType& sock ) {
|
void accept( AcceptorType& acc, SocketType& sock ) {
|
||||||
//promise<boost::system::error_code>::ptr p( new promise<boost::system::error_code>("fc::asio::tcp::accept") );
|
promise<void>::ptr p = promise<void>::create("fc::asio::tcp::accept");
|
||||||
promise<void>::ptr p( new promise<void>("fc::asio::tcp::accept") );
|
|
||||||
acc.async_accept( sock, boost::bind( fc::asio::detail::error_handler, p, _1 ) );
|
acc.async_accept( sock, boost::bind( fc::asio::detail::error_handler, p, _1 ) );
|
||||||
p->wait();
|
p->wait();
|
||||||
//if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) );
|
//if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) );
|
||||||
|
|
@ -262,7 +261,7 @@ namespace asio {
|
||||||
*/
|
*/
|
||||||
template<typename AsyncSocket, typename EndpointType>
|
template<typename AsyncSocket, typename EndpointType>
|
||||||
void connect( AsyncSocket& sock, const EndpointType& ep ) {
|
void connect( AsyncSocket& sock, const EndpointType& ep ) {
|
||||||
promise<void>::ptr p(new promise<void>("fc::asio::tcp::connect"));
|
promise<void>::ptr p = promise<void>::create("fc::asio::tcp::connect");
|
||||||
sock.async_connect( ep, boost::bind( fc::asio::detail::error_handler, p, _1 ) );
|
sock.async_connect( ep, boost::bind( fc::asio::detail::error_handler, p, _1 ) );
|
||||||
p->wait();
|
p->wait();
|
||||||
//if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) );
|
//if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) );
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
|
|
||||||
static const std::size_t bits_per_char = 0x08; // 8 bits in 1 char(unsigned)
|
static constexpr std::size_t bits_per_char = 0x08; // 8 bits in 1 char(unsigned)
|
||||||
static const unsigned char bit_mask[bits_per_char] = {
|
static const unsigned char bit_mask[bits_per_char] = {
|
||||||
0x01, //00000001
|
0x01, //00000001
|
||||||
0x02, //00000010
|
0x02, //00000010
|
||||||
|
|
|
||||||
79
include/fc/container/zeroed_array.hpp
Normal file
79
include/fc/container/zeroed_array.hpp
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 BitShares Blockchain Foundation, and contributors
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <fc/io/raw_fwd.hpp>
|
||||||
|
|
||||||
|
namespace fc {
|
||||||
|
|
||||||
|
template< typename T, size_t N >
|
||||||
|
class zero_initialized_array;
|
||||||
|
|
||||||
|
template< size_t N >
|
||||||
|
class zero_initialized_array< unsigned char, N > : public std::array< unsigned char, N > {
|
||||||
|
public:
|
||||||
|
zero_initialized_array() : std::array< unsigned char, N >() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T,size_t N>
|
||||||
|
struct get_typename< zero_initialized_array<T,N> >
|
||||||
|
{
|
||||||
|
static const char* name()
|
||||||
|
{
|
||||||
|
static std::string _name = std::string("zero_initialized_array<")
|
||||||
|
+ std::string(fc::get_typename<T>::name())
|
||||||
|
+ "," + fc::to_string(N) + ">";
|
||||||
|
return _name.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class variant;
|
||||||
|
template<size_t N>
|
||||||
|
void to_variant( const zero_initialized_array<unsigned char,N>& bi, variant& v, uint32_t max_depth = 1 )
|
||||||
|
{
|
||||||
|
to_variant( static_cast<const std::array<unsigned char,N>&>( bi ), v, max_depth );
|
||||||
|
}
|
||||||
|
template<size_t N>
|
||||||
|
void from_variant( const variant& v, zero_initialized_array<unsigned char,N>& bi, uint32_t max_depth = 1 )
|
||||||
|
{
|
||||||
|
from_variant( v, static_cast<std::array<unsigned char,N>&>( bi ), max_depth );
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace raw {
|
||||||
|
template<typename Stream, size_t N>
|
||||||
|
inline void pack( Stream& s, const zero_initialized_array<unsigned char,N>& v, uint32_t _max_depth ) {
|
||||||
|
pack( s, static_cast<const std::array<unsigned char,N>&>( v ), _max_depth );
|
||||||
|
}
|
||||||
|
template<typename Stream, size_t N>
|
||||||
|
inline void unpack( Stream& s, zero_initialized_array<unsigned char,N>& v, uint32_t _max_depth ) {
|
||||||
|
try {
|
||||||
|
unpack( s, static_cast<std::array<unsigned char,N>&>( v ), _max_depth );
|
||||||
|
} FC_RETHROW_EXCEPTIONS( warn, "zero_initialized_array<unsigned char,${length}>", ("length",N) )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template< typename T, size_t N >
|
||||||
|
class tuple_size< fc::zero_initialized_array< T, N > > : public tuple_size< array< T, N > > {};
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fc/io/raw_fwd.hpp>
|
|
||||||
#include <fc/crypto/sha512.hpp>
|
#include <fc/crypto/sha512.hpp>
|
||||||
#include <fc/crypto/sha256.hpp>
|
#include <fc/crypto/sha256.hpp>
|
||||||
#include <fc/uint128.hpp>
|
|
||||||
#include <fc/fwd.hpp>
|
#include <fc/fwd.hpp>
|
||||||
|
#include <fc/uint128.hpp>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
@ -15,9 +16,8 @@ namespace fc {
|
||||||
aes_encoder();
|
aes_encoder();
|
||||||
~aes_encoder();
|
~aes_encoder();
|
||||||
|
|
||||||
void init( const fc::sha256& key, const fc::uint128& init_value );
|
void init( const fc::sha256& key, const uint128_t& init_value );
|
||||||
uint32_t encode( const char* plaintxt, uint32_t len, char* ciphertxt );
|
uint32_t encode( const char* plaintxt, uint32_t len, char* ciphertxt );
|
||||||
// uint32_t final_encode( char* ciphertxt );
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct impl;
|
struct impl;
|
||||||
|
|
@ -29,9 +29,8 @@ namespace fc {
|
||||||
aes_decoder();
|
aes_decoder();
|
||||||
~aes_decoder();
|
~aes_decoder();
|
||||||
|
|
||||||
void init( const fc::sha256& key, const fc::uint128& init_value );
|
void init( const fc::sha256& key, const uint128_t& init_value );
|
||||||
uint32_t decode( const char* ciphertxt, uint32_t len, char* plaintext );
|
uint32_t decode( const char* ciphertxt, uint32_t len, char* plaintext );
|
||||||
// uint32_t final_decode( char* plaintext );
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct impl;
|
struct impl;
|
||||||
|
|
|
||||||
|
|
@ -41,36 +41,25 @@
|
||||||
// doesn't hold for any hash functions in this file.
|
// doesn't hold for any hash functions in this file.
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <fc/uint128.hpp>
|
||||||
|
|
||||||
#include <stdlib.h> // for size_t.
|
#include <stdlib.h> // for size_t.
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
template<typename T, size_t N>
|
|
||||||
class array;
|
|
||||||
class uint128;
|
|
||||||
|
|
||||||
// Hash function for a byte array.
|
// Hash function for a byte array.
|
||||||
uint64_t city_hash64(const char *buf, size_t len);
|
uint64_t city_hash64(const char *buf, size_t len);
|
||||||
|
|
||||||
uint32_t city_hash32(const char *buf, size_t len);
|
|
||||||
|
|
||||||
#if SIZE_MAX > UINT32_MAX
|
#if SIZE_MAX > UINT32_MAX
|
||||||
inline size_t city_hash_size_t(const char *buf, size_t len) { return city_hash64(buf, len); }
|
inline size_t city_hash_size_t(const char *buf, size_t len) { return city_hash64(buf, len); }
|
||||||
#else
|
#else
|
||||||
|
uint32_t city_hash32(const char *buf, size_t len);
|
||||||
inline size_t city_hash_size_t(const char *buf, size_t len) { return city_hash32(buf, len); }
|
inline size_t city_hash_size_t(const char *buf, size_t len) { return city_hash32(buf, len); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Hash function for a byte array.
|
// Hash function for a byte array.
|
||||||
uint128 city_hash128(const char *s, size_t len);
|
uint128_t city_hash_crc_128(const char *s, size_t len);
|
||||||
|
|
||||||
// Hash function for a byte array.
|
|
||||||
uint64_t city_hash_crc_64(const char *buf, size_t len);
|
|
||||||
|
|
||||||
// Hash function for a byte array.
|
|
||||||
uint128 city_hash_crc_128(const char *s, size_t len);
|
|
||||||
array<uint64_t,4> city_hash_crc_256(const char *s, size_t len);
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace fc
|
} // namespace fc
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <fc/container/zeroed_array.hpp>
|
||||||
#include <fc/crypto/bigint.hpp>
|
#include <fc/crypto/bigint.hpp>
|
||||||
#include <fc/crypto/openssl.hpp>
|
#include <fc/crypto/openssl.hpp>
|
||||||
#include <fc/crypto/sha256.hpp>
|
#include <fc/crypto/sha256.hpp>
|
||||||
#include <fc/crypto/sha512.hpp>
|
#include <fc/crypto/sha512.hpp>
|
||||||
#include <fc/fwd.hpp>
|
#include <fc/fwd.hpp>
|
||||||
#include <fc/array.hpp>
|
|
||||||
#include <fc/io/raw_fwd.hpp>
|
#include <fc/io/raw_fwd.hpp>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
namespace ecc {
|
namespace ecc {
|
||||||
|
|
@ -16,15 +18,15 @@ namespace fc {
|
||||||
class private_key_impl;
|
class private_key_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef fc::sha256 blind_factor_type;
|
typedef fc::sha256 blind_factor_type;
|
||||||
typedef fc::array<char,33> commitment_type;
|
typedef zero_initialized_array<unsigned char,33> commitment_type;
|
||||||
typedef fc::array<char,33> public_key_data;
|
typedef zero_initialized_array<unsigned char,33> public_key_data;
|
||||||
typedef fc::sha256 private_key_secret;
|
typedef fc::sha256 private_key_secret;
|
||||||
typedef fc::array<char,65> public_key_point_data; ///< the full non-compressed version of the ECC point
|
typedef zero_initialized_array<unsigned char,65> public_key_point_data; ///< the full non-compressed version of the ECC point
|
||||||
typedef fc::array<char,72> signature;
|
typedef zero_initialized_array<unsigned char,72> signature;
|
||||||
typedef fc::array<unsigned char,65> compact_signature;
|
typedef zero_initialized_array<unsigned char,65> compact_signature;
|
||||||
typedef std::vector<char> range_proof_type;
|
typedef std::vector<char> range_proof_type;
|
||||||
typedef fc::array<char,78> extended_key_data;
|
typedef zero_initialized_array<unsigned char,78> extended_key_data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class public_key
|
* @class public_key
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <openssl/ec.h>
|
#include <openssl/ec.h>
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
|
#include <openssl/dh.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/conf.h>
|
#include <openssl/conf.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
|
@ -21,6 +22,8 @@ namespace fc
|
||||||
struct ssl_wrapper
|
struct ssl_wrapper
|
||||||
{
|
{
|
||||||
ssl_wrapper(ssl_type* obj):obj(obj) {}
|
ssl_wrapper(ssl_type* obj):obj(obj) {}
|
||||||
|
ssl_wrapper( ssl_wrapper& copy ) = delete;
|
||||||
|
ssl_wrapper& operator=( ssl_wrapper& copy ) = delete;
|
||||||
|
|
||||||
operator ssl_type*() { return obj; }
|
operator ssl_type*() { return obj; }
|
||||||
operator const ssl_type*() const { return obj; }
|
operator const ssl_type*() const { return obj; }
|
||||||
|
|
@ -30,23 +33,21 @@ namespace fc
|
||||||
ssl_type* obj;
|
ssl_type* obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SSL_TYPE(name, ssl_type, free_func) \
|
#define SSL_TYPE_DECL(name, ssl_type) \
|
||||||
struct name : public ssl_wrapper<ssl_type> \
|
struct name : public ssl_wrapper<ssl_type> \
|
||||||
{ \
|
{ \
|
||||||
name(ssl_type* obj=nullptr) \
|
name( ssl_type* obj=nullptr ); \
|
||||||
: ssl_wrapper(obj) {} \
|
name( name&& move ); \
|
||||||
~name() \
|
~name(); \
|
||||||
{ \
|
name& operator=( name&& move ); \
|
||||||
if( obj != nullptr ) \
|
|
||||||
free_func(obj); \
|
|
||||||
} \
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SSL_TYPE(ec_group, EC_GROUP, EC_GROUP_free)
|
SSL_TYPE_DECL(ec_group, EC_GROUP)
|
||||||
SSL_TYPE(ec_point, EC_POINT, EC_POINT_free)
|
SSL_TYPE_DECL(ec_point, EC_POINT)
|
||||||
SSL_TYPE(ecdsa_sig, ECDSA_SIG, ECDSA_SIG_free)
|
SSL_TYPE_DECL(ecdsa_sig, ECDSA_SIG)
|
||||||
SSL_TYPE(bn_ctx, BN_CTX, BN_CTX_free)
|
SSL_TYPE_DECL(bn_ctx, BN_CTX)
|
||||||
SSL_TYPE(evp_cipher_ctx, EVP_CIPHER_CTX, EVP_CIPHER_CTX_free )
|
SSL_TYPE_DECL(evp_cipher_ctx, EVP_CIPHER_CTX)
|
||||||
|
SSL_TYPE_DECL(ssl_dh, DH)
|
||||||
|
|
||||||
/** allocates a bignum by default.. */
|
/** allocates a bignum by default.. */
|
||||||
struct ssl_bignum : public ssl_wrapper<BIGNUM>
|
struct ssl_bignum : public ssl_wrapper<BIGNUM>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class ripemd160
|
||||||
explicit operator string()const;
|
explicit operator string()const;
|
||||||
|
|
||||||
char* data()const;
|
char* data()const;
|
||||||
size_t data_size()const { return 160/8; }
|
static constexpr size_t data_size() { return 160/8; }
|
||||||
|
|
||||||
static ripemd160 hash( const fc::sha512& h );
|
static ripemd160 hash( const fc::sha512& h );
|
||||||
static ripemd160 hash( const fc::sha256& h );
|
static ripemd160 hash( const fc::sha256& h );
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class sha1
|
||||||
operator std::string()const;
|
operator std::string()const;
|
||||||
|
|
||||||
char* data()const;
|
char* data()const;
|
||||||
size_t data_size()const { return 20; }
|
static constexpr size_t data_size() { return 20; }
|
||||||
|
|
||||||
static sha1 hash( const char* d, uint32_t dlen );
|
static sha1 hash( const char* d, uint32_t dlen );
|
||||||
static sha1 hash( const std::string& );
|
static sha1 hash( const std::string& );
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class sha224
|
||||||
operator string()const;
|
operator string()const;
|
||||||
|
|
||||||
char* data()const;
|
char* data()const;
|
||||||
size_t data_size()const { return 224 / 8; }
|
static constexpr size_t data_size() { return 224 / 8; }
|
||||||
|
|
||||||
static sha224 hash( const char* d, uint32_t dlen );
|
static sha224 hash( const char* d, uint32_t dlen );
|
||||||
static sha224 hash( const string& );
|
static sha224 hash( const string& );
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class sha256
|
||||||
operator string()const;
|
operator string()const;
|
||||||
|
|
||||||
char* data()const;
|
char* data()const;
|
||||||
size_t data_size()const { return 256 / 8; }
|
static constexpr size_t data_size() { return 256 / 8; }
|
||||||
|
|
||||||
static sha256 hash( const char* d, uint32_t dlen );
|
static sha256 hash( const char* d, uint32_t dlen );
|
||||||
static sha256 hash( const string& );
|
static sha256 hash( const string& );
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <boost/endian/buffers.hpp>
|
#include <boost/endian/buffers.hpp>
|
||||||
|
#include <fc/io/raw_fwd.hpp>
|
||||||
#include <fc/fwd.hpp>
|
#include <fc/fwd.hpp>
|
||||||
|
|
||||||
namespace fc
|
namespace fc
|
||||||
|
|
@ -9,16 +10,16 @@ class sha512
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
sha512();
|
sha512();
|
||||||
explicit sha512( const string& hex_str );
|
explicit sha512( const std::string& hex_str );
|
||||||
|
|
||||||
string str()const;
|
std::string str()const;
|
||||||
operator string()const;
|
operator std::string()const;
|
||||||
|
|
||||||
char* data()const;
|
char* data()const;
|
||||||
size_t data_size()const { return 512 / 8; }
|
static constexpr size_t data_size() { return 512 / 8; }
|
||||||
|
|
||||||
static sha512 hash( const char* d, uint32_t dlen );
|
static sha512 hash( const char* d, uint32_t dlen );
|
||||||
static sha512 hash( const string& );
|
static sha512 hash( const std::string& );
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static sha512 hash( const T& t )
|
static sha512 hash( const T& t )
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
*/
|
*/
|
||||||
#include <fc/log/logger.hpp>
|
#include <fc/log/logger.hpp>
|
||||||
#include <fc/optional.hpp>
|
#include <fc/optional.hpp>
|
||||||
#include <fc/utility.hpp>
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
@ -107,7 +106,7 @@ namespace fc
|
||||||
*
|
*
|
||||||
* @note does not return.
|
* @note does not return.
|
||||||
*/
|
*/
|
||||||
virtual NO_RETURN void dynamic_rethrow_exception()const;
|
[[noreturn]] virtual void dynamic_rethrow_exception()const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is equivalent to:
|
* This is equivalent to:
|
||||||
|
|
@ -156,7 +155,7 @@ namespace fc
|
||||||
|
|
||||||
std::exception_ptr get_inner_exception()const;
|
std::exception_ptr get_inner_exception()const;
|
||||||
|
|
||||||
virtual NO_RETURN void dynamic_rethrow_exception()const;
|
[[noreturn]] virtual void dynamic_rethrow_exception()const;
|
||||||
virtual std::shared_ptr<exception> dynamic_copy_exception()const;
|
virtual std::shared_ptr<exception> dynamic_copy_exception()const;
|
||||||
private:
|
private:
|
||||||
std::exception_ptr _inner;
|
std::exception_ptr _inner;
|
||||||
|
|
@ -167,10 +166,10 @@ namespace fc
|
||||||
{
|
{
|
||||||
#if defined(_MSC_VER) && (_MSC_VER < 1700)
|
#if defined(_MSC_VER) && (_MSC_VER < 1700)
|
||||||
return std::make_shared<unhandled_exception>( log_message(),
|
return std::make_shared<unhandled_exception>( log_message(),
|
||||||
std::copy_exception(fc::forward<T>(e)) );
|
std::copy_exception(std::forward<T>(e)) );
|
||||||
#else
|
#else
|
||||||
return std::make_shared<unhandled_exception>( log_message(),
|
return std::make_shared<unhandled_exception>( log_message(),
|
||||||
std::make_exception_ptr(fc::forward<T>(e)) );
|
std::make_exception_ptr(std::forward<T>(e)) );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,13 +179,13 @@ namespace fc
|
||||||
public:
|
public:
|
||||||
struct base_exception_builder
|
struct base_exception_builder
|
||||||
{
|
{
|
||||||
virtual NO_RETURN void rethrow( const exception& e )const = 0;
|
[[noreturn]] virtual void rethrow( const exception& e )const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct exception_builder : public base_exception_builder
|
struct exception_builder : public base_exception_builder
|
||||||
{
|
{
|
||||||
virtual NO_RETURN void rethrow( const exception& e )const override
|
[[noreturn]] virtual void rethrow( const exception& e )const override
|
||||||
{
|
{
|
||||||
throw T( e );
|
throw T( e );
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +201,7 @@ namespace fc
|
||||||
_registered_exceptions[T::code_value] = &builder;
|
_registered_exceptions[T::code_value] = &builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NO_RETURN rethrow( const exception& e )const;
|
[[noreturn]] void rethrow( const exception& e )const;
|
||||||
|
|
||||||
static exception_factory& instance()
|
static exception_factory& instance()
|
||||||
{
|
{
|
||||||
|
|
@ -244,7 +243,7 @@ namespace fc
|
||||||
explicit TYPE();\
|
explicit TYPE();\
|
||||||
\
|
\
|
||||||
virtual std::shared_ptr<fc::exception> dynamic_copy_exception()const;\
|
virtual std::shared_ptr<fc::exception> dynamic_copy_exception()const;\
|
||||||
virtual NO_RETURN void dynamic_rethrow_exception()const; \
|
[[noreturn]] virtual void dynamic_rethrow_exception()const; \
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FC_IMPLEMENT_DERIVED_EXCEPTION( TYPE, BASE, CODE, WHAT ) \
|
#define FC_IMPLEMENT_DERIVED_EXCEPTION( TYPE, BASE, CODE, WHAT ) \
|
||||||
|
|
@ -270,7 +269,7 @@ namespace fc
|
||||||
{ \
|
{ \
|
||||||
return std::make_shared<TYPE>( *this ); \
|
return std::make_shared<TYPE>( *this ); \
|
||||||
} \
|
} \
|
||||||
NO_RETURN void TYPE::dynamic_rethrow_exception()const \
|
[[noreturn]] void TYPE::dynamic_rethrow_exception()const \
|
||||||
{ \
|
{ \
|
||||||
if( code() == CODE ) throw *this;\
|
if( code() == CODE ) throw *this;\
|
||||||
else fc::exception::dynamic_rethrow_exception(); \
|
else fc::exception::dynamic_rethrow_exception(); \
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fc/utility.hpp>
|
|
||||||
#include <fc/fwd.hpp>
|
#include <fc/fwd.hpp>
|
||||||
|
#include <cstdint>
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
@ -41,10 +41,10 @@ namespace fc {
|
||||||
|
|
||||||
|
|
||||||
template<typename T, unsigned int S, typename U, typename A>
|
template<typename T, unsigned int S, typename U, typename A>
|
||||||
auto operator + ( const fwd<T,S,A>& x, U&& u ) -> typename detail::add<T,U>::type { return *x+fc::forward<U>(u); }
|
auto operator + ( const fwd<T,S,A>& x, U&& u ) -> typename detail::add<T,U>::type { return *x+std::forward<U>(u); }
|
||||||
|
|
||||||
template<typename T, unsigned int S, typename U, typename A>
|
template<typename T, unsigned int S, typename U, typename A>
|
||||||
auto operator - ( const fwd<T,S,A>& x, U&& u ) -> typename detail::sub<T,U>::type { return *x-fc::forward<U>(u); }
|
auto operator - ( const fwd<T,S,A>& x, U&& u ) -> typename detail::sub<T,U>::type { return *x-std::forward<U>(u); }
|
||||||
|
|
||||||
template<typename T, unsigned int S, typename U, typename A>
|
template<typename T, unsigned int S, typename U, typename A>
|
||||||
auto operator << ( U& u, const fwd<T,S,A>& f ) -> typename detail::insert_op<U,T>::type { return u << *f; }
|
auto operator << ( U& u, const fwd<T,S,A>& f ) -> typename detail::insert_op<U,T>::type { return u << *f; }
|
||||||
|
|
@ -63,20 +63,20 @@ namespace fc {
|
||||||
template<typename U>
|
template<typename U>
|
||||||
fwd<T,S,A>::fwd( U&& u ) {
|
fwd<T,S,A>::fwd( U&& u ) {
|
||||||
check_size<sizeof(T),sizeof(_store)>();
|
check_size<sizeof(T),sizeof(_store)>();
|
||||||
new (this) T( fc::forward<U>(u) );
|
new (this) T( std::forward<U>(u) );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T,unsigned int S,typename A>
|
template<typename T,unsigned int S,typename A>
|
||||||
template<typename U,typename V>
|
template<typename U,typename V>
|
||||||
fwd<T,S,A>::fwd( U&& u, V&& v ) {
|
fwd<T,S,A>::fwd( U&& u, V&& v ) {
|
||||||
check_size<sizeof(T),sizeof(_store)>();
|
check_size<sizeof(T),sizeof(_store)>();
|
||||||
new (this) T( fc::forward<U>(u), fc::forward<V>(v) );
|
new (this) T( std::forward<U>(u), std::forward<V>(v) );
|
||||||
}
|
}
|
||||||
template<typename T,unsigned int S,typename A>
|
template<typename T,unsigned int S,typename A>
|
||||||
template<typename U,typename V,typename X,typename Y>
|
template<typename U,typename V,typename X,typename Y>
|
||||||
fwd<T,S,A>::fwd( U&& u, V&& v, X&& x, Y&& y ) {
|
fwd<T,S,A>::fwd( U&& u, V&& v, X&& x, Y&& y ) {
|
||||||
check_size<sizeof(T),sizeof(_store)>();
|
check_size<sizeof(T),sizeof(_store)>();
|
||||||
new (this) T( fc::forward<U>(u), fc::forward<V>(v), fc::forward<X>(x), fc::forward<Y>(y) );
|
new (this) T( std::forward<U>(u), std::forward<V>(v), std::forward<X>(x), std::forward<Y>(y) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ namespace fc {
|
||||||
template<typename T,unsigned int S, typename A>
|
template<typename T,unsigned int S, typename A>
|
||||||
template<typename U>
|
template<typename U>
|
||||||
T& fwd<T,S,A>::operator = ( U&& u ) {
|
T& fwd<T,S,A>::operator = ( U&& u ) {
|
||||||
return **this = fc::forward<U>(u);
|
return **this = std::forward<U>(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T,unsigned int S, typename A>
|
template<typename T,unsigned int S, typename A>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fc/utility.hpp>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
@ -7,7 +6,7 @@ namespace fc {
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
NO_RETURN void throw_datastream_range_error( const char* file, size_t len, int64_t over );
|
[[noreturn]] void throw_datastream_range_error( const char* file, size_t len, int64_t over );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fc/shared_ptr.hpp>
|
|
||||||
#include <fc/filesystem.hpp>
|
#include <fc/filesystem.hpp>
|
||||||
#include <fc/io/iostream.hpp>
|
#include <fc/io/iostream.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
class path;
|
class path;
|
||||||
|
|
@ -21,7 +21,7 @@ namespace fc {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class impl;
|
class impl;
|
||||||
fc::shared_ptr<impl> my;
|
std::shared_ptr<impl> my;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ifstream : virtual public istream {
|
class ifstream : virtual public istream {
|
||||||
|
|
@ -44,7 +44,7 @@ namespace fc {
|
||||||
bool eof()const;
|
bool eof()const;
|
||||||
private:
|
private:
|
||||||
class impl;
|
class impl;
|
||||||
fc::shared_ptr<impl> my;
|
std::shared_ptr<impl> my;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <boost/endian/buffers.hpp>
|
#include <boost/endian/buffers.hpp>
|
||||||
|
|
||||||
#include <fc/io/raw_variant.hpp>
|
#include <fc/io/raw_variant.hpp>
|
||||||
#include <fc/reflect/reflect.hpp>
|
#include <fc/reflect/reflect.hpp>
|
||||||
#include <fc/io/datastream.hpp>
|
#include <fc/io/datastream.hpp>
|
||||||
#include <fc/io/varint.hpp>
|
|
||||||
#include <fc/optional.hpp>
|
#include <fc/optional.hpp>
|
||||||
#include <fc/fwd.hpp>
|
#include <fc/fwd.hpp>
|
||||||
#include <fc/array.hpp>
|
|
||||||
#include <fc/time.hpp>
|
#include <fc/time.hpp>
|
||||||
#include <fc/filesystem.hpp>
|
#include <fc/filesystem.hpp>
|
||||||
#include <fc/exception/exception.hpp>
|
#include <fc/exception/exception.hpp>
|
||||||
#include <fc/safe.hpp>
|
|
||||||
#include <fc/io/raw_fwd.hpp>
|
#include <fc/io/raw_fwd.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
@ -27,6 +25,22 @@ namespace fc {
|
||||||
pack( s, args..., _max_depth );
|
pack( s, args..., _max_depth );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Stream>
|
||||||
|
inline void pack( Stream& s, const uint128_t& v, uint32_t _max_depth )
|
||||||
|
{
|
||||||
|
boost::endian::little_uint64_buf_at hilo[2];
|
||||||
|
hilo[0] = uint128_hi64( v );
|
||||||
|
hilo[1] = uint128_lo64( v );
|
||||||
|
s.write( hilo[0].data(), sizeof(hilo) );
|
||||||
|
}
|
||||||
|
template<typename Stream>
|
||||||
|
inline void unpack( Stream& s, uint128_t& v, uint32_t _max_depth )
|
||||||
|
{
|
||||||
|
boost::endian::little_uint64_buf_at hilo[2];
|
||||||
|
s.read( (char*) hilo, sizeof(hilo) );
|
||||||
|
v = uint128( hilo[0].value(), hilo[1].value() );
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Stream>
|
template<typename Stream>
|
||||||
inline void pack( Stream& s, const fc::exception& e, uint32_t _max_depth )
|
inline void pack( Stream& s, const fc::exception& e, uint32_t _max_depth )
|
||||||
{
|
{
|
||||||
|
|
@ -130,22 +144,22 @@ namespace fc {
|
||||||
} FC_RETHROW_EXCEPTIONS( warn, "" ) }
|
} FC_RETHROW_EXCEPTIONS( warn, "" ) }
|
||||||
|
|
||||||
template<typename Stream, size_t N>
|
template<typename Stream, size_t N>
|
||||||
inline void pack( Stream& s, const fc::array<char,N>& v, uint32_t _max_depth ) {
|
inline void pack( Stream& s, const std::array<char,N>& v, uint32_t _max_depth ) {
|
||||||
s.write( &v.data[0], N );
|
s.write( v.data(), N );
|
||||||
}
|
}
|
||||||
template<typename Stream, size_t N>
|
template<typename Stream, size_t N>
|
||||||
inline void pack( Stream& s, const fc::array<unsigned char,N>& v, uint32_t _max_depth ) {
|
inline void pack( Stream& s, const std::array<unsigned char,N>& v, uint32_t _max_depth ) {
|
||||||
s.write( (char*)&v.data[0], N );
|
s.write( (char*)v.data(), N );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Stream, size_t N>
|
template<typename Stream, size_t N>
|
||||||
inline void unpack( Stream& s, fc::array<char,N>& v, uint32_t _max_depth ) { try {
|
inline void unpack( Stream& s, std::array<char,N>& v, uint32_t _max_depth ) { try {
|
||||||
s.read( &v.data[0], N );
|
s.read( v.data(), N );
|
||||||
} FC_RETHROW_EXCEPTIONS( warn, "fc::array<char,${length}>", ("length",N) ) }
|
} FC_RETHROW_EXCEPTIONS( warn, "std::array<char,${length}>", ("length",N) ) }
|
||||||
template<typename Stream, size_t N>
|
template<typename Stream, size_t N>
|
||||||
inline void unpack( Stream& s, fc::array<unsigned char,N>& v, uint32_t _max_depth ) { try {
|
inline void unpack( Stream& s, std::array<unsigned char,N>& v, uint32_t _max_depth ) { try {
|
||||||
s.read( (char*)&v.data[0], N );
|
s.read( (char*)v.data(), N );
|
||||||
} FC_RETHROW_EXCEPTIONS( warn, "fc::array<unsigned char,${length}>", ("length",N) ) }
|
} FC_RETHROW_EXCEPTIONS( warn, "std::array<unsigned char,${length}>", ("length",N) ) }
|
||||||
|
|
||||||
template<typename Stream, typename T>
|
template<typename Stream, typename T>
|
||||||
inline void pack( Stream& s, const std::shared_ptr<T>& v, uint32_t _max_depth )
|
inline void pack( Stream& s, const std::shared_ptr<T>& v, uint32_t _max_depth )
|
||||||
|
|
@ -293,7 +307,7 @@ namespace fc {
|
||||||
template<typename Stream> inline void pack( Stream& s, const bool& v, uint32_t _max_depth )
|
template<typename Stream> inline void pack( Stream& s, const bool& v, uint32_t _max_depth )
|
||||||
{
|
{
|
||||||
FC_ASSERT( _max_depth > 0 );
|
FC_ASSERT( _max_depth > 0 );
|
||||||
fc::raw::pack( s, uint8_t(v), _max_depth - 1 );
|
fc::raw::pack( s, v ? uint8_t(1) : uint8_t(0), _max_depth - 1 );
|
||||||
}
|
}
|
||||||
template<typename Stream> inline void unpack( Stream& s, bool& v, uint32_t _max_depth )
|
template<typename Stream> inline void unpack( Stream& s, bool& v, uint32_t _max_depth )
|
||||||
{
|
{
|
||||||
|
|
@ -342,17 +356,21 @@ namespace fc {
|
||||||
const uint32_t max_depth;
|
const uint32_t max_depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default pack/unpack functions for classes (if_class<fc::true_type>) are removed due to recursion issue.
|
// Default pack/unpack functions for classes are removed due to recursion issue.
|
||||||
// Classes should implement pack/unpack functions explicitly.
|
// Classes should implement pack/unpack functions explicitly.
|
||||||
template<typename IsClass=fc::true_type>
|
template<typename T, typename Dummy = void>
|
||||||
struct if_class;
|
struct if_class;
|
||||||
|
|
||||||
template<>
|
template<typename T>
|
||||||
struct if_class<fc::false_type> {
|
struct if_class<T, std::enable_if_t<!std::is_class<T>::value>> {
|
||||||
template<typename Stream, typename T>
|
template<typename Stream>
|
||||||
static inline void pack( Stream& s, const T v, uint32_t _max_depth ) = delete;
|
static inline void pack( Stream& s, const T v, uint32_t _max_depth ) = delete;
|
||||||
template<typename Stream, typename T>
|
template<typename Stream>
|
||||||
static inline void unpack( Stream& s, T& v, uint32_t _max_depth ) = delete;
|
static inline void unpack( Stream& s, T& v, uint32_t _max_depth ) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct if_class<int64_t, void> {
|
||||||
template<typename Stream>
|
template<typename Stream>
|
||||||
static inline void pack( Stream& s, const int64_t v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const int64_t v, uint32_t _max_depth ) {
|
||||||
boost::endian::little_int64_buf_t tmp;
|
boost::endian::little_int64_buf_t tmp;
|
||||||
|
|
@ -365,6 +383,10 @@ namespace fc {
|
||||||
s.read( (char*)&tmp, sizeof(tmp) );
|
s.read( (char*)&tmp, sizeof(tmp) );
|
||||||
v = tmp.value();
|
v = tmp.value();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct if_class<uint64_t, void> {
|
||||||
template<typename Stream>
|
template<typename Stream>
|
||||||
static inline void pack( Stream& s, const uint64_t v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const uint64_t v, uint32_t _max_depth ) {
|
||||||
boost::endian::little_uint64_buf_t tmp;
|
boost::endian::little_uint64_buf_t tmp;
|
||||||
|
|
@ -377,6 +399,10 @@ namespace fc {
|
||||||
s.read( (char*)&tmp, sizeof(tmp) );
|
s.read( (char*)&tmp, sizeof(tmp) );
|
||||||
v = tmp.value();
|
v = tmp.value();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct if_class<int32_t, void> {
|
||||||
template<typename Stream>
|
template<typename Stream>
|
||||||
static inline void pack( Stream& s, const int32_t v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const int32_t v, uint32_t _max_depth ) {
|
||||||
boost::endian::little_int32_buf_t tmp;
|
boost::endian::little_int32_buf_t tmp;
|
||||||
|
|
@ -389,6 +415,10 @@ namespace fc {
|
||||||
s.read( (char*)&tmp, sizeof(tmp) );
|
s.read( (char*)&tmp, sizeof(tmp) );
|
||||||
v = tmp.value();
|
v = tmp.value();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct if_class<uint32_t, void> {
|
||||||
template<typename Stream>
|
template<typename Stream>
|
||||||
static inline void pack( Stream& s, const uint32_t v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const uint32_t v, uint32_t _max_depth ) {
|
||||||
boost::endian::little_uint32_buf_t tmp;
|
boost::endian::little_uint32_buf_t tmp;
|
||||||
|
|
@ -401,6 +431,10 @@ namespace fc {
|
||||||
s.read( (char*)&tmp, sizeof(tmp) );
|
s.read( (char*)&tmp, sizeof(tmp) );
|
||||||
v = tmp.value();
|
v = tmp.value();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct if_class<int16_t, void> {
|
||||||
template<typename Stream>
|
template<typename Stream>
|
||||||
static inline void pack( Stream& s, const int16_t v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const int16_t v, uint32_t _max_depth ) {
|
||||||
boost::endian::little_int16_buf_t tmp;
|
boost::endian::little_int16_buf_t tmp;
|
||||||
|
|
@ -413,6 +447,10 @@ namespace fc {
|
||||||
s.read( (char*)&tmp, sizeof(tmp) );
|
s.read( (char*)&tmp, sizeof(tmp) );
|
||||||
v = tmp.value();
|
v = tmp.value();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct if_class<uint16_t, void> {
|
||||||
template<typename Stream>
|
template<typename Stream>
|
||||||
static inline void pack( Stream& s, const uint16_t v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const uint16_t v, uint32_t _max_depth ) {
|
||||||
boost::endian::little_uint16_buf_t tmp;
|
boost::endian::little_uint16_buf_t tmp;
|
||||||
|
|
@ -425,6 +463,10 @@ namespace fc {
|
||||||
s.read( (char*)&tmp, sizeof(tmp) );
|
s.read( (char*)&tmp, sizeof(tmp) );
|
||||||
v = tmp.value();
|
v = tmp.value();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct if_class<int8_t, void> {
|
||||||
template<typename Stream>
|
template<typename Stream>
|
||||||
static inline void pack( Stream& s, const int8_t v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const int8_t v, uint32_t _max_depth ) {
|
||||||
s.write( (char*)&v, 1 );
|
s.write( (char*)&v, 1 );
|
||||||
|
|
@ -433,6 +475,10 @@ namespace fc {
|
||||||
static inline void unpack( Stream& s, int8_t& v, uint32_t _max_depth ) {
|
static inline void unpack( Stream& s, int8_t& v, uint32_t _max_depth ) {
|
||||||
s.read( (char*)&v, 1 );
|
s.read( (char*)&v, 1 );
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct if_class<uint8_t, void> {
|
||||||
template<typename Stream>
|
template<typename Stream>
|
||||||
static inline void pack( Stream& s, const uint8_t v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const uint8_t v, uint32_t _max_depth ) {
|
||||||
s.write( (char*)&v, 1 );
|
s.write( (char*)&v, 1 );
|
||||||
|
|
@ -443,27 +489,29 @@ namespace fc {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename IsEnum=fc::false_type>
|
template<typename T, typename Dummy=void>
|
||||||
struct if_enum {
|
struct if_enum;
|
||||||
template<typename Stream, typename T>
|
template<typename T>
|
||||||
|
struct if_enum<T, std::enable_if_t<!std::is_enum<T>::value>> {
|
||||||
|
template<typename Stream>
|
||||||
static inline void pack( Stream& s, const T& v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const T& v, uint32_t _max_depth ) {
|
||||||
FC_ASSERT( _max_depth > 0 );
|
FC_ASSERT( _max_depth > 0 );
|
||||||
fc::reflector<T>::visit( pack_object_visitor<Stream,T>( v, s, _max_depth - 1 ) );
|
fc::reflector<T>::visit( pack_object_visitor<Stream,T>( v, s, _max_depth - 1 ) );
|
||||||
}
|
}
|
||||||
template<typename Stream, typename T>
|
template<typename Stream>
|
||||||
static inline void unpack( Stream& s, T& v, uint32_t _max_depth ) {
|
static inline void unpack( Stream& s, T& v, uint32_t _max_depth ) {
|
||||||
FC_ASSERT( _max_depth > 0 );
|
FC_ASSERT( _max_depth > 0 );
|
||||||
fc::reflector<T>::visit( unpack_object_visitor<Stream,T>( v, s, _max_depth - 1 ) );
|
fc::reflector<T>::visit( unpack_object_visitor<Stream,T>( v, s, _max_depth - 1 ) );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<>
|
template<typename T>
|
||||||
struct if_enum<fc::true_type> {
|
struct if_enum<T, std::enable_if_t<std::is_enum<T>::value>> {
|
||||||
template<typename Stream, typename T>
|
template<typename Stream>
|
||||||
static inline void pack( Stream& s, const T& v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const T& v, uint32_t _max_depth ) {
|
||||||
FC_ASSERT( _max_depth > 0 );
|
FC_ASSERT( _max_depth > 0 );
|
||||||
fc::raw::pack( s, (int64_t)v, _max_depth - 1 );
|
fc::raw::pack( s, (int64_t)v, _max_depth - 1 );
|
||||||
}
|
}
|
||||||
template<typename Stream, typename T>
|
template<typename Stream>
|
||||||
static inline void unpack( Stream& s, T& v, uint32_t _max_depth ) {
|
static inline void unpack( Stream& s, T& v, uint32_t _max_depth ) {
|
||||||
FC_ASSERT( _max_depth > 0 );
|
FC_ASSERT( _max_depth > 0 );
|
||||||
int64_t temp;
|
int64_t temp;
|
||||||
|
|
@ -472,30 +520,30 @@ namespace fc {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename IsReflected=fc::false_type>
|
template<typename IsReflected=std::false_type>
|
||||||
struct if_reflected {
|
struct if_reflected {
|
||||||
template<typename Stream, typename T>
|
template<typename Stream, typename T>
|
||||||
static inline void pack( Stream& s, const T& v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const T& v, uint32_t _max_depth ) {
|
||||||
FC_ASSERT( _max_depth > 0 );
|
FC_ASSERT( _max_depth > 0 );
|
||||||
if_class<typename fc::is_class<T>::type>::pack( s, v, _max_depth - 1 );
|
if_class<T>::pack( s, v, _max_depth - 1 );
|
||||||
}
|
}
|
||||||
template<typename Stream, typename T>
|
template<typename Stream, typename T>
|
||||||
static inline void unpack( Stream& s, T& v, uint32_t _max_depth ) {
|
static inline void unpack( Stream& s, T& v, uint32_t _max_depth ) {
|
||||||
FC_ASSERT( _max_depth > 0 );
|
FC_ASSERT( _max_depth > 0 );
|
||||||
if_class<typename fc::is_class<T>::type>::unpack( s, v, _max_depth - 1 );
|
if_class<T>::unpack( s, v, _max_depth - 1 );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<>
|
template<>
|
||||||
struct if_reflected<fc::true_type> {
|
struct if_reflected<std::true_type> {
|
||||||
template<typename Stream, typename T>
|
template<typename Stream, typename T>
|
||||||
static inline void pack( Stream& s, const T& v, uint32_t _max_depth ) {
|
static inline void pack( Stream& s, const T& v, uint32_t _max_depth ) {
|
||||||
FC_ASSERT( _max_depth > 0 );
|
FC_ASSERT( _max_depth > 0 );
|
||||||
if_enum< typename fc::reflector<T>::is_enum >::pack( s, v, _max_depth - 1 );
|
if_enum<T>::pack( s, v, _max_depth - 1 );
|
||||||
}
|
}
|
||||||
template<typename Stream, typename T>
|
template<typename Stream, typename T>
|
||||||
static inline void unpack( Stream& s, T& v, uint32_t _max_depth ) {
|
static inline void unpack( Stream& s, T& v, uint32_t _max_depth ) {
|
||||||
FC_ASSERT( _max_depth > 0 );
|
FC_ASSERT( _max_depth > 0 );
|
||||||
if_enum< typename fc::reflector<T>::is_enum >::unpack( s, v, _max_depth - 1 );
|
if_enum<T>::unpack( s, v, _max_depth - 1 );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <boost/endian/buffers.hpp>
|
#include <boost/endian/buffers.hpp>
|
||||||
|
|
||||||
#include <fc/config.hpp>
|
#include <fc/config.hpp>
|
||||||
#include <fc/container/flat_fwd.hpp>
|
#include <fc/container/flat_fwd.hpp>
|
||||||
#include <fc/io/varint.hpp>
|
#include <fc/io/varint.hpp>
|
||||||
#include <fc/array.hpp>
|
|
||||||
#include <fc/safe.hpp>
|
#include <fc/safe.hpp>
|
||||||
|
#include <fc/uint128.hpp>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
@ -41,7 +45,10 @@ namespace fc {
|
||||||
template<typename Stream, typename IntType, typename EnumType>
|
template<typename Stream, typename IntType, typename EnumType>
|
||||||
inline void unpack( Stream& s, fc::enum_type<IntType,EnumType>& tp, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
inline void unpack( Stream& s, fc::enum_type<IntType,EnumType>& tp, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
|
|
||||||
|
template<typename Stream>
|
||||||
|
inline void pack( Stream& s, const uint128_t& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
|
template<typename Stream>
|
||||||
|
inline void unpack( Stream& s, uint128_t& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
|
|
||||||
template<typename Stream, typename T> inline void pack( Stream& s, const std::set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
template<typename Stream, typename T> inline void pack( Stream& s, const std::set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
template<typename Stream, typename T> inline void unpack( Stream& s, std::set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
template<typename Stream, typename T> inline void unpack( Stream& s, std::set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
|
|
@ -124,22 +131,26 @@ namespace fc {
|
||||||
inline void unpack( Stream& s, boost::endian::endian_buffer<O,T,N,A>& v, uint32_t _max_depth );
|
inline void unpack( Stream& s, boost::endian::endian_buffer<O,T,N,A>& v, uint32_t _max_depth );
|
||||||
|
|
||||||
template<typename Stream, typename T, size_t N>
|
template<typename Stream, typename T, size_t N>
|
||||||
inline void pack( Stream& s, const fc::array<T,N>& v, uint32_t _max_depth ) = delete;
|
inline void pack( Stream& s, const std::array<T,N>& v, uint32_t _max_depth ) = delete;
|
||||||
template<typename Stream, typename T, size_t N>
|
template<typename Stream, typename T, size_t N>
|
||||||
inline void unpack( Stream& s, fc::array<T,N>& v, uint32_t _max_depth ) = delete;
|
inline void unpack( Stream& s, std::array<T,N>& v, uint32_t _max_depth ) = delete;
|
||||||
template<typename Stream, size_t N> inline void pack( Stream& s, const fc::array<char,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
template<typename Stream, size_t N>
|
||||||
template<typename Stream, size_t N> inline void unpack( Stream& s, fc::array<char,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH);
|
inline void pack( Stream& s, const std::array<char,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
template<typename Stream, size_t N> inline void pack( Stream& s, const fc::array<unsigned char,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
template<typename Stream, size_t N>
|
||||||
template<typename Stream, size_t N> inline void unpack( Stream& s, fc::array<unsigned char,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH);
|
inline void unpack( Stream& s, std::array<char,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH);
|
||||||
|
template<typename Stream, size_t N>
|
||||||
|
inline void pack( Stream& s, const std::array<unsigned char,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
|
template<typename Stream, size_t N>
|
||||||
|
inline void unpack( Stream& s, std::array<unsigned char,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH);
|
||||||
|
|
||||||
template<typename Stream, typename T> inline void pack( Stream& s, const shared_ptr<T>& v,
|
template<typename Stream, typename T> inline void pack( Stream& s, const std::shared_ptr<T>& v,
|
||||||
uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
template<typename Stream, typename T> inline void unpack( Stream& s, shared_ptr<T>& v,
|
template<typename Stream, typename T> inline void unpack( Stream& s, std::shared_ptr<T>& v,
|
||||||
uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
|
|
||||||
template<typename Stream, typename T> inline void pack( Stream& s, const shared_ptr<const T>& v,
|
template<typename Stream, typename T> inline void pack( Stream& s, const std::shared_ptr<const T>& v,
|
||||||
uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
template<typename Stream, typename T> inline void unpack( Stream& s, shared_ptr<const T>& v,
|
template<typename Stream, typename T> inline void unpack( Stream& s, std::shared_ptr<const T>& v,
|
||||||
uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
|
|
||||||
template<typename Stream> inline void pack( Stream& s, const bool& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
template<typename Stream> inline void pack( Stream& s, const bool& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fc/shared_ptr.hpp>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
@ -7,33 +7,34 @@ namespace fc {
|
||||||
class log_message;
|
class log_message;
|
||||||
class variant;
|
class variant;
|
||||||
|
|
||||||
class appender_factory : public fc::retainable {
|
class appender_factory {
|
||||||
public:
|
public:
|
||||||
typedef fc::shared_ptr<appender_factory> ptr;
|
typedef std::shared_ptr<appender_factory> ptr;
|
||||||
|
|
||||||
virtual ~appender_factory(){};
|
virtual ~appender_factory(){};
|
||||||
virtual fc::shared_ptr<appender> create( const variant& args ) = 0;
|
virtual std::shared_ptr<appender> create( const variant& args ) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class appender_factory_impl : public appender_factory {
|
class appender_factory_impl : public appender_factory {
|
||||||
public:
|
public:
|
||||||
virtual fc::shared_ptr<appender> create( const variant& args ) {
|
virtual std::shared_ptr<appender> create( const variant& args ) {
|
||||||
return fc::shared_ptr<appender>(new T(args));
|
return std::shared_ptr<appender>(new T(args));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class appender : public fc::retainable {
|
class appender {
|
||||||
public:
|
public:
|
||||||
typedef fc::shared_ptr<appender> ptr;
|
typedef std::shared_ptr<appender> ptr;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static bool register_appender(const std::string& type) {
|
static bool register_appender(const std::string& type) {
|
||||||
return register_appender( type, new detail::appender_factory_impl<T>() );
|
return register_appender( type, appender_factory::ptr( new detail::appender_factory_impl<T>() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual ~appender() = default;
|
||||||
static appender::ptr create( const std::string& name, const std::string& type, const variant& args );
|
static appender::ptr create( const std::string& name, const std::string& type, const variant& args );
|
||||||
static appender::ptr get( const std::string& name );
|
static appender::ptr get( const std::string& name );
|
||||||
static bool register_appender( const std::string& type, const appender_factory::ptr& f );
|
static bool register_appender( const std::string& type, const appender_factory::ptr& f );
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ class file_appender : public appender {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class impl;
|
class impl;
|
||||||
fc::shared_ptr<impl> my;
|
std::unique_ptr<impl> my;
|
||||||
};
|
};
|
||||||
} // namespace fc
|
} // namespace fc
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace fc
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class impl;
|
class impl;
|
||||||
fc::shared_ptr<impl> my;
|
std::unique_ptr<impl> my;
|
||||||
};
|
};
|
||||||
} // namespace fc
|
} // namespace fc
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
#include <fc/config.hpp>
|
#include <fc/config.hpp>
|
||||||
#include <fc/time.hpp>
|
#include <fc/time.hpp>
|
||||||
#include <fc/variant_object.hpp>
|
#include <fc/variant_object.hpp>
|
||||||
#include <fc/shared_ptr.hpp>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fc/config.hpp>
|
#include <fc/config.hpp>
|
||||||
#include <fc/time.hpp>
|
#include <fc/time.hpp>
|
||||||
#include <fc/shared_ptr.hpp>
|
#include <fc/log/appender.hpp>
|
||||||
#include <fc/log/log_message.hpp>
|
#include <fc/log/log_message.hpp>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace fc
|
namespace fc
|
||||||
{
|
{
|
||||||
|
|
||||||
class appender;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
|
@ -32,8 +31,8 @@ namespace fc
|
||||||
~logger();
|
~logger();
|
||||||
logger& operator=(const logger&);
|
logger& operator=(const logger&);
|
||||||
logger& operator=(logger&&);
|
logger& operator=(logger&&);
|
||||||
friend bool operator==( const logger&, nullptr_t );
|
friend bool operator==( const logger&, std::nullptr_t );
|
||||||
friend bool operator!=( const logger&, nullptr_t );
|
friend bool operator!=( const logger&, std::nullptr_t );
|
||||||
|
|
||||||
logger& set_log_level( log_level e );
|
logger& set_log_level( log_level e );
|
||||||
log_level get_log_level()const;
|
log_level get_log_level()const;
|
||||||
|
|
@ -43,16 +42,16 @@ namespace fc
|
||||||
void set_name( const std::string& n );
|
void set_name( const std::string& n );
|
||||||
const std::string& name()const;
|
const std::string& name()const;
|
||||||
|
|
||||||
void add_appender( const fc::shared_ptr<appender>& a );
|
void add_appender( const appender::ptr& a );
|
||||||
std::vector<fc::shared_ptr<appender> > get_appenders()const;
|
std::vector<appender::ptr> get_appenders()const;
|
||||||
void remove_appender( const fc::shared_ptr<appender>& a );
|
void remove_appender( const appender::ptr& a );
|
||||||
|
|
||||||
bool is_enabled( log_level e )const;
|
bool is_enabled( log_level e )const;
|
||||||
void log( log_message m );
|
void log( log_message m );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class impl;
|
class impl;
|
||||||
fc::shared_ptr<impl> my;
|
std::shared_ptr<impl> my;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fc
|
} // namespace fc
|
||||||
|
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <fc/network/http/connection.hpp>
|
|
||||||
#include <fc/shared_ptr.hpp>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace fc { namespace http {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listens on a given port for incomming http
|
|
||||||
* connections and then calls a user provided callback
|
|
||||||
* function for every http request.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class server
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
server();
|
|
||||||
server( uint16_t port );
|
|
||||||
server( server&& s );
|
|
||||||
~server();
|
|
||||||
|
|
||||||
server& operator=(server&& s);
|
|
||||||
|
|
||||||
class response
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
class impl;
|
|
||||||
|
|
||||||
response();
|
|
||||||
response( const fc::shared_ptr<impl>& my);
|
|
||||||
response( const response& r);
|
|
||||||
response( response&& r );
|
|
||||||
~response();
|
|
||||||
response& operator=(const response& );
|
|
||||||
response& operator=( response&& );
|
|
||||||
|
|
||||||
void add_header( const std::string& key, const std::string& val )const;
|
|
||||||
void set_status( const http::reply::status_code& s )const;
|
|
||||||
void set_length( uint64_t s )const;
|
|
||||||
|
|
||||||
void write( const char* data, uint64_t len )const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
fc::shared_ptr<impl> my;
|
|
||||||
};
|
|
||||||
|
|
||||||
void listen( const fc::ip::endpoint& p );
|
|
||||||
fc::ip::endpoint get_local_endpoint() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the callback to be called for every http request made.
|
|
||||||
*/
|
|
||||||
void on_request( const std::function<void(const http::request&, const server::response& s )>& cb );
|
|
||||||
|
|
||||||
private:
|
|
||||||
class impl;
|
|
||||||
std::unique_ptr<impl> my;
|
|
||||||
};
|
|
||||||
typedef std::shared_ptr<server> server_ptr;
|
|
||||||
|
|
||||||
} }
|
|
||||||
|
|
@ -12,7 +12,9 @@ namespace fc {
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
tcp_socket();
|
tcp_socket();
|
||||||
|
tcp_socket( tcp_socket& copy ) = delete;
|
||||||
~tcp_socket();
|
~tcp_socket();
|
||||||
|
tcp_socket& operator=( tcp_socket& copy ) = delete;
|
||||||
|
|
||||||
void connect_to( const fc::ip::endpoint& remote_endpoint );
|
void connect_to( const fc::ip::endpoint& remote_endpoint );
|
||||||
void bind( const fc::ip::endpoint& local_endpoint );
|
void bind( const fc::ip::endpoint& local_endpoint );
|
||||||
|
|
@ -51,9 +53,9 @@ namespace fc {
|
||||||
friend class tcp_server;
|
friend class tcp_server;
|
||||||
class impl;
|
class impl;
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
fc::fwd<impl,0x88> my;
|
fc::fwd<impl,0xa8> my;
|
||||||
#else
|
#else
|
||||||
fc::fwd<impl,0x54> my;
|
fc::fwd<impl,0x60> my;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr<tcp_socket> tcp_socket_ptr;
|
typedef std::shared_ptr<tcp_socket> tcp_socket_ptr;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fc/shared_ptr.hpp>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
@ -35,8 +34,8 @@ namespace fc {
|
||||||
fc::ip::endpoint local_endpoint()const;
|
fc::ip::endpoint local_endpoint()const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class impl;
|
class impl;
|
||||||
fc::shared_ptr<impl> my;
|
std::shared_ptr<impl> my;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fc/utility.hpp>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
|
|
@ -81,14 +79,14 @@ namespace fc {
|
||||||
optional( U&& u )
|
optional( U&& u )
|
||||||
:_valid(true)
|
:_valid(true)
|
||||||
{
|
{
|
||||||
new ((char*)ptr()) T( fc::forward<U>(u) );
|
new ((char*)ptr()) T( std::forward<U>(u) );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
optional& operator=( U&& u )
|
optional& operator=( U&& u )
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
new (ptr()) T( fc::forward<U>(u) );
|
new (ptr()) T( std::forward<U>(u) );
|
||||||
_valid = true;
|
_valid = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
40
include/fc/popcount.hpp
Normal file
40
include/fc/popcount.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 BitShares Blockchain Foundation, and contributors.
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fc/platform_independence.hpp>
|
||||||
|
#include <fc/uint128.hpp>
|
||||||
|
|
||||||
|
namespace fc {
|
||||||
|
|
||||||
|
#if _MSC_VER || __GNUC__ || __clang__
|
||||||
|
inline uint8_t popcount( uint64_t v ) { return __builtin_popcountll(v); }
|
||||||
|
#else
|
||||||
|
uint8_t popcount( uint64_t v );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t popcount( const fc::uint128_t& v );
|
||||||
|
|
||||||
|
} // namespace fc
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <fc/uint128.hpp>
|
|
||||||
|
|
||||||
#define FC_REAL128_PRECISION (uint64_t(1000000) * uint64_t(1000000) * uint64_t(1000000))
|
|
||||||
|
|
||||||
namespace fc {
|
|
||||||
class variant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides fixed point math operations based on decimal fractions
|
|
||||||
* with 18 places.
|
|
||||||
* Delegates to fc::bigint for multiplication and division.
|
|
||||||
*/
|
|
||||||
class real128
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
real128( uint64_t integer = 0);
|
|
||||||
explicit real128( const std::string& str );
|
|
||||||
operator std::string()const;
|
|
||||||
|
|
||||||
friend real128 operator * ( real128 a, const real128& b ) { a *= b; return a; }
|
|
||||||
friend real128 operator / ( real128 a, const real128& b ) { a /= b; return a; }
|
|
||||||
friend real128 operator + ( real128 a, const real128& b ) { a += b; return a; }
|
|
||||||
friend real128 operator - ( real128 a, const real128& b ) { a -= b; return a; }
|
|
||||||
|
|
||||||
real128& operator += ( const real128& o );
|
|
||||||
real128& operator -= ( const real128& o );
|
|
||||||
real128& operator /= ( const real128& o );
|
|
||||||
real128& operator *= ( const real128& o );
|
|
||||||
|
|
||||||
static real128 from_fixed( const uint128& fixed );
|
|
||||||
|
|
||||||
uint64_t to_uint64()const;
|
|
||||||
|
|
||||||
template<typename Stream>
|
|
||||||
inline void pack( Stream& s, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
|
|
||||||
pack( s, fixed, _max_depth );
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
uint128 fixed;
|
|
||||||
};
|
|
||||||
|
|
||||||
void to_variant( const real128& var, variant& vo, uint32_t max_depth = 1 );
|
|
||||||
void from_variant( const variant& var, real128& vo, uint32_t max_depth = 1 );
|
|
||||||
|
|
||||||
namespace raw
|
|
||||||
{
|
|
||||||
template<typename Stream>
|
|
||||||
inline void pack( Stream& s, const real128& value_to_pack, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
|
|
||||||
{ value_to_pack.pack( s, _max_depth ); }
|
|
||||||
|
|
||||||
template<typename Stream>
|
|
||||||
inline void unpack( Stream& s, real128& value_to_unpack, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
|
|
||||||
{
|
|
||||||
uint128_t delegate;
|
|
||||||
unpack( s, delegate, _max_depth );
|
|
||||||
value_to_unpack = fc::real128::from_fixed( delegate );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fc
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
/**
|
/**
|
||||||
* @file fc/reflect.hpp
|
* @file fc/reflect/reflect.hpp
|
||||||
*
|
*
|
||||||
* @brief Defines types and macros used to provide reflection.
|
* @brief Defines types and macros used to provide reflection.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <fc/string.hpp>
|
#include <fc/string.hpp>
|
||||||
#include <fc/utility.hpp>
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/preprocessor/seq/for_each.hpp>
|
#include <boost/preprocessor/seq/for_each.hpp>
|
||||||
#include <boost/preprocessor/seq/enum.hpp>
|
#include <boost/preprocessor/seq/enum.hpp>
|
||||||
|
|
@ -16,11 +15,117 @@
|
||||||
#include <boost/preprocessor/stringize.hpp>
|
#include <boost/preprocessor/stringize.hpp>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include <fc/reflect/typename.hpp>
|
#include <fc/reflect/typename.hpp>
|
||||||
|
#include <fc/reflect/typelist.hpp>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
|
template<typename> struct reflector;
|
||||||
|
namespace member_names {
|
||||||
|
/// A template which stores the name of the native member at a given index in a given class
|
||||||
|
template<typename Class, std::size_t index> struct member_name {
|
||||||
|
constexpr static const char* value = "Unknown member";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A template to store compile-time information about a field in a reflected struct
|
||||||
|
*
|
||||||
|
* @tparam Container The type of the struct or class containing the field
|
||||||
|
* @tparam Member The type of the field
|
||||||
|
* @tparam field A pointer-to-member for the reflected field
|
||||||
|
*/
|
||||||
|
template<std::size_t Index, typename Container, typename Member, Member Container::*field>
|
||||||
|
struct field_reflection {
|
||||||
|
using container = Container;
|
||||||
|
using type = Member;
|
||||||
|
using reflector = fc::reflector<type>;
|
||||||
|
constexpr static std::size_t index = Index;
|
||||||
|
constexpr static bool is_derived = false;
|
||||||
|
constexpr static type container::*pointer = field;
|
||||||
|
|
||||||
|
/// @brief Given a reference to the container type, get a reference to the field
|
||||||
|
static type& get(container& c) { return c.*field; }
|
||||||
|
static const type& get(const container& c) { return c.*field; }
|
||||||
|
/// @brief Get the name of the field
|
||||||
|
static const char* get_name() { return fc::member_names::member_name<container, index>::value; }
|
||||||
|
};
|
||||||
|
/// Basically the same as @ref field_reflection, but for inherited fields
|
||||||
|
/// Note that inherited field reflections do not have an index field; indexes are for native fields only
|
||||||
|
template<std::size_t IndexInBase, typename Base, typename Derived, typename Member, Member Base::*field>
|
||||||
|
struct inherited_field_reflection {
|
||||||
|
using container = Derived;
|
||||||
|
using field_container = Base;
|
||||||
|
using type = Member;
|
||||||
|
using reflector = fc::reflector<type>;
|
||||||
|
constexpr static std::size_t index_in_base = IndexInBase;
|
||||||
|
constexpr static bool is_derived = true;
|
||||||
|
constexpr static type field_container::*pointer = field;
|
||||||
|
|
||||||
|
static type& get(container& c) {
|
||||||
|
// And we need a distinct inherited_field_reflection type because this conversion can't be done statically
|
||||||
|
type container::* derived_field = field;
|
||||||
|
return c.*derived_field;
|
||||||
|
}
|
||||||
|
static const type& get(const container& c) {
|
||||||
|
type container::* derived_field = field;
|
||||||
|
return c.*derived_field;
|
||||||
|
}
|
||||||
|
static const char* get_name() {
|
||||||
|
using Reflector = typename fc::reflector<Base>::native_members::template at<IndexInBase>;
|
||||||
|
return Reflector::get_name();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
/// Helper template to create a @ref field_reflection without any commas (makes it macro-friendly)
|
||||||
|
template<typename Container>
|
||||||
|
struct Reflect_type {
|
||||||
|
template<typename Member>
|
||||||
|
struct with_field_type {
|
||||||
|
template<std::size_t Index>
|
||||||
|
struct at_index {
|
||||||
|
template<Member Container::*field>
|
||||||
|
struct with_field_pointer {
|
||||||
|
using type = field_reflection<Index, Container, Member, field>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/// Template to make a transformer of a @ref field_reflection from a base class to a derived class
|
||||||
|
template<typename Derived>
|
||||||
|
struct Derivation_reflection_transformer {
|
||||||
|
template<typename> struct transform;
|
||||||
|
template<std::size_t IndexInBase, typename BaseContainer, typename Member, Member BaseContainer::*field>
|
||||||
|
struct transform<field_reflection<IndexInBase, BaseContainer, Member, field>> {
|
||||||
|
using type = inherited_field_reflection<IndexInBase, BaseContainer, Derived, Member, field>;
|
||||||
|
};
|
||||||
|
template<std::size_t IndexInBase, typename BaseContainer, typename IntermediateContainer,
|
||||||
|
typename Member, Member BaseContainer::*field>
|
||||||
|
struct transform<inherited_field_reflection<IndexInBase, BaseContainer, IntermediateContainer, Member, field>> {
|
||||||
|
using type = inherited_field_reflection<IndexInBase, BaseContainer, Derived, Member, field>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
|
/// Macro to transform reflected fields of a base class to a derived class and concatenate them to a type list
|
||||||
|
#define FC_CONCAT_BASE_MEMBER_REFLECTIONS(r, derived, base) \
|
||||||
|
::add_list<typelist::transform<reflector<base>::members, impl::Derivation_reflection_transformer<derived>>>
|
||||||
|
/// Macro to concatenate a new @ref field_reflection to a typelist
|
||||||
|
#define FC_CONCAT_MEMBER_REFLECTION(r, container, idx, member) \
|
||||||
|
::add<typename impl::Reflect_type<container>::template with_field_type<decltype(container::member)> \
|
||||||
|
::template at_index<idx> \
|
||||||
|
::template with_field_pointer<&container::member>::type>
|
||||||
|
#define FC_REFLECT_MEMBER_NAME(r, container, idx, member) \
|
||||||
|
template<> struct member_name<container, idx> { constexpr static const char* value = BOOST_PP_STRINGIZE(member); };
|
||||||
|
#define FC_REFLECT_TEMPLATE_MEMBER_NAME(r, data, idx, member) \
|
||||||
|
template<BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_ELEM(0, data))> struct member_name<BOOST_PP_SEQ_ELEM(1, data), idx> { \
|
||||||
|
constexpr static const char* value = BOOST_PP_STRINGIZE(member); };
|
||||||
|
/// Macro to concatenate a new type to a typelist
|
||||||
|
#define FC_CONCAT_TYPE(r, x, TYPE) ::add<TYPE>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief defines visit functions for T
|
* @brief defines visit functions for T
|
||||||
* Unless this is specialized, visit() will not be defined for T.
|
* Unless this is specialized, visit() will not be defined for T.
|
||||||
|
|
@ -33,8 +138,15 @@ namespace fc {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct reflector{
|
struct reflector{
|
||||||
typedef T type;
|
typedef T type;
|
||||||
typedef fc::false_type is_defined;
|
typedef std::false_type is_defined;
|
||||||
typedef fc::false_type is_enum;
|
/// A typelist with a @ref field_reflection for each native member (non-inherited) of the struct
|
||||||
|
using native_members = typelist::list<>;
|
||||||
|
/// A typelist with a @ref field_reflection for each inherited member of the struct
|
||||||
|
using inherited_members = typelist::list<>;
|
||||||
|
/// A typelist with a @ref field_reflection for each member of the struct, starting with inherited members
|
||||||
|
using members = typelist::list<>;
|
||||||
|
/// A typelist of base classes for this type
|
||||||
|
using base_classes = typelist::list<>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @tparam Visitor a function object of the form:
|
* @tparam Visitor a function object of the form:
|
||||||
|
|
@ -92,31 +204,11 @@ void throw_bad_enum_cast( const char* k, const char* e );
|
||||||
case I: FC_REFLECT_VISIT_MEMBER( r, visitor, elem ) break;
|
case I: FC_REFLECT_VISIT_MEMBER( r, visitor, elem ) break;
|
||||||
|
|
||||||
|
|
||||||
#define FC_REFLECT_BASE_MEMBER_COUNT( r, OP, elem ) \
|
|
||||||
OP fc::reflector<elem>::total_member_count
|
|
||||||
|
|
||||||
#define FC_REFLECT_MEMBER_COUNT( r, OP, elem ) \
|
|
||||||
OP 1
|
|
||||||
|
|
||||||
#define FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
|
#define FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
|
||||||
template<typename Visitor>\
|
template<typename Visitor>\
|
||||||
static inline void visit( const Visitor& v ) { \
|
static inline void visit( const Visitor& v ) { \
|
||||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_BASE, v, INHERITS ) \
|
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_BASE, v, INHERITS ) \
|
||||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \
|
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \
|
||||||
}\
|
|
||||||
template<typename Visitor, typename IndexType>\
|
|
||||||
static inline void visit_local_member( const Visitor& v, IndexType index ) { \
|
|
||||||
switch( index ) {\
|
|
||||||
BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_VISIT_MEMBER_I, v, MEMBERS ) \
|
|
||||||
default: break;\
|
|
||||||
}\
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FC_REFLECT_DERIVED_IMPL_EXT( TYPE, INHERITS, MEMBERS ) \
|
|
||||||
template<typename Visitor>\
|
|
||||||
void fc::reflector<TYPE>::visit( const Visitor& v ) { \
|
|
||||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_BASE, v, INHERITS ) \
|
|
||||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DOXYGEN
|
#endif // DOXYGEN
|
||||||
|
|
@ -137,8 +229,7 @@ void fc::reflector<TYPE>::visit( const Visitor& v ) { \
|
||||||
#define FC_REFLECT_ENUM( ENUM, FIELDS ) \
|
#define FC_REFLECT_ENUM( ENUM, FIELDS ) \
|
||||||
namespace fc { \
|
namespace fc { \
|
||||||
template<> struct reflector<ENUM> { \
|
template<> struct reflector<ENUM> { \
|
||||||
typedef fc::true_type is_defined; \
|
typedef std::true_type is_defined; \
|
||||||
typedef fc::true_type is_enum; \
|
|
||||||
static const char* to_string(ENUM elem) { \
|
static const char* to_string(ENUM elem) { \
|
||||||
switch( elem ) { \
|
switch( elem ) { \
|
||||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_TO_STRING, ENUM, FIELDS ) \
|
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_TO_STRING, ENUM, FIELDS ) \
|
||||||
|
|
@ -177,7 +268,7 @@ template<> struct reflector<ENUM> { \
|
||||||
{ \
|
{ \
|
||||||
i = boost::lexical_cast<int64_t>(s); \
|
i = boost::lexical_cast<int64_t>(s); \
|
||||||
} \
|
} \
|
||||||
catch( const boost::bad_lexical_cast& e ) \
|
catch( const boost::bad_lexical_cast& ) \
|
||||||
{ \
|
{ \
|
||||||
fc::throw_bad_enum_cast( s, BOOST_PP_STRINGIZE(ENUM) ); \
|
fc::throw_bad_enum_cast( s, BOOST_PP_STRINGIZE(ENUM) ); \
|
||||||
} \
|
} \
|
||||||
|
|
@ -215,29 +306,74 @@ namespace fc { \
|
||||||
template<> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
|
template<> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
|
||||||
template<> struct reflector<TYPE> {\
|
template<> struct reflector<TYPE> {\
|
||||||
typedef TYPE type; \
|
typedef TYPE type; \
|
||||||
typedef fc::true_type is_defined; \
|
typedef std::true_type is_defined; \
|
||||||
typedef fc::false_type is_enum; \
|
using native_members = \
|
||||||
|
typename typelist::builder<>::type \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \
|
||||||
|
using inherited_members = \
|
||||||
|
typename typelist::builder<>::type \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \
|
||||||
|
using members = typename typelist::concat<inherited_members, native_members>::type; \
|
||||||
|
using base_classes = typename typelist::builder<>::type \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \
|
||||||
enum member_count_enum { \
|
enum member_count_enum { \
|
||||||
local_member_count = 0 BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_MEMBER_COUNT, +, MEMBERS ),\
|
local_member_count = typelist::length<native_members>(), \
|
||||||
total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\
|
total_member_count = typelist::length<members>() \
|
||||||
}; \
|
}; \
|
||||||
FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
|
FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
|
||||||
}; }
|
}; \
|
||||||
|
namespace member_names { \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_MEMBER_NAME, TYPE, MEMBERS ) \
|
||||||
|
} }
|
||||||
|
|
||||||
#define FC_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, INHERITS, MEMBERS ) \
|
#define FC_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, INHERITS, MEMBERS ) \
|
||||||
namespace fc { \
|
namespace fc { \
|
||||||
template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
|
template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct get_typename<TYPE> { \
|
||||||
|
static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } \
|
||||||
|
}; \
|
||||||
template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct reflector<TYPE> {\
|
template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct reflector<TYPE> {\
|
||||||
typedef TYPE type; \
|
typedef TYPE type; \
|
||||||
typedef fc::true_type is_defined; \
|
typedef std::true_type is_defined; \
|
||||||
typedef fc::false_type is_enum; \
|
using native_members = \
|
||||||
|
typename typelist::builder<>::type \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \
|
||||||
|
using inherited_members = \
|
||||||
|
typename typelist::builder<>::type \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \
|
||||||
|
using members = typename typelist::concat<inherited_members, native_members>::type; \
|
||||||
|
using base_classes = typename typelist::builder<>::type \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \
|
||||||
enum member_count_enum { \
|
enum member_count_enum { \
|
||||||
local_member_count = 0 BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_MEMBER_COUNT, +, MEMBERS ),\
|
local_member_count = typelist::length<native_members>(), \
|
||||||
total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\
|
total_member_count = typelist::length<members>() \
|
||||||
}; \
|
}; \
|
||||||
FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
|
FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
|
||||||
}; }
|
}; \
|
||||||
|
namespace member_names { \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_TEMPLATE_MEMBER_NAME, (TEMPLATE_ARGS)(TYPE), MEMBERS ) \
|
||||||
|
} }
|
||||||
|
|
||||||
//BOOST_PP_SEQ_SIZE(MEMBERS),
|
#define FC_REFLECT_DERIVED_NO_TYPENAME( TYPE, INHERITS, MEMBERS ) \
|
||||||
|
namespace fc { \
|
||||||
|
template<> struct reflector<TYPE> {\
|
||||||
|
typedef TYPE type; \
|
||||||
|
typedef std::true_type is_defined; \
|
||||||
|
using native_members = \
|
||||||
|
typename typelist::builder<>::type \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \
|
||||||
|
using inherited_members = \
|
||||||
|
typename typelist::builder<>::type \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \
|
||||||
|
using members = typename typelist::concat<inherited_members, native_members>::type; \
|
||||||
|
using base_classes = typename typelist::builder<>::type \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \
|
||||||
|
enum member_count_enum { \
|
||||||
|
local_member_count = typelist::length<native_members>(), \
|
||||||
|
total_member_count = typelist::length<members>() \
|
||||||
|
}; \
|
||||||
|
FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
|
||||||
|
}; \
|
||||||
|
} // fc
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @def FC_REFLECT(TYPE,MEMBERS)
|
* @def FC_REFLECT(TYPE,MEMBERS)
|
||||||
|
|
@ -248,7 +384,8 @@ template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct reflector<TYPE> {\
|
||||||
* @see FC_REFLECT_DERIVED
|
* @see FC_REFLECT_DERIVED
|
||||||
*/
|
*/
|
||||||
#define FC_REFLECT( TYPE, MEMBERS ) \
|
#define FC_REFLECT( TYPE, MEMBERS ) \
|
||||||
FC_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
|
FC_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
|
||||||
|
|
||||||
|
|
||||||
#define FC_REFLECT_TEMPLATE( TEMPLATE_ARGS, TYPE, MEMBERS ) \
|
#define FC_REFLECT_TEMPLATE( TEMPLATE_ARGS, TYPE, MEMBERS ) \
|
||||||
FC_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
|
FC_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
|
||||||
|
|
@ -261,25 +398,3 @@ namespace fc { \
|
||||||
template<> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
|
template<> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FC_REFLECT_FWD( TYPE ) \
|
|
||||||
namespace fc { \
|
|
||||||
template<> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
|
|
||||||
template<> struct reflector<TYPE> {\
|
|
||||||
typedef TYPE type; \
|
|
||||||
typedef fc::true_type is_defined; \
|
|
||||||
enum member_count_enum { \
|
|
||||||
local_member_count = BOOST_PP_SEQ_SIZE(MEMBERS), \
|
|
||||||
total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\
|
|
||||||
}; \
|
|
||||||
template<typename Visitor> static void visit( const Visitor& v ); \
|
|
||||||
}; }
|
|
||||||
|
|
||||||
|
|
||||||
#define FC_REFLECT_DERIVED_IMPL( TYPE, MEMBERS ) \
|
|
||||||
FC_REFLECT_IMPL_DERIVED_EXT( TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
|
|
||||||
|
|
||||||
#define FC_REFLECT_IMPL( TYPE, MEMBERS ) \
|
|
||||||
FC_REFLECT_DERIVED_IMPL_EXT( TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
262
include/fc/reflect/typelist.hpp
Normal file
262
include/fc/reflect/typelist.hpp
Normal file
|
|
@ -0,0 +1,262 @@
|
||||||
|
#pragma once
|
||||||
|
/**
|
||||||
|
* @file fc/reflect/typelist.hpp
|
||||||
|
*
|
||||||
|
* @brief Defines a template for manipulating and storing compile-time lists of types
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace fc {
|
||||||
|
|
||||||
|
/// This namespace contains the list type, and all of the operations and queries which can be performed upon it
|
||||||
|
namespace typelist {
|
||||||
|
|
||||||
|
// Forward declare the list so impl can see it
|
||||||
|
template<typename...> struct list;
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
using typelist::list;
|
||||||
|
|
||||||
|
template<typename, template<typename...> class> struct apply;
|
||||||
|
template<typename... Ts, template<typename...> class Delegate>
|
||||||
|
struct apply<list<Ts...>, Delegate> { using type = Delegate<Ts...>; };
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
struct length;
|
||||||
|
template<> struct length<> { constexpr static std::size_t value = 0; };
|
||||||
|
template<typename T, typename... Ts>
|
||||||
|
struct length<T, Ts...> { constexpr static std::size_t value = length<Ts...>::value+1; };
|
||||||
|
|
||||||
|
template<typename...> struct concat;
|
||||||
|
template<typename... OldTypes, typename... NewTypes>
|
||||||
|
struct concat<list<OldTypes...>, list<NewTypes...>> {
|
||||||
|
using type = list<OldTypes..., NewTypes...>;
|
||||||
|
};
|
||||||
|
template<typename... OldTypes, typename... NewTypes, typename NextList, typename... Lists>
|
||||||
|
struct concat<list<OldTypes...>, list<NewTypes...>, NextList, Lists...> {
|
||||||
|
using type = typename concat<list<OldTypes..., NewTypes...>, NextList, Lists...>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<std::size_t count> struct make_sequence;
|
||||||
|
template<> struct make_sequence<0> { using type = list<>; };
|
||||||
|
template<> struct make_sequence<1> { using type = list<std::integral_constant<std::size_t, 0>>; };
|
||||||
|
template<std::size_t count>
|
||||||
|
struct make_sequence {
|
||||||
|
using type = typename concat<typename make_sequence<count-1>::type,
|
||||||
|
list<std::integral_constant<std::size_t, count-1>>>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename, typename> struct transform;
|
||||||
|
template<typename... List, typename Transformer>
|
||||||
|
struct transform<list<List...>, Transformer> {
|
||||||
|
using type = list<typename Transformer::template transform<List>::type...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Search, typename List> struct index_of;
|
||||||
|
template<typename Search> struct index_of<Search, list<>> { constexpr static int value = -1; };
|
||||||
|
template<typename Search, typename T, typename... Ts>
|
||||||
|
struct index_of<Search, list<T, Ts...>> {
|
||||||
|
constexpr static int deeper = index_of<Search, list<Ts...>>::value;
|
||||||
|
constexpr static int value = std::is_same<Search, T>::value? 0 : (deeper == -1? -1 : deeper + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename...> struct concat_unique;
|
||||||
|
template<typename... Uniques>
|
||||||
|
struct concat_unique<list<Uniques...>, list<>> {
|
||||||
|
using type = list<Uniques...>;
|
||||||
|
};
|
||||||
|
template<typename... Uniques, typename T>
|
||||||
|
struct concat_unique<list<Uniques...>, list<T>> {
|
||||||
|
using type = std::conditional_t<index_of<T, list<Uniques...>>::value >= 0,
|
||||||
|
list<Uniques...>, list<Uniques..., T>>;
|
||||||
|
};
|
||||||
|
template<typename... Uniques, typename T1, typename T2, typename... Types>
|
||||||
|
struct concat_unique<list<Uniques...>, list<T1, T2, Types...>> {
|
||||||
|
using type = typename concat_unique<
|
||||||
|
typename concat_unique<list<Uniques...>, list<T1>>::type, list<T2, Types...>>::type;
|
||||||
|
};
|
||||||
|
template<typename... Uniques, typename... Lists>
|
||||||
|
struct concat_unique<list<Uniques...>, list<>, Lists...> {
|
||||||
|
using type = typename concat_unique<list<Uniques...>, Lists...>::type;
|
||||||
|
};
|
||||||
|
template<typename Uniques, typename L1a, typename... L1s, typename L2, typename... Lists>
|
||||||
|
struct concat_unique<Uniques, list<L1a, L1s...>, L2, Lists...> {
|
||||||
|
using type = typename concat_unique<typename concat_unique<Uniques, list<L1a, L1s...>>::type, L2, Lists...>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename, std::size_t> struct at;
|
||||||
|
template<typename T, typename... Types>
|
||||||
|
struct at<list<T, Types...>, 0> { using type = T; };
|
||||||
|
template<typename T, typename... Types, std::size_t index>
|
||||||
|
struct at<list<T, Types...>, index> : at<list<Types...>, index-1> {};
|
||||||
|
|
||||||
|
template<typename, typename, std::size_t> struct remove_at;
|
||||||
|
template<typename... Left, typename T, typename... Right>
|
||||||
|
struct remove_at<list<Left...>, list<T, Right...>, 0> { using type = list<Left..., Right...>; };
|
||||||
|
template<typename... Left, typename T, typename... Right, std::size_t index>
|
||||||
|
struct remove_at<list<Left...>, list<T, Right...>, index> {
|
||||||
|
using type = typename remove_at<list<Left..., T>, list<Right...>, index-1>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<template<typename> class Filter, typename Filtered, typename List> struct filter;
|
||||||
|
template<template<typename> class Filter, typename... Filtered>
|
||||||
|
struct filter<Filter, list<Filtered...>, list<>> { using type = list<Filtered...>; };
|
||||||
|
template<template<typename> class Filter, typename... Filtered, typename T1, typename... Types>
|
||||||
|
struct filter<Filter, list<Filtered...>, list<T1, Types...>> {
|
||||||
|
using type = typename std::conditional_t<Filter<T1>::value,
|
||||||
|
filter<Filter, list<Filtered..., T1>, list<Types...>>,
|
||||||
|
filter<Filter, list<Filtered...>, list<Types...>>>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename, typename, std::size_t, std::size_t, typename = void> struct slice;
|
||||||
|
template<typename... Results, typename... Types, std::size_t index>
|
||||||
|
struct slice<list<Results...>, list<Types...>, index, index, void> { using type = list<Results...>; };
|
||||||
|
template<typename... Results, typename T, typename... Types, std::size_t end>
|
||||||
|
struct slice<list<Results...>, list<T, Types...>, 0, end, std::enable_if_t<end != 0>>
|
||||||
|
: slice<list<Results..., T>, list<Types...>, 0, end-1> {};
|
||||||
|
template<typename T, typename... Types, std::size_t start, std::size_t end>
|
||||||
|
struct slice<list<>, list<T, Types...>, start, end, std::enable_if_t<start != 0>>
|
||||||
|
: slice<list<>, list<Types...>, start-1, end-1> {};
|
||||||
|
|
||||||
|
template<typename, typename> struct zip;
|
||||||
|
template<>
|
||||||
|
struct zip<list<>, list<>> { using type = list<>; };
|
||||||
|
template<typename A, typename... As, typename B, typename... Bs>
|
||||||
|
struct zip<list<A, As...>, list<B, Bs...>> {
|
||||||
|
using type = typename concat<list<list<A, B>>, typename zip<list<As...>, list<Bs...>>::type>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Callable, typename Ret, typename T>
|
||||||
|
Ret dispatch_helper(Callable& c) { return c(T()); }
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
|
/// The actual list type
|
||||||
|
template<typename... Types>
|
||||||
|
struct list { using type = list; };
|
||||||
|
|
||||||
|
/// Apply a list of types as arguments to another template
|
||||||
|
template<typename List, template<typename...> class Delegate>
|
||||||
|
using apply = typename impl::apply<List, Delegate>::type;
|
||||||
|
|
||||||
|
/// Get the number of types in a list
|
||||||
|
template<typename List>
|
||||||
|
constexpr static std::size_t length() { return apply<List, impl::length>::value; }
|
||||||
|
|
||||||
|
/// Concatenate two or more typelists together
|
||||||
|
template<typename... Lists>
|
||||||
|
using concat = typename impl::concat<Lists...>::type;
|
||||||
|
|
||||||
|
/// Create a list of sequential integers ranging from [0, count)
|
||||||
|
template<std::size_t count>
|
||||||
|
using make_sequence = typename impl::make_sequence<count>::type;
|
||||||
|
|
||||||
|
/// Template to build typelists using the following syntax:
|
||||||
|
/// builder<>::type::add<T1>::add<T2>::add<T3>[...]::finalize
|
||||||
|
/// Or:
|
||||||
|
/// builder<>::type::add_list<list<T1, T2>>::add_list<T3, T4>>[...]::finalize
|
||||||
|
template<typename List = list<>>
|
||||||
|
struct builder {
|
||||||
|
template<typename NewType> using add = typename builder<typename impl::concat<List, list<NewType>>::type>::type;
|
||||||
|
template<typename NewList> using add_list = typename builder<typename impl::concat<List, NewList>::type>::type;
|
||||||
|
using type = builder;
|
||||||
|
using finalize = List;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Transform elements of a typelist
|
||||||
|
template<typename List, typename Transformer>
|
||||||
|
using transform = typename impl::transform<List, Transformer>::type;
|
||||||
|
|
||||||
|
/// Get the index of the given type within a list, or -1 if type is not found
|
||||||
|
template<typename List, typename T>
|
||||||
|
constexpr static int index_of() { return impl::index_of<T, List>::value; }
|
||||||
|
|
||||||
|
/// Check if a given type is in a list
|
||||||
|
template<typename List, typename T>
|
||||||
|
constexpr static bool contains() { return impl::index_of<T, List>::value != -1; }
|
||||||
|
|
||||||
|
/// Remove duplicate items from one or more typelists and concatenate them all together
|
||||||
|
template<typename... TypeLists>
|
||||||
|
using concat_unique = typename impl::concat_unique<list<>, TypeLists...>::type;
|
||||||
|
|
||||||
|
/// Get the type at the specified list index
|
||||||
|
template<typename List, std::size_t index>
|
||||||
|
using at = typename impl::at<List, index>::type;
|
||||||
|
|
||||||
|
/// Get the type at the beginning of the list
|
||||||
|
template<typename List>
|
||||||
|
using first = at<List, 0>;
|
||||||
|
/// Get the type at the end of the list
|
||||||
|
template<typename List>
|
||||||
|
using last = at<List, length<List>()-1>;
|
||||||
|
|
||||||
|
/// Get the list with the element at the given index removed
|
||||||
|
template<typename List, std::size_t index>
|
||||||
|
using remove_at = typename impl::remove_at<list<>, List, index>::type;
|
||||||
|
|
||||||
|
/// Get the list with the given type removed
|
||||||
|
template<typename List, typename Remove>
|
||||||
|
using remove_element = remove_at<List, index_of<List, Remove>()>;
|
||||||
|
|
||||||
|
/// Get a list with all elements that do not pass a filter removed
|
||||||
|
template<typename List, template<typename> class Filter>
|
||||||
|
using filter = typename impl::filter<Filter, list<>, List>::type;
|
||||||
|
|
||||||
|
/// Template to invert a filter, i.e. filter<mylist, filter_inverter<myfilter>::type>
|
||||||
|
template<template<typename> class Filter>
|
||||||
|
struct invert_filter {
|
||||||
|
template<typename T>
|
||||||
|
struct type { constexpr static bool value = !Filter<T>::value; };
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Take the sublist at indexes [start, end)
|
||||||
|
template<typename List, std::size_t start, std::size_t end = length<List>()>
|
||||||
|
using slice = typename impl::slice<list<>, List, start, end>::type;
|
||||||
|
|
||||||
|
/// Zip two equal-length typelists together, i.e. zip<list<X, Y>, list<A, B>> == list<list<X, A>, list<Y, B>>
|
||||||
|
template<typename ListA, typename ListB>
|
||||||
|
using zip = typename impl::zip<ListA, ListB>::type;
|
||||||
|
|
||||||
|
/// Add indexes to types in the list, i.e. index<list<A, B, C>> == list<list<0, A>, list<1, B>, list<2, C>> where
|
||||||
|
/// 0, 1, and 2 are std::integral_constants of type std::size_t
|
||||||
|
template<typename List>
|
||||||
|
using index = typename impl::zip<typename impl::make_sequence<length<List>()>::type, List>::type;
|
||||||
|
|
||||||
|
/// This namespace contains some utilities that provide runtime operations on typelists
|
||||||
|
namespace runtime {
|
||||||
|
/// Type wrapper object allowing arbitrary types to be passed to functions as information rather than data
|
||||||
|
template<typename T> struct wrapper { using type = T; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Index into the typelist for a type T, and invoke the callable with an argument wrapper<T>()
|
||||||
|
* @param index Index of the type in the typelist to invoke the callable with
|
||||||
|
* @param c The callable to invoke
|
||||||
|
* @return The value returned by the callable
|
||||||
|
* @note The callable return type must be the same for all list elements
|
||||||
|
*
|
||||||
|
* If index is out of bounds, throws std::out_of_range exception
|
||||||
|
*/
|
||||||
|
template<typename... Types, typename Callable, typename = std::enable_if_t<impl::length<Types...>::value != 0>,
|
||||||
|
typename Return = decltype(std::declval<Callable>()(wrapper<at<list<Types...>, 0>>()))>
|
||||||
|
Return dispatch(list<Types...>, std::size_t index, Callable c) {
|
||||||
|
static std::function<Return(Callable&)> call_table[] =
|
||||||
|
{ impl::dispatch_helper<Callable, Return, wrapper<Types>>... };
|
||||||
|
if (index < impl::length<Types...>::value) return call_table[index](c);
|
||||||
|
throw std::out_of_range("Invalid index to fc::typelist::runtime::dispatch()");
|
||||||
|
}
|
||||||
|
template<typename List, typename Callable>
|
||||||
|
auto dispatch(List l, int64_t index, Callable c) {
|
||||||
|
if (index < 0) throw std::out_of_range("Negative index to fc::typelist::runtime::dispatch()");
|
||||||
|
return dispatch(l, std::size_t(index), std::move(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Invoke the provided callable with an argument wrapper<Type>() for each type in the list
|
||||||
|
template<typename... Types, typename Callable>
|
||||||
|
void for_each(list<Types...>, Callable c) {
|
||||||
|
bool trues[] = { [](Callable& c, auto t) { c(t); return true; }(c, wrapper<Types>())... };
|
||||||
|
(void)(trues);
|
||||||
|
}
|
||||||
|
|
||||||
|
} } } // namespace fc::typelist::runtime
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
@ -7,15 +8,19 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <fc/optional.hpp>
|
#include <fc/optional.hpp>
|
||||||
|
#include <fc/string.hpp>
|
||||||
#include <fc/container/flat_fwd.hpp>
|
#include <fc/container/flat_fwd.hpp>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
template<typename...> class static_variant;
|
||||||
class value;
|
class value;
|
||||||
class exception;
|
class exception;
|
||||||
namespace ip { class address; }
|
namespace ip { class address; }
|
||||||
|
|
||||||
template<typename... T> struct get_typename;
|
template<typename... T> struct get_typename;
|
||||||
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
||||||
|
template<> struct get_typename<size_t> { static const char* name() { return "size_t"; } };
|
||||||
|
#endif
|
||||||
template<> struct get_typename<int32_t> { static const char* name() { return "int32_t"; } };
|
template<> struct get_typename<int32_t> { static const char* name() { return "int32_t"; } };
|
||||||
template<> struct get_typename<int64_t> { static const char* name() { return "int64_t"; } };
|
template<> struct get_typename<int64_t> { static const char* name() { return "int64_t"; } };
|
||||||
template<> struct get_typename<int16_t> { static const char* name() { return "int16_t"; } };
|
template<> struct get_typename<int16_t> { static const char* name() { return "int16_t"; } };
|
||||||
|
|
@ -40,10 +45,19 @@ namespace fc {
|
||||||
return n.c_str();
|
return n.c_str();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<typename T> struct get_typename<flat_set<T>>
|
template<typename T> struct get_typename<flat_set<T>>
|
||||||
|
{
|
||||||
|
static const char* name() {
|
||||||
|
static std::string n = std::string("flat_set<") + get_typename<T>::name() + ">";
|
||||||
|
return n.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<typename... Ts>
|
||||||
|
struct get_typename<flat_set<static_variant<Ts...>, typename static_variant<Ts...>::type_lt>>
|
||||||
{
|
{
|
||||||
static const char* name() {
|
static const char* name() {
|
||||||
static std::string n = std::string("flat_set<") + get_typename<T>::name() + ">";
|
using TN = get_typename<static_variant<Ts...>>;
|
||||||
|
static std::string n = std::string("flat_set<") + TN::name() + ", " + TN::name() + "::type_lt>";
|
||||||
return n.c_str();
|
return n.c_str();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -92,6 +106,31 @@ namespace fc {
|
||||||
return n.c_str();
|
return n.c_str();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
template<typename T,size_t N> struct get_typename< std::array<T,N> >
|
||||||
|
{
|
||||||
|
static const char* name()
|
||||||
|
{
|
||||||
|
static std::string _name = std::string("std::array<") + std::string(fc::get_typename<T>::name())
|
||||||
|
+ "," + fc::to_string(N) + ">";
|
||||||
|
return _name.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<typename T> struct get_typename< const T* >
|
||||||
|
{
|
||||||
|
static const char* name()
|
||||||
|
{
|
||||||
|
static std::string n = std::string("const ") + get_typename<T>::name() + "*";
|
||||||
|
return n.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<typename T> struct get_typename< T* >
|
||||||
|
{
|
||||||
|
static const char* name()
|
||||||
|
{
|
||||||
|
static std::string n = std::string(get_typename<T>::name()) + "*";
|
||||||
|
return n.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct unsigned_int;
|
struct unsigned_int;
|
||||||
class variant_object;
|
class variant_object;
|
||||||
|
|
|
||||||
|
|
@ -63,17 +63,17 @@ namespace fc
|
||||||
const uint32_t _max_depth;
|
const uint32_t _max_depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename IsEnum=fc::false_type>
|
template<typename T, typename Dummy = void>
|
||||||
struct if_enum
|
struct if_enum;
|
||||||
|
template<typename T>
|
||||||
|
struct if_enum<T, std::enable_if_t<!std::is_enum<T>::value>>
|
||||||
{
|
{
|
||||||
template<typename T>
|
|
||||||
static inline void to_variant( const T& v, fc::variant& vo, uint32_t max_depth )
|
static inline void to_variant( const T& v, fc::variant& vo, uint32_t max_depth )
|
||||||
{
|
{
|
||||||
mutable_variant_object mvo;
|
mutable_variant_object mvo;
|
||||||
fc::reflector<T>::visit( to_variant_visitor<T>( mvo, v, max_depth ) );
|
fc::reflector<T>::visit( to_variant_visitor<T>( mvo, v, max_depth ) );
|
||||||
vo = std::move(mvo);
|
vo = std::move(mvo);
|
||||||
}
|
}
|
||||||
template<typename T>
|
|
||||||
static inline void from_variant( const fc::variant& v, T& o, uint32_t max_depth )
|
static inline void from_variant( const fc::variant& v, T& o, uint32_t max_depth )
|
||||||
{
|
{
|
||||||
const variant_object& vo = v.get_object();
|
const variant_object& vo = v.get_object();
|
||||||
|
|
@ -81,15 +81,13 @@ namespace fc
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<typename T>
|
||||||
struct if_enum<fc::true_type>
|
struct if_enum<T, std::enable_if_t<std::is_enum<T>::value>>
|
||||||
{
|
{
|
||||||
template<typename T>
|
|
||||||
static inline void to_variant( const T& o, fc::variant& v, uint32_t max_depth = 1 )
|
static inline void to_variant( const T& o, fc::variant& v, uint32_t max_depth = 1 )
|
||||||
{
|
{
|
||||||
v = fc::reflector<T>::to_fc_string(o);
|
v = fc::reflector<T>::to_fc_string(o);
|
||||||
}
|
}
|
||||||
template<typename T>
|
|
||||||
static inline void from_variant( const fc::variant& v, T& o, uint32_t max_depth = 1 )
|
static inline void from_variant( const fc::variant& v, T& o, uint32_t max_depth = 1 )
|
||||||
{
|
{
|
||||||
if( v.is_string() )
|
if( v.is_string() )
|
||||||
|
|
@ -103,12 +101,12 @@ namespace fc
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void to_variant( const T& o, variant& v, uint32_t max_depth )
|
void to_variant( const T& o, variant& v, uint32_t max_depth )
|
||||||
{
|
{
|
||||||
if_enum<typename fc::reflector<T>::is_enum>::to_variant( o, v, max_depth );
|
if_enum<T>::to_variant( o, v, max_depth );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void from_variant( const variant& v, T& o, uint32_t max_depth )
|
void from_variant( const variant& v, T& o, uint32_t max_depth )
|
||||||
{
|
{
|
||||||
if_enum<typename fc::reflector<T>::is_enum>::from_variant( v, o, max_depth );
|
if_enum<T>::from_variant( v, o, max_depth );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,13 +44,18 @@ namespace fc {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename Arg0, typename ... Args>
|
template<typename R, typename Arg0, typename ... Args>
|
||||||
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth )
|
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0,
|
||||||
|
variants::const_iterator e, uint32_t max_depth )
|
||||||
{
|
{
|
||||||
bool optional_args = all_optionals<std::decay_t<Arg0>, std::decay_t<Args>...>::value;
|
bool optional_args = all_optionals<std::decay_t<Arg0>, std::decay_t<Args>...>::value;
|
||||||
FC_ASSERT( a0 != e || optional_args );
|
FC_ASSERT( a0 != e || optional_args );
|
||||||
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
|
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
|
||||||
auto arg = (a0 == e)? std::decay_t<Arg0>() : a0->as<std::decay_t<Arg0>>(max_depth - 1);
|
if (a0==e)
|
||||||
return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, arg ), a0+1, e, max_depth - 1 );
|
return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, std::decay_t<Arg0>() ), a0,
|
||||||
|
e, max_depth - 1 );
|
||||||
|
auto arg = a0->as<std::decay_t<Arg0>>(max_depth - 1);
|
||||||
|
return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, std::move(arg) ), a0+1, e,
|
||||||
|
max_depth - 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename ... Args>
|
template<typename R, typename ... Args>
|
||||||
|
|
@ -180,13 +185,18 @@ namespace fc {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename Arg0, typename ... Args>
|
template<typename R, typename Arg0, typename ... Args>
|
||||||
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth )
|
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0,
|
||||||
|
variants::const_iterator e, uint32_t max_depth )
|
||||||
{
|
{
|
||||||
bool optional_args = detail::all_optionals<std::decay_t<Arg0>, std::decay_t<Args>...>::value;
|
bool optional_args = detail::all_optionals<std::decay_t<Arg0>, std::decay_t<Args>...>::value;
|
||||||
FC_ASSERT( a0 != e || optional_args, "too few arguments passed to method" );
|
FC_ASSERT( a0 != e || optional_args, "too few arguments passed to method" );
|
||||||
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
|
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
|
||||||
auto arg = (a0 == e)? std::decay_t<Arg0>() : a0->as<std::decay_t<Arg0>>(max_depth - 1);
|
if (a0==e)
|
||||||
return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, arg ), a0+1, e, max_depth - 1 );
|
return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, std::decay_t<Arg0>() ), a0,
|
||||||
|
e, max_depth - 1 );
|
||||||
|
auto arg = a0->as<std::decay_t<Arg0>>(max_depth - 1);
|
||||||
|
return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, std::move(arg) ), a0+1, e,
|
||||||
|
max_depth - 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
struct api_visitor
|
struct api_visitor
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <fc/io/json.hpp>
|
|
||||||
#include <fc/network/http/connection.hpp>
|
|
||||||
#include <fc/network/http/server.hpp>
|
|
||||||
#include <fc/reflect/variant.hpp>
|
|
||||||
#include <fc/rpc/api_connection.hpp>
|
|
||||||
#include <fc/rpc/state.hpp>
|
|
||||||
|
|
||||||
namespace fc { namespace rpc {
|
|
||||||
|
|
||||||
class http_api_connection : public api_connection
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
http_api_connection(uint32_t max_conversion_depth);
|
|
||||||
~http_api_connection();
|
|
||||||
|
|
||||||
virtual variant send_call(
|
|
||||||
api_id_type api_id,
|
|
||||||
string method_name,
|
|
||||||
variants args = variants() ) override;
|
|
||||||
virtual variant send_callback(
|
|
||||||
uint64_t callback_id,
|
|
||||||
variants args = variants() ) override;
|
|
||||||
virtual void send_notice(
|
|
||||||
uint64_t callback_id,
|
|
||||||
variants args = variants() ) override;
|
|
||||||
|
|
||||||
void on_request(
|
|
||||||
const fc::http::request& req,
|
|
||||||
const fc::http::server::response& resp );
|
|
||||||
|
|
||||||
fc::rpc::state _rpc_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
} } // namespace fc::rpc
|
|
||||||
|
|
@ -11,8 +11,7 @@ namespace fc {
|
||||||
* integer overflow and default initialization. It will
|
* integer overflow and default initialization. It will
|
||||||
* throw an exception on overflow conditions.
|
* throw an exception on overflow conditions.
|
||||||
*
|
*
|
||||||
* It can only be used on built-in types. In particular,
|
* It can only be used on built-in types.
|
||||||
* safe<uint128_t> is buggy and should not be used.
|
|
||||||
*
|
*
|
||||||
* Implemented using spec from:
|
* Implemented using spec from:
|
||||||
* https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
|
* https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
|
||||||
|
|
@ -27,11 +26,11 @@ namespace fc {
|
||||||
safe(){}
|
safe(){}
|
||||||
safe( const safe& o ):value(o.value){}
|
safe( const safe& o ):value(o.value){}
|
||||||
|
|
||||||
static safe min()
|
static constexpr safe min()
|
||||||
{
|
{
|
||||||
return std::numeric_limits<T>::min();
|
return std::numeric_limits<T>::min();
|
||||||
}
|
}
|
||||||
static safe max()
|
static constexpr safe max()
|
||||||
{
|
{
|
||||||
return std::numeric_limits<T>::max();
|
return std::numeric_limits<T>::max();
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +91,7 @@ namespace fc {
|
||||||
|
|
||||||
safe operator - ()const
|
safe operator - ()const
|
||||||
{
|
{
|
||||||
if( value == std::numeric_limits<T>::min() ) FC_CAPTURE_AND_THROW( overflow_exception, (*this) );
|
if( value == min() ) FC_CAPTURE_AND_THROW( overflow_exception, (*this) );
|
||||||
return safe( -value );
|
return safe( -value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace fc {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief used to create reference counted types.
|
|
||||||
*
|
|
||||||
* Must be a virtual base class that is initialized with the
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class retainable {
|
|
||||||
public:
|
|
||||||
retainable();
|
|
||||||
void retain();
|
|
||||||
void release();
|
|
||||||
int32_t retain_count()const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~retainable();
|
|
||||||
private:
|
|
||||||
volatile int32_t _ref_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class shared_ptr {
|
|
||||||
public:
|
|
||||||
template<typename Other>
|
|
||||||
shared_ptr( const shared_ptr<Other>& o )
|
|
||||||
:_ptr(o.get()) {
|
|
||||||
if(_ptr != nullptr ) _ptr->retain();
|
|
||||||
}
|
|
||||||
shared_ptr( const shared_ptr& o )
|
|
||||||
:_ptr(o.get()) {
|
|
||||||
if(_ptr != nullptr ) _ptr->retain();
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_ptr( T* t, bool inc = false )
|
|
||||||
:_ptr(t) { if( inc && t != nullptr) t->retain(); }
|
|
||||||
|
|
||||||
shared_ptr():_ptr(nullptr){}
|
|
||||||
|
|
||||||
|
|
||||||
shared_ptr( shared_ptr&& p )
|
|
||||||
:_ptr(p._ptr){ p._ptr = nullptr; }
|
|
||||||
|
|
||||||
~shared_ptr() { if( nullptr != _ptr ) { _ptr->release(); _ptr = nullptr; } }
|
|
||||||
|
|
||||||
shared_ptr& reset( T* v = nullptr, bool inc = false ) {
|
|
||||||
if( v == _ptr ) return *this;
|
|
||||||
if( inc && nullptr != v ) v->retain();
|
|
||||||
if( nullptr != _ptr ) _ptr->release();
|
|
||||||
_ptr = v;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_ptr& operator=(const shared_ptr& p ) {
|
|
||||||
if( _ptr == p._ptr ) return *this;
|
|
||||||
if( p._ptr != nullptr ) p._ptr->retain();
|
|
||||||
if( _ptr != nullptr ) _ptr->release();
|
|
||||||
_ptr = p._ptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
shared_ptr& operator=(shared_ptr&& p ) {
|
|
||||||
std::swap(_ptr,p._ptr);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
T& operator* ()const { return *_ptr; }
|
|
||||||
T* operator-> ()const { return _ptr; }
|
|
||||||
|
|
||||||
bool operator==( const shared_ptr& p )const { return get() == p.get(); }
|
|
||||||
bool operator<( const shared_ptr& p )const { return get() < p.get(); }
|
|
||||||
T * get() const { return _ptr; }
|
|
||||||
|
|
||||||
bool operator!()const { return _ptr == 0; }
|
|
||||||
operator bool()const { return _ptr != 0; }
|
|
||||||
private:
|
|
||||||
T* _ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename O>
|
|
||||||
fc::shared_ptr<T> dynamic_pointer_cast( const fc::shared_ptr<O>& t ) {
|
|
||||||
return fc::shared_ptr<T>( dynamic_cast<T*>(t.get()), true );
|
|
||||||
}
|
|
||||||
template<typename T, typename O>
|
|
||||||
fc::shared_ptr<T> static_pointer_cast( const fc::shared_ptr<O>& t ) {
|
|
||||||
return fc::shared_ptr<T>( static_cast<T*>(t.get()), true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -36,13 +36,13 @@ namespace fc {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T wait( boost::signals2::signal<void(T)>& sig, const microseconds& timeout_us=microseconds::maximum() ) {
|
inline T wait( boost::signals2::signal<void(T)>& sig, const microseconds& timeout_us=microseconds::maximum() ) {
|
||||||
typename promise<T>::ptr p(new promise<T>("fc::signal::wait"));
|
typename promise<T>::ptr p = promise<T>::create("fc::signal::wait");
|
||||||
boost::signals2::scoped_connection c( sig.connect( [=]( T t ) { p->set_value(t); } ));
|
boost::signals2::scoped_connection c( sig.connect( [=]( T t ) { p->set_value(t); } ));
|
||||||
return p->wait( timeout_us );
|
return p->wait( timeout_us );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void wait( boost::signals2::signal<void()>& sig, const microseconds& timeout_us=microseconds::maximum() ) {
|
inline void wait( boost::signals2::signal<void()>& sig, const microseconds& timeout_us=microseconds::maximum() ) {
|
||||||
promise<void>::ptr p(new promise<void>("fc::signal::wait"));
|
promise<void>::ptr p = promise<void>::create("fc::signal::wait");
|
||||||
boost::signals2::scoped_connection c( sig.connect( [=]() { p->set_value(); } ));
|
boost::signals2::scoped_connection c( sig.connect( [=]() { p->set_value(); } ));
|
||||||
p->wait( timeout_us );
|
p->wait( timeout_us );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,11 @@
|
||||||
**/
|
**/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
||||||
#include <fc/array.hpp>
|
|
||||||
#include <fc/exception/exception.hpp>
|
#include <fc/exception/exception.hpp>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
@ -23,179 +23,6 @@ namespace fc {
|
||||||
// Implementation details, the user should not import this:
|
// Implementation details, the user should not import this:
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
template<int N, typename... Ts>
|
|
||||||
struct storage_ops;
|
|
||||||
|
|
||||||
template<typename X, typename... Ts>
|
|
||||||
struct position;
|
|
||||||
|
|
||||||
template<typename... Ts>
|
|
||||||
struct type_info;
|
|
||||||
|
|
||||||
template<typename StaticVariant>
|
|
||||||
struct copy_construct
|
|
||||||
{
|
|
||||||
typedef void result_type;
|
|
||||||
StaticVariant& sv;
|
|
||||||
copy_construct( StaticVariant& s ):sv(s){}
|
|
||||||
template<typename T>
|
|
||||||
void operator()( const T& v )const
|
|
||||||
{
|
|
||||||
sv.init(v);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename StaticVariant>
|
|
||||||
struct move_construct
|
|
||||||
{
|
|
||||||
typedef void result_type;
|
|
||||||
StaticVariant& sv;
|
|
||||||
move_construct( StaticVariant& s ):sv(s){}
|
|
||||||
template<typename T>
|
|
||||||
void operator()( T& v )const
|
|
||||||
{
|
|
||||||
sv.init( std::move(v) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<int N, typename T, typename... Ts>
|
|
||||||
struct storage_ops<N, T&, Ts...> {
|
|
||||||
static void del(int n, void *data) {}
|
|
||||||
static void con(int n, void *data) {}
|
|
||||||
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, void *data, visitor& v) {}
|
|
||||||
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, void *data, const visitor& v) {}
|
|
||||||
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, const void *data, visitor& v) {}
|
|
||||||
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, const void *data, const visitor& v) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<int N, typename T, typename... Ts>
|
|
||||||
struct storage_ops<N, T, Ts...> {
|
|
||||||
static void del(int n, void *data) {
|
|
||||||
if(n == N) reinterpret_cast<T*>(data)->~T();
|
|
||||||
else storage_ops<N + 1, Ts...>::del(n, data);
|
|
||||||
}
|
|
||||||
static void con(int n, void *data) {
|
|
||||||
if(n == N) new(reinterpret_cast<T*>(data)) T();
|
|
||||||
else storage_ops<N + 1, Ts...>::con(n, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, void *data, visitor& v) {
|
|
||||||
if(n == N) return v(*reinterpret_cast<T*>(data));
|
|
||||||
else return storage_ops<N + 1, Ts...>::apply(n, data, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, void *data, const visitor& v) {
|
|
||||||
if(n == N) return v(*reinterpret_cast<T*>(data));
|
|
||||||
else return storage_ops<N + 1, Ts...>::apply(n, data, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, const void *data, visitor& v) {
|
|
||||||
if(n == N) return v(*reinterpret_cast<const T*>(data));
|
|
||||||
else return storage_ops<N + 1, Ts...>::apply(n, data, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, const void *data, const visitor& v) {
|
|
||||||
if(n == N) return v(*reinterpret_cast<const T*>(data));
|
|
||||||
else return storage_ops<N + 1, Ts...>::apply(n, data, v);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<int N>
|
|
||||||
struct storage_ops<N> {
|
|
||||||
static void del(int n, void *data) {
|
|
||||||
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid.");
|
|
||||||
}
|
|
||||||
static void con(int n, void *data) {
|
|
||||||
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." );
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, void *data, visitor& v) {
|
|
||||||
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." );
|
|
||||||
}
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, void *data, const visitor& v) {
|
|
||||||
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." );
|
|
||||||
}
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, const void *data, visitor& v) {
|
|
||||||
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." );
|
|
||||||
}
|
|
||||||
template<typename visitor>
|
|
||||||
static typename visitor::result_type apply(int n, const void *data, const visitor& v) {
|
|
||||||
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename X>
|
|
||||||
struct position<X> {
|
|
||||||
static const int pos = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename X, typename... Ts>
|
|
||||||
struct position<X, X, Ts...> {
|
|
||||||
static const int pos = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename X, typename T, typename... Ts>
|
|
||||||
struct position<X, T, Ts...> {
|
|
||||||
static const int pos = position<X, Ts...>::pos != -1 ? position<X, Ts...>::pos + 1 : -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename... Ts>
|
|
||||||
struct type_info<T&, Ts...> {
|
|
||||||
static const bool no_reference_types = false;
|
|
||||||
static const bool no_duplicates = position<T, Ts...>::pos == -1 && type_info<Ts...>::no_duplicates;
|
|
||||||
static const size_t size = type_info<Ts...>::size > sizeof(T&) ? type_info<Ts...>::size : sizeof(T&);
|
|
||||||
static const size_t count = 1 + type_info<Ts...>::count;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename... Ts>
|
|
||||||
struct type_info<T, Ts...> {
|
|
||||||
static const bool no_reference_types = type_info<Ts...>::no_reference_types;
|
|
||||||
static const bool no_duplicates = position<T, Ts...>::pos == -1 && type_info<Ts...>::no_duplicates;
|
|
||||||
static const size_t size = type_info<Ts...>::size > sizeof(T) ? type_info<Ts...>::size : sizeof(T&);
|
|
||||||
static const size_t count = 1 + type_info<Ts...>::count;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct type_info<> {
|
|
||||||
static const bool no_reference_types = true;
|
|
||||||
static const bool no_duplicates = true;
|
|
||||||
static const size_t count = 0;
|
|
||||||
static const size_t size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename TTag>
|
|
||||||
size_t size( TTag )
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TTag, typename A, typename...Ts>
|
|
||||||
size_t size( TTag tag )
|
|
||||||
{
|
|
||||||
if (tag <= 0)
|
|
||||||
{
|
|
||||||
return sizeof(A);
|
|
||||||
}
|
|
||||||
|
|
||||||
return size<TTag, Ts...>( --tag );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class dynamic_storage
|
class dynamic_storage
|
||||||
{
|
{
|
||||||
char* storage;
|
char* storage;
|
||||||
|
|
@ -211,71 +38,36 @@ public:
|
||||||
void release();
|
void release();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace impl
|
} // namespace impl
|
||||||
|
|
||||||
template<int L,typename Visitor,typename Data>
|
|
||||||
static const fc::array<typename Visitor::result_type(*)(Visitor&,Data),L>
|
|
||||||
init_wrappers( Visitor& v, Data d, typename Visitor::result_type(**funcs)(Visitor&,Data) = 0)
|
|
||||||
{
|
|
||||||
return fc::array<typename Visitor::result_type(*)(Visitor&,Data),L>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<int L,typename Visitor,typename Data,typename T, typename ... Types>
|
|
||||||
static const fc::array<typename Visitor::result_type(*)(Visitor&,Data),L>
|
|
||||||
init_wrappers( Visitor& v, Data d, typename Visitor::result_type(**funcs)(Visitor&,Data) = 0 )
|
|
||||||
{
|
|
||||||
fc::array<typename Visitor::result_type(*)(Visitor&,Data),L> result{};
|
|
||||||
if( !funcs ) funcs = result.begin();
|
|
||||||
*funcs++ = [] ( Visitor& v, Data d ) { return v( *reinterpret_cast<T*>( d ) ); };
|
|
||||||
init_wrappers<L,Visitor,Data,Types...>( v, d, funcs );
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<int L,typename Visitor,typename Data>
|
|
||||||
static const fc::array<typename Visitor::result_type(*)(Visitor&,Data),L>
|
|
||||||
init_const_wrappers( Visitor& v, Data d, typename Visitor::result_type(**funcs)(Visitor&,Data) = 0 )
|
|
||||||
{
|
|
||||||
return fc::array<typename Visitor::result_type(*)(Visitor&,Data),L>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<int L,typename Visitor,typename Data,typename T, typename ... Types>
|
|
||||||
static const fc::array<typename Visitor::result_type(*)(Visitor&,Data),L>
|
|
||||||
init_const_wrappers( Visitor& v, Data d, typename Visitor::result_type(**funcs)(Visitor&,Data) = 0 )
|
|
||||||
{
|
|
||||||
fc::array<typename Visitor::result_type(*)(Visitor&,Data),L> result{};
|
|
||||||
if( !funcs ) funcs = result.begin();
|
|
||||||
*funcs++ = [] ( Visitor& v, Data d ) { return v( *reinterpret_cast<const T*>( d ) ); };
|
|
||||||
init_const_wrappers<L,Visitor,Data,Types...>( v, d, funcs );
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Types>
|
template<typename... Types>
|
||||||
class static_variant {
|
class static_variant {
|
||||||
public:
|
public:
|
||||||
using tag_type = int64_t;
|
using tag_type = int64_t;
|
||||||
|
using list = typelist::list<Types...>;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static_assert(impl::type_info<Types...>::no_reference_types, "Reference types are not permitted in static_variant.");
|
static_assert(typelist::length<typelist::filter<list, std::is_reference>>() == 0,
|
||||||
static_assert(impl::type_info<Types...>::no_duplicates, "static_variant type arguments contain duplicate types.");
|
"Reference types are not permitted in static_variant.");
|
||||||
|
static_assert(typelist::length<typelist::concat_unique<list>>() == typelist::length<list>(),
|
||||||
|
"static_variant type arguments contain duplicate types.");
|
||||||
|
|
||||||
template<typename X>
|
template<typename X>
|
||||||
using type_in_typelist = typename std::enable_if<impl::position<X, Types...>::pos != -1, X>::type; // type is in typelist of static_variant.
|
using type_in_typelist = std::enable_if_t<typelist::index_of<list, X>() != -1>;
|
||||||
|
|
||||||
tag_type _tag;
|
tag_type _tag;
|
||||||
impl::dynamic_storage storage;
|
impl::dynamic_storage storage;
|
||||||
|
|
||||||
template<typename X, typename = type_in_typelist<X>>
|
template<typename X, typename = type_in_typelist<X>>
|
||||||
void init(const X& x) {
|
void init(const X& x) {
|
||||||
_tag = impl::position<X, Types...>::pos;
|
_tag = typelist::index_of<list, X>();
|
||||||
storage.alloc( sizeof(X) );
|
storage.alloc( sizeof(X) );
|
||||||
new(storage.data()) X(x);
|
new(storage.data()) X(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename X, typename = type_in_typelist<X>>
|
template<typename X, typename = type_in_typelist<X>>
|
||||||
void init(X&& x) {
|
void init(X&& x) {
|
||||||
_tag = impl::position<X, Types...>::pos;
|
_tag = typelist::index_of<list, X>();
|
||||||
storage.alloc( sizeof(X) );
|
storage.alloc( sizeof(X) );
|
||||||
new(storage.data()) X( std::move(x) );
|
new(storage.data()) X( std::move(x) );
|
||||||
}
|
}
|
||||||
|
|
@ -283,30 +75,79 @@ protected:
|
||||||
void init_from_tag(tag_type tag)
|
void init_from_tag(tag_type tag)
|
||||||
{
|
{
|
||||||
FC_ASSERT( tag >= 0 );
|
FC_ASSERT( tag >= 0 );
|
||||||
FC_ASSERT( tag < count() );
|
FC_ASSERT( static_cast<size_t>(tag) < count() );
|
||||||
_tag = tag;
|
_tag = tag;
|
||||||
storage.alloc( impl::size<tag_type, Types...>( tag ) );
|
typelist::runtime::dispatch(list(), tag, [this](auto t) {
|
||||||
impl::storage_ops<0, Types...>::con(_tag, storage.data());
|
using T = typename decltype(t)::type;
|
||||||
|
storage.alloc(sizeof(T));
|
||||||
|
new(reinterpret_cast<T*>(storage.data())) T();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void clean()
|
void clean()
|
||||||
{
|
{
|
||||||
impl::storage_ops<0, Types...>::del(_tag, storage.data() );
|
typelist::runtime::dispatch(list(), _tag, [data=storage.data()](auto t) {
|
||||||
|
using T = typename decltype(t)::type;
|
||||||
|
reinterpret_cast<T*>(data)->~T();
|
||||||
|
});
|
||||||
storage.release();
|
storage.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T, typename = void>
|
||||||
|
struct import_helper {
|
||||||
|
static static_variant construct(const T&) {
|
||||||
|
FC_THROW_EXCEPTION(assert_exception, "Cannot import unsupported type ${T} into static_variant",
|
||||||
|
("T", get_typename<T>::name()));
|
||||||
|
}
|
||||||
|
static static_variant construct(T&&) {
|
||||||
|
FC_THROW_EXCEPTION(assert_exception, "Cannot import unsupported type ${T} into static_variant",
|
||||||
|
("T", get_typename<T>::name()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<typename T>
|
||||||
|
struct import_helper<T, type_in_typelist<T>> {
|
||||||
|
static static_variant construct(const T& t) {
|
||||||
|
return static_variant(t);
|
||||||
|
}
|
||||||
|
static static_variant construct(T&& t) {
|
||||||
|
return static_variant(std::move(t));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename StaticVariant>
|
|
||||||
friend struct impl::copy_construct;
|
|
||||||
template<typename StaticVariant>
|
|
||||||
friend struct impl::move_construct;
|
|
||||||
public:
|
public:
|
||||||
template<typename X, typename = type_in_typelist<X>>
|
template<typename X, typename = type_in_typelist<X>>
|
||||||
struct tag
|
struct tag
|
||||||
{
|
{
|
||||||
static const int value = impl::position<X, Types...>::pos;
|
static constexpr tag_type value = typelist::index_of<list, X>();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct type_lt {
|
||||||
|
bool operator()(const static_variant& a, const static_variant& b) const { return a.which() < b.which(); }
|
||||||
|
};
|
||||||
|
struct type_eq {
|
||||||
|
bool operator()(const static_variant& a, const static_variant& b) const { return a.which() == b.which(); }
|
||||||
|
};
|
||||||
|
using flat_set_type = flat_set<static_variant, type_lt>;
|
||||||
|
|
||||||
|
/// Import the value from a foreign static_variant with types not in this one, and throw if the value is an
|
||||||
|
/// incompatible type
|
||||||
|
template<typename... Other>
|
||||||
|
static static_variant import_from(const static_variant<Other...>& other) {
|
||||||
|
return typelist::runtime::dispatch(typelist::list<Other...>(), other.which(), [&other](auto t) {
|
||||||
|
using other_type = typename decltype(t)::type;
|
||||||
|
return import_helper<other_type>::construct(other.template get<other_type>());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/// Import the value from a foreign static_variant with types not in this one, and throw if the value is an
|
||||||
|
/// incompatible type
|
||||||
|
template<typename... Other>
|
||||||
|
static static_variant import_from(static_variant<Other...>&& other) {
|
||||||
|
return typelist::runtime::dispatch(typelist::list<Other...>(), other.which(), [&other](auto t) {
|
||||||
|
using other_type = typename decltype(t)::type;
|
||||||
|
return import_helper<other_type>::construct(std::move(other.template get<other_type>()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static_variant()
|
static_variant()
|
||||||
{
|
{
|
||||||
init_from_tag(0);
|
init_from_tag(0);
|
||||||
|
|
@ -315,23 +156,41 @@ public:
|
||||||
template<typename... Other>
|
template<typename... Other>
|
||||||
static_variant( const static_variant<Other...>& cpy )
|
static_variant( const static_variant<Other...>& cpy )
|
||||||
{
|
{
|
||||||
cpy.visit( impl::copy_construct<static_variant>(*this) );
|
typelist::runtime::dispatch(typelist::list<Other...>(), cpy.which(), [this, &cpy](auto t) mutable {
|
||||||
|
this->init(cpy.template get<typename decltype(t)::type>());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static_variant( const static_variant& cpy )
|
static_variant( const static_variant& cpy )
|
||||||
{
|
{
|
||||||
cpy.visit( impl::copy_construct<static_variant>(*this) );
|
typelist::runtime::dispatch(list(), cpy.which(), [this, &cpy](auto t) mutable {
|
||||||
|
this->init(cpy.template get<typename decltype(t)::type>());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static_variant( static_variant&& mv )
|
static_variant( static_variant&& mv )
|
||||||
{
|
{
|
||||||
mv.visit( impl::move_construct<static_variant>(*this) );
|
typelist::runtime::dispatch(list(), mv.which(), [this, &mv](auto t) mutable {
|
||||||
|
this->init(std::move(mv.template get<typename decltype(t)::type>()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Other>
|
||||||
|
static_variant( static_variant<Other...>&& mv )
|
||||||
|
{
|
||||||
|
typelist::runtime::dispatch(typelist::list<Other...>(), mv.which(), [this, &mv](auto t) mutable {
|
||||||
|
this->init(std::move(mv.template get<typename decltype(t)::type>()));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename X, typename = type_in_typelist<X>>
|
template<typename X, typename = type_in_typelist<X>>
|
||||||
static_variant(const X& v) {
|
static_variant(const X& v) {
|
||||||
init(v);
|
init(v);
|
||||||
}
|
}
|
||||||
|
template<typename X, typename = type_in_typelist<X>>
|
||||||
|
static_variant(X&& v) {
|
||||||
|
init(std::move(v));
|
||||||
|
}
|
||||||
|
|
||||||
~static_variant() {
|
~static_variant() {
|
||||||
clean();
|
clean();
|
||||||
|
|
@ -347,28 +206,33 @@ public:
|
||||||
{
|
{
|
||||||
if( this == &v ) return *this;
|
if( this == &v ) return *this;
|
||||||
clean();
|
clean();
|
||||||
v.visit( impl::copy_construct<static_variant>(*this) );
|
typelist::runtime::dispatch(list(), v.which(), [this, &v](auto t)mutable {
|
||||||
|
this->init(v.template get<typename decltype(t)::type>());
|
||||||
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
static_variant& operator=( static_variant&& v )
|
static_variant& operator=( static_variant&& v )
|
||||||
{
|
{
|
||||||
if( this == &v ) return *this;
|
if( this == &v ) return *this;
|
||||||
clean();
|
clean();
|
||||||
v.visit( impl::move_construct<static_variant>(*this) );
|
typelist::runtime::dispatch(list(), v.which(), [this, &v](auto t)mutable {
|
||||||
|
this->init(std::move(v.template get<typename decltype(t)::type>()));
|
||||||
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
friend bool operator == ( const static_variant& a, const static_variant& b )
|
|
||||||
{
|
friend bool operator==( const static_variant& a, const static_variant& b ) {
|
||||||
return a.which() == b.which();
|
if (a.which() != b.which())
|
||||||
}
|
return false;
|
||||||
friend bool operator < ( const static_variant& a, const static_variant& b )
|
return typelist::runtime::dispatch(list(), a.which(), [&a, &b](auto t) {
|
||||||
{
|
using Value = typename decltype(t)::type;
|
||||||
return a.which() < b.which();
|
return a.template get<Value>() == b.template get<Value>();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename X, typename = type_in_typelist<X>>
|
template<typename X, typename = type_in_typelist<X>>
|
||||||
X& get() {
|
X& get() {
|
||||||
if(_tag == impl::position<X, Types...>::pos) {
|
if(_tag == typelist::index_of<list, X>()) {
|
||||||
return *reinterpret_cast<X*>(storage.data());
|
return *reinterpret_cast<X*>(storage.data());
|
||||||
} else {
|
} else {
|
||||||
FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename<X>::name()) );
|
FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename<X>::name()) );
|
||||||
|
|
@ -376,7 +240,7 @@ public:
|
||||||
}
|
}
|
||||||
template<typename X, typename = type_in_typelist<X>>
|
template<typename X, typename = type_in_typelist<X>>
|
||||||
const X& get() const {
|
const X& get() const {
|
||||||
if(_tag == impl::position<X, Types...>::pos) {
|
if(_tag == typelist::index_of<list, X>()) {
|
||||||
return *reinterpret_cast<const X*>(storage.data());
|
return *reinterpret_cast<const X*>(storage.data());
|
||||||
} else {
|
} else {
|
||||||
FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename<X>::name()) );
|
FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename<X>::name()) );
|
||||||
|
|
@ -405,41 +269,45 @@ public:
|
||||||
template<typename visitor>
|
template<typename visitor>
|
||||||
static typename visitor::result_type visit( tag_type tag, visitor& v, void* data )
|
static typename visitor::result_type visit( tag_type tag, visitor& v, void* data )
|
||||||
{
|
{
|
||||||
static const auto wrappers = init_wrappers<impl::type_info<Types...>::count,visitor,void*,Types...>( v, data );
|
FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) );
|
||||||
FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) );
|
return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
|
||||||
return wrappers[tag]( v, data );
|
return v(*reinterpret_cast<typename decltype(t)::type*>(data));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename visitor>
|
template<typename visitor>
|
||||||
static typename visitor::result_type visit( tag_type tag, const visitor& v, void* data )
|
static typename visitor::result_type visit( tag_type tag, const visitor& v, void* data )
|
||||||
{
|
{
|
||||||
static const auto wrappers = init_wrappers<impl::type_info<Types...>::count,const visitor,void*,Types...>( v, data );
|
FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) );
|
||||||
FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) );
|
return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
|
||||||
return wrappers[tag]( v, data );
|
return v(*reinterpret_cast<typename decltype(t)::type*>(data));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename visitor>
|
template<typename visitor>
|
||||||
static typename visitor::result_type visit( tag_type tag, visitor& v, const void* data )
|
static typename visitor::result_type visit( tag_type tag, visitor& v, const void* data )
|
||||||
{
|
{
|
||||||
static const auto wrappers = init_const_wrappers<impl::type_info<Types...>::count,visitor,const void*,Types...>( v, data );
|
FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) );
|
||||||
FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) );
|
return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
|
||||||
return wrappers[tag]( v, data );
|
return v(*reinterpret_cast<const typename decltype(t)::type*>(data));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename visitor>
|
template<typename visitor>
|
||||||
static typename visitor::result_type visit( tag_type tag, const visitor& v, const void* data )
|
static typename visitor::result_type visit( tag_type tag, const visitor& v, const void* data )
|
||||||
{
|
{
|
||||||
static const auto wrappers = init_const_wrappers<impl::type_info<Types...>::count,const visitor,const void*,Types...>( v, data );
|
FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) );
|
||||||
FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) );
|
return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
|
||||||
return wrappers[tag]( v, data );
|
return v(*reinterpret_cast<const typename decltype(t)::type*>(data));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static int count() { return impl::type_info<Types...>::count; }
|
static constexpr size_t count() { return typelist::length<list>(); }
|
||||||
void set_which( tag_type w ) {
|
void set_which( tag_type tag ) {
|
||||||
FC_ASSERT( w >= 0 );
|
FC_ASSERT( tag >= 0 );
|
||||||
FC_ASSERT( w < count() );
|
FC_ASSERT( static_cast<size_t>(tag) < count() );
|
||||||
clean();
|
clean();
|
||||||
init_from_tag(w);
|
init_from_tag(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
tag_type which() const {return _tag;}
|
tag_type which() const {return _tag;}
|
||||||
|
|
@ -447,6 +315,12 @@ public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool is_type() const { return _tag == tag<T>::value; }
|
bool is_type() const { return _tag == tag<T>::value; }
|
||||||
};
|
};
|
||||||
|
template<> class static_variant<> {
|
||||||
|
public:
|
||||||
|
using tag_type = int64_t;
|
||||||
|
static_variant() { FC_THROW_EXCEPTION(assert_exception, "Cannot create static_variant with no types"); }
|
||||||
|
};
|
||||||
|
template<typename... Types> class static_variant<typelist::list<Types...>> : public static_variant<Types...> {};
|
||||||
|
|
||||||
struct from_static_variant
|
struct from_static_variant
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace fc
|
||||||
std::string to_pretty_string( int64_t );
|
std::string to_pretty_string( int64_t );
|
||||||
inline std::string to_string( int32_t v ) { return to_string( int64_t(v) ); }
|
inline std::string to_string( int32_t v ) { return to_string( int64_t(v) ); }
|
||||||
inline std::string to_string( uint32_t v ){ return to_string( uint64_t(v) ); }
|
inline std::string to_string( uint32_t v ){ return to_string( uint64_t(v) ); }
|
||||||
#ifdef __APPLE__
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
||||||
inline std::string to_string( size_t s) { return to_string(uint64_t(s)); }
|
inline std::string to_string( size_t s) { return to_string(uint64_t(s)); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fc/time.hpp>
|
#include <fc/time.hpp>
|
||||||
#include <fc/shared_ptr.hpp>
|
|
||||||
#include <fc/exception/exception.hpp>
|
#include <fc/exception/exception.hpp>
|
||||||
#include <fc/thread/spin_yield_lock.hpp>
|
#include <fc/thread/spin_yield_lock.hpp>
|
||||||
#include <fc/optional.hpp>
|
#include <fc/optional.hpp>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
//#define FC_TASK_NAMES_ARE_MANDATORY 1
|
//#define FC_TASK_NAMES_ARE_MANDATORY 1
|
||||||
#ifdef FC_TASK_NAMES_ARE_MANDATORY
|
#ifdef FC_TASK_NAMES_ARE_MANDATORY
|
||||||
# define FC_TASK_NAME_DEFAULT_ARG
|
# define FC_TASK_NAME_DEFAULT_ARG
|
||||||
|
|
@ -56,10 +58,10 @@ namespace fc {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class promise_base : public virtual retainable{
|
class promise_base : public std::enable_shared_from_this<promise_base> {
|
||||||
public:
|
public:
|
||||||
typedef fc::shared_ptr<promise_base> ptr;
|
typedef std::shared_ptr<promise_base> ptr;
|
||||||
promise_base(const char* desc FC_TASK_NAME_DEFAULT_ARG);
|
virtual ~promise_base();
|
||||||
|
|
||||||
const char* get_desc()const;
|
const char* get_desc()const;
|
||||||
|
|
||||||
|
|
@ -71,26 +73,26 @@ namespace fc {
|
||||||
void set_exception( const fc::exception_ptr& e );
|
void set_exception( const fc::exception_ptr& e );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
promise_base(const char* desc FC_TASK_NAME_DEFAULT_ARG);
|
||||||
|
|
||||||
void _wait( const microseconds& timeout_us );
|
void _wait( const microseconds& timeout_us );
|
||||||
void _wait_until( const time_point& timeout_us );
|
void _wait_until( const time_point& timeout_us );
|
||||||
void _enqueue_thread();
|
|
||||||
void _dequeue_thread();
|
|
||||||
void _notify();
|
void _notify();
|
||||||
void _set_timeout();
|
|
||||||
void _set_value(const void* v);
|
void _set_value(const void* v);
|
||||||
|
|
||||||
void _on_complete( detail::completion_handler* c );
|
void _on_complete( detail::completion_handler* c );
|
||||||
~promise_base();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void _enqueue_thread();
|
||||||
|
void _dequeue_thread();
|
||||||
|
|
||||||
friend class thread;
|
friend class thread;
|
||||||
friend struct context;
|
friend struct context;
|
||||||
friend class thread_d;
|
friend class thread_d;
|
||||||
|
|
||||||
bool _ready;
|
std::atomic<bool> _ready;
|
||||||
mutable spin_yield_lock _spin_yield;
|
std::atomic<thread*> _blocked_thread;
|
||||||
thread* _blocked_thread;
|
std::atomic<int32_t> _blocked_fiber_count;
|
||||||
unsigned _blocked_fiber_count;
|
|
||||||
time_point _timeout;
|
time_point _timeout;
|
||||||
fc::exception_ptr _exceptp;
|
fc::exception_ptr _exceptp;
|
||||||
bool _canceled;
|
bool _canceled;
|
||||||
|
|
@ -99,18 +101,29 @@ namespace fc {
|
||||||
const char* _cancellation_reason;
|
const char* _cancellation_reason;
|
||||||
private:
|
private:
|
||||||
#endif
|
#endif
|
||||||
const char* _desc;
|
const char* _desc;
|
||||||
detail::completion_handler* _compl;
|
std::atomic<detail::completion_handler*> _compl;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T = void>
|
template<typename T = void>
|
||||||
class promise : virtual public promise_base {
|
class promise : virtual public promise_base {
|
||||||
public:
|
public:
|
||||||
typedef fc::shared_ptr< promise<T> > ptr;
|
typedef std::shared_ptr< promise<T> > ptr;
|
||||||
promise( const char* desc FC_TASK_NAME_DEFAULT_ARG):promise_base(desc){}
|
virtual ~promise(){}
|
||||||
promise( const T& val ){ set_value(val); }
|
|
||||||
promise( T&& val ){ set_value(std::move(val) ); }
|
static ptr create( const char* desc FC_TASK_NAME_DEFAULT_ARG )
|
||||||
|
{
|
||||||
|
return ptr( new promise<T>( desc ) );
|
||||||
|
}
|
||||||
|
static ptr create( const T& val )
|
||||||
|
{
|
||||||
|
return ptr( new promise<T>( val ) );
|
||||||
|
}
|
||||||
|
static ptr create( T&& val )
|
||||||
|
{
|
||||||
|
return ptr( new promise<T>( std::move(val) ) );
|
||||||
|
}
|
||||||
|
|
||||||
const T& wait(const microseconds& timeout = microseconds::maximum() ){
|
const T& wait(const microseconds& timeout = microseconds::maximum() ){
|
||||||
this->_wait( timeout );
|
this->_wait( timeout );
|
||||||
return *result;
|
return *result;
|
||||||
|
|
@ -132,22 +145,32 @@ namespace fc {
|
||||||
|
|
||||||
template<typename CompletionHandler>
|
template<typename CompletionHandler>
|
||||||
void on_complete( CompletionHandler&& c ) {
|
void on_complete( CompletionHandler&& c ) {
|
||||||
_on_complete( new detail::completion_handler_impl<CompletionHandler,T>(fc::forward<CompletionHandler>(c)) );
|
_on_complete( new detail::completion_handler_impl<CompletionHandler,T>(std::forward<CompletionHandler>(c)) );
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
|
promise( const char* desc ):promise_base(desc){}
|
||||||
|
promise( const T& val ){ set_value(val); }
|
||||||
|
promise( T&& val ){ set_value(std::move(val) ); }
|
||||||
|
|
||||||
optional<T> result;
|
optional<T> result;
|
||||||
~promise(){}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class promise<void> : virtual public promise_base {
|
class promise<void> : virtual public promise_base {
|
||||||
public:
|
public:
|
||||||
typedef fc::shared_ptr< promise<void> > ptr;
|
typedef std::shared_ptr< promise<void> > ptr;
|
||||||
promise( const char* desc FC_TASK_NAME_DEFAULT_ARG):promise_base(desc){}
|
|
||||||
promise( bool fulfilled, const char* desc FC_TASK_NAME_DEFAULT_ARG ){
|
virtual ~promise(){}
|
||||||
if( fulfilled ) set_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
static ptr create( const char* desc FC_TASK_NAME_DEFAULT_ARG )
|
||||||
|
{
|
||||||
|
return ptr( new promise<void>( desc ) );
|
||||||
|
}
|
||||||
|
static ptr create( bool fulfilled, const char* desc FC_TASK_NAME_DEFAULT_ARG )
|
||||||
|
{
|
||||||
|
return ptr( new promise<void>( fulfilled, desc ) );
|
||||||
|
}
|
||||||
|
|
||||||
void wait(const microseconds& timeout = microseconds::maximum() ){
|
void wait(const microseconds& timeout = microseconds::maximum() ){
|
||||||
this->_wait( timeout );
|
this->_wait( timeout );
|
||||||
}
|
}
|
||||||
|
|
@ -160,10 +183,13 @@ namespace fc {
|
||||||
|
|
||||||
template<typename CompletionHandler>
|
template<typename CompletionHandler>
|
||||||
void on_complete( CompletionHandler&& c ) {
|
void on_complete( CompletionHandler&& c ) {
|
||||||
_on_complete( new detail::completion_handler_impl<CompletionHandler,void>(fc::forward<CompletionHandler>(c)) );
|
_on_complete( new detail::completion_handler_impl<CompletionHandler,void>(std::forward<CompletionHandler>(c)) );
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
~promise(){}
|
promise( const char* desc ):promise_base(desc){}
|
||||||
|
promise( bool fulfilled, const char* desc ){
|
||||||
|
if( fulfilled ) set_value();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -184,8 +210,8 @@ namespace fc {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class future {
|
class future {
|
||||||
public:
|
public:
|
||||||
future( const fc::shared_ptr<promise<T>>& p ):m_prom(p){}
|
future( const typename promise<T>::ptr& p ):m_prom(p){}
|
||||||
future( fc::shared_ptr<promise<T>>&& p ):m_prom(std::move(p)){}
|
future( typename promise<T>::ptr&& p ):m_prom(std::move(p)){}
|
||||||
future(const future<T>& f ) : m_prom(f.m_prom){}
|
future(const future<T>& f ) : m_prom(f.m_prom){}
|
||||||
future(){}
|
future(){}
|
||||||
|
|
||||||
|
|
@ -194,7 +220,6 @@ namespace fc {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator const T&()const { return wait(); }
|
operator const T&()const { return wait(); }
|
||||||
|
|
||||||
/// @pre valid()
|
/// @pre valid()
|
||||||
|
|
@ -247,18 +272,18 @@ namespace fc {
|
||||||
*/
|
*/
|
||||||
template<typename CompletionHandler>
|
template<typename CompletionHandler>
|
||||||
void on_complete( CompletionHandler&& c ) {
|
void on_complete( CompletionHandler&& c ) {
|
||||||
m_prom->on_complete( fc::forward<CompletionHandler>(c) );
|
m_prom->on_complete( std::forward<CompletionHandler>(c) );
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
friend class thread;
|
friend class thread;
|
||||||
fc::shared_ptr<promise<T>> m_prom;
|
typename promise<T>::ptr m_prom;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class future<void> {
|
class future<void> {
|
||||||
public:
|
public:
|
||||||
future( const fc::shared_ptr<promise<void>>& p ):m_prom(p){}
|
future( const typename promise<void>::ptr& p ):m_prom(p){}
|
||||||
future( fc::shared_ptr<promise<void>>&& p ):m_prom(std::move(p)){}
|
future( typename promise<void>::ptr&& p ):m_prom(std::move(p)){}
|
||||||
future(const future<void>& f ) : m_prom(f.m_prom){}
|
future(const future<void>& f ) : m_prom(f.m_prom){}
|
||||||
future(){}
|
future(){}
|
||||||
|
|
||||||
|
|
@ -308,12 +333,12 @@ namespace fc {
|
||||||
|
|
||||||
template<typename CompletionHandler>
|
template<typename CompletionHandler>
|
||||||
void on_complete( CompletionHandler&& c ) {
|
void on_complete( CompletionHandler&& c ) {
|
||||||
m_prom->on_complete( fc::forward<CompletionHandler>(c) );
|
m_prom->on_complete( std::forward<CompletionHandler>(c) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class thread;
|
friend class thread;
|
||||||
fc::shared_ptr<promise<void>> m_prom;
|
typename promise<void>::ptr m_prom;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,8 @@ namespace fc {
|
||||||
~ticket_guard();
|
~ticket_guard();
|
||||||
void wait_for_my_turn();
|
void wait_for_my_turn();
|
||||||
private:
|
private:
|
||||||
promise<void>* my_promise;
|
promise<void>::ptr my_promise;
|
||||||
future<void>* ticket;
|
future<void>* ticket;
|
||||||
};
|
};
|
||||||
|
|
||||||
friend class ticket_guard;
|
friend class ticket_guard;
|
||||||
|
|
@ -96,11 +96,12 @@ namespace fc {
|
||||||
template<typename Functor>
|
template<typename Functor>
|
||||||
auto do_parallel( Functor&& f, const char* desc FC_TASK_NAME_DEFAULT_ARG ) -> fc::future<decltype(f())> {
|
auto do_parallel( Functor&& f, const char* desc FC_TASK_NAME_DEFAULT_ARG ) -> fc::future<decltype(f())> {
|
||||||
typedef decltype(f()) Result;
|
typedef decltype(f()) Result;
|
||||||
typedef typename fc::deduce<Functor>::type FunctorType;
|
typedef typename std::remove_const_t< std::remove_reference_t<Functor> > FunctorType;
|
||||||
fc::task<Result,sizeof(FunctorType)>* tsk =
|
typename task<Result,sizeof(FunctorType)>::ptr tsk =
|
||||||
new fc::task<Result,sizeof(FunctorType)>( fc::forward<Functor>(f), desc );
|
task<Result,sizeof(FunctorType)>::create( std::forward<Functor>(f), desc );
|
||||||
fc::future<Result> r(fc::shared_ptr< fc::promise<Result> >(tsk,true) );
|
tsk->retain(); // HERE BE DRAGONS
|
||||||
detail::get_worker_pool().post( tsk );
|
fc::future<Result> r( std::dynamic_pointer_cast< promise<Result> >(tsk) );
|
||||||
|
detail::get_worker_pool().post( tsk.get() );
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
#include <fc/thread/future.hpp>
|
#include <fc/thread/future.hpp>
|
||||||
#include <fc/thread/priority.hpp>
|
#include <fc/thread/priority.hpp>
|
||||||
#include <fc/fwd.hpp>
|
#include <fc/fwd.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <boost/atomic.hpp>
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
struct context;
|
struct context;
|
||||||
|
|
@ -31,9 +34,28 @@ namespace fc {
|
||||||
public:
|
public:
|
||||||
void run();
|
void run();
|
||||||
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override;
|
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override;
|
||||||
|
virtual ~task_base();
|
||||||
|
|
||||||
|
/* HERE BE DRAGONS
|
||||||
|
*
|
||||||
|
* Tasks are handled by an fc::thread . To avoid concurrency issues, fc::thread keeps a reference to the
|
||||||
|
* task in the form of a simple pointer.
|
||||||
|
* At the same time, a task is also a promise that will be fulfilled with the task result, so typically the
|
||||||
|
* creator of the task also keeps a reference to the task (but not necessarily always).
|
||||||
|
*
|
||||||
|
* Because effectively neither fc::thread nor the task creator are responsible for releasing resources
|
||||||
|
* associated with a task, and neither can delete the task without knowing if the other still needs it,
|
||||||
|
* the task object is managed by a shared_ptr.
|
||||||
|
* However, fc::thread doesn't hold a shared_ptr but a native pointer. To work around this, the task can
|
||||||
|
* be made to contain a shared_ptr holding itself (by calling retain()), which happens before the task
|
||||||
|
* is handed to an fc::thread, e. g. in fc::async(). Once the thread has processed the task, it calls
|
||||||
|
* release() which deletes the self-referencing shared_ptr and deletes the task object if it's no longer
|
||||||
|
* in use anywhere.
|
||||||
|
*/
|
||||||
|
void retain();
|
||||||
|
void release();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~task_base();
|
|
||||||
/// Task priority looks like unsupported feature.
|
/// Task priority looks like unsupported feature.
|
||||||
uint64_t _posted_num;
|
uint64_t _posted_num;
|
||||||
priority _prio;
|
priority _prio;
|
||||||
|
|
@ -65,6 +87,9 @@ namespace fc {
|
||||||
void run_impl();
|
void run_impl();
|
||||||
|
|
||||||
void cleanup_task_specific_data();
|
void cleanup_task_specific_data();
|
||||||
|
private:
|
||||||
|
std::shared_ptr<promise_base> _self;
|
||||||
|
boost::atomic<int32_t> _retain_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
@ -90,41 +115,57 @@ namespace fc {
|
||||||
template<typename R,uint64_t FunctorSize=64>
|
template<typename R,uint64_t FunctorSize=64>
|
||||||
class task : virtual public task_base, virtual public promise<R> {
|
class task : virtual public task_base, virtual public promise<R> {
|
||||||
public:
|
public:
|
||||||
|
typedef std::shared_ptr<task<R,FunctorSize>> ptr;
|
||||||
|
|
||||||
|
virtual ~task(){}
|
||||||
|
|
||||||
|
template<typename Functor>
|
||||||
|
static ptr create( Functor&& f, const char* desc )
|
||||||
|
{
|
||||||
|
return ptr( new task<R,FunctorSize>( std::move(f), desc ) );
|
||||||
|
}
|
||||||
|
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override { task_base::cancel(reason); }
|
||||||
|
private:
|
||||||
template<typename Functor>
|
template<typename Functor>
|
||||||
task( Functor&& f, const char* desc ):promise_base(desc), task_base(&_functor), promise<R>(desc) {
|
task( Functor&& f, const char* desc ):promise_base(desc), task_base(&_functor), promise<R>(desc) {
|
||||||
typedef typename fc::deduce<Functor>::type FunctorType;
|
typedef typename std::remove_const_t< std::remove_reference_t<Functor> > FunctorType;
|
||||||
static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" );
|
static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" );
|
||||||
new ((char*)&_functor) FunctorType( fc::forward<Functor>(f) );
|
new ((char*)&_functor) FunctorType( std::forward<Functor>(f) );
|
||||||
_destroy_functor = &detail::functor_destructor<FunctorType>::destroy;
|
_destroy_functor = &detail::functor_destructor<FunctorType>::destroy;
|
||||||
|
|
||||||
_promise_impl = static_cast<promise<R>*>(this);
|
_promise_impl = static_cast<promise<R>*>(this);
|
||||||
_run_functor = &detail::functor_run<FunctorType>::run;
|
_run_functor = &detail::functor_run<FunctorType>::run;
|
||||||
}
|
}
|
||||||
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override { task_base::cancel(reason); }
|
|
||||||
|
|
||||||
alignas(double) char _functor[FunctorSize];
|
alignas(double) char _functor[FunctorSize];
|
||||||
private:
|
|
||||||
~task(){}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<uint64_t FunctorSize>
|
template<uint64_t FunctorSize>
|
||||||
class task<void,FunctorSize> : virtual public task_base, virtual public promise<void> {
|
class task<void,FunctorSize> : public task_base, public promise<void> {
|
||||||
public:
|
public:
|
||||||
|
typedef std::shared_ptr<task<void,FunctorSize>> ptr;
|
||||||
|
|
||||||
|
virtual ~task(){}
|
||||||
|
|
||||||
|
template<typename Functor>
|
||||||
|
static ptr create( Functor&& f, const char* desc )
|
||||||
|
{
|
||||||
|
return ptr( new task<void,FunctorSize>( std::move(f), desc ) );
|
||||||
|
}
|
||||||
|
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override { task_base::cancel(reason); }
|
||||||
|
private:
|
||||||
template<typename Functor>
|
template<typename Functor>
|
||||||
task( Functor&& f, const char* desc ):promise_base(desc), task_base(&_functor), promise<void>(desc) {
|
task( Functor&& f, const char* desc ):promise_base(desc), task_base(&_functor), promise<void>(desc) {
|
||||||
typedef typename fc::deduce<Functor>::type FunctorType;
|
typedef typename std::remove_const_t< std::remove_reference_t<Functor> > FunctorType;
|
||||||
static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" );
|
static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" );
|
||||||
new ((char*)&_functor) FunctorType( fc::forward<Functor>(f) );
|
new ((char*)&_functor) FunctorType( std::forward<Functor>(f) );
|
||||||
_destroy_functor = &detail::functor_destructor<FunctorType>::destroy;
|
_destroy_functor = &detail::functor_destructor<FunctorType>::destroy;
|
||||||
|
|
||||||
_promise_impl = static_cast<promise<void>*>(this);
|
_promise_impl = static_cast<promise<void>*>(this);
|
||||||
_run_functor = &detail::void_functor_run<FunctorType>::run;
|
_run_functor = &detail::void_functor_run<FunctorType>::run;
|
||||||
}
|
}
|
||||||
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override { task_base::cancel(reason); }
|
|
||||||
|
|
||||||
alignas(double) char _functor[FunctorSize];
|
alignas(double) char _functor[FunctorSize];
|
||||||
private:
|
|
||||||
~task(){}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,11 +86,12 @@ namespace fc {
|
||||||
template<typename Functor>
|
template<typename Functor>
|
||||||
auto async( Functor&& f, const char* desc FC_TASK_NAME_DEFAULT_ARG, priority prio = priority()) -> fc::future<decltype(f())> {
|
auto async( Functor&& f, const char* desc FC_TASK_NAME_DEFAULT_ARG, priority prio = priority()) -> fc::future<decltype(f())> {
|
||||||
typedef decltype(f()) Result;
|
typedef decltype(f()) Result;
|
||||||
typedef typename fc::deduce<Functor>::type FunctorType;
|
typedef typename std::remove_const_t< std::remove_reference_t<Functor> > FunctorType;
|
||||||
fc::task<Result,sizeof(FunctorType)>* tsk =
|
typename task<Result,sizeof(FunctorType)>::ptr tsk =
|
||||||
new fc::task<Result,sizeof(FunctorType)>( fc::forward<Functor>(f), desc );
|
task<Result,sizeof(FunctorType)>::create( std::forward<Functor>(f), desc );
|
||||||
fc::future<Result> r(fc::shared_ptr< fc::promise<Result> >(tsk,true) );
|
tsk->retain(); // HERE BE DRAGONS
|
||||||
async_task(tsk,prio);
|
fc::future<Result> r( std::dynamic_pointer_cast< promise<Result> >(tsk) );
|
||||||
|
async_task(tsk.get(),prio);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
void poke();
|
void poke();
|
||||||
|
|
@ -109,10 +110,11 @@ namespace fc {
|
||||||
auto schedule( Functor&& f, const fc::time_point& when,
|
auto schedule( Functor&& f, const fc::time_point& when,
|
||||||
const char* desc FC_TASK_NAME_DEFAULT_ARG, priority prio = priority()) -> fc::future<decltype(f())> {
|
const char* desc FC_TASK_NAME_DEFAULT_ARG, priority prio = priority()) -> fc::future<decltype(f())> {
|
||||||
typedef decltype(f()) Result;
|
typedef decltype(f()) Result;
|
||||||
fc::task<Result,sizeof(Functor)>* tsk =
|
typename task<Result,sizeof(Functor)>::ptr tsk =
|
||||||
new fc::task<Result,sizeof(Functor)>( fc::forward<Functor>(f), desc );
|
task<Result,sizeof(Functor)>::create( std::forward<Functor>(f), desc );
|
||||||
fc::future<Result> r(fc::shared_ptr< fc::promise<Result> >(tsk,true) );
|
tsk->retain(); // HERE BE DRAGONS
|
||||||
async_task(tsk,prio,when);
|
fc::future<Result> r( std::dynamic_pointer_cast< promise<Result> >(tsk) );
|
||||||
|
async_task(tsk.get(),prio,when);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,8 +149,8 @@ namespace fc {
|
||||||
template<typename T1, typename T2>
|
template<typename T1, typename T2>
|
||||||
int wait_any( const fc::future<T1>& f1, const fc::future<T2>& f2, const microseconds& timeout_us = microseconds::maximum()) {
|
int wait_any( const fc::future<T1>& f1, const fc::future<T2>& f2, const microseconds& timeout_us = microseconds::maximum()) {
|
||||||
std::vector<fc::promise_base::ptr> proms(2);
|
std::vector<fc::promise_base::ptr> proms(2);
|
||||||
proms[0] = fc::static_pointer_cast<fc::promise_base>(f1.m_prom);
|
proms[0] = std::static_pointer_cast<fc::promise_base>(f1.m_prom);
|
||||||
proms[1] = fc::static_pointer_cast<fc::promise_base>(f2.m_prom);
|
proms[1] = std::static_pointer_cast<fc::promise_base>(f2.m_prom);
|
||||||
return wait_any_until(std::move(proms), fc::time_point::now()+timeout_us );
|
return wait_any_until(std::move(proms), fc::time_point::now()+timeout_us );
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
|
@ -223,11 +225,11 @@ namespace fc {
|
||||||
|
|
||||||
template<typename Functor>
|
template<typename Functor>
|
||||||
auto async( Functor&& f, const char* desc FC_TASK_NAME_DEFAULT_ARG, priority prio = priority()) -> fc::future<decltype(f())> {
|
auto async( Functor&& f, const char* desc FC_TASK_NAME_DEFAULT_ARG, priority prio = priority()) -> fc::future<decltype(f())> {
|
||||||
return fc::thread::current().async( fc::forward<Functor>(f), desc, prio );
|
return fc::thread::current().async( std::forward<Functor>(f), desc, prio );
|
||||||
}
|
}
|
||||||
template<typename Functor>
|
template<typename Functor>
|
||||||
auto schedule( Functor&& f, const fc::time_point& t, const char* desc FC_TASK_NAME_DEFAULT_ARG, priority prio = priority()) -> fc::future<decltype(f())> {
|
auto schedule( Functor&& f, const fc::time_point& t, const char* desc FC_TASK_NAME_DEFAULT_ARG, priority prio = priority()) -> fc::future<decltype(f())> {
|
||||||
return fc::thread::current().schedule( fc::forward<Functor>(f), t, desc, prio );
|
return fc::thread::current().schedule( std::forward<Functor>(f), t, desc, prio );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,158 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 BitShares Blockchain Foundation, and contributors.
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <limits>
|
|
||||||
|
#ifdef __SIZEOF_INT128__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <fc/config.hpp>
|
namespace fc {
|
||||||
#include <fc/exception/exception.hpp>
|
|
||||||
#include <fc/crypto/city.hpp>
|
|
||||||
#include <fc/io/raw.hpp>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
using int128_t = __int128_t;
|
||||||
#pragma warning (push)
|
using uint128_t = __uint128_t;
|
||||||
#pragma warning (disable : 4244)
|
|
||||||
#endif //// _MSC_VER
|
|
||||||
|
|
||||||
namespace fc
|
inline uint64_t uint128_lo64(const uint128_t x) {
|
||||||
{
|
return static_cast<uint64_t>(x & 0xffffffffffffffffULL);
|
||||||
class bigint;
|
}
|
||||||
/**
|
inline uint64_t uint128_hi64(const uint128_t x) {
|
||||||
* @brief an implementation of 128 bit unsigned integer
|
return static_cast<uint64_t>( x >> 64 );
|
||||||
*
|
|
||||||
*/
|
|
||||||
class uint128
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
uint128():hi(0),lo(0){}
|
|
||||||
uint128( uint32_t l ):hi(0),lo(l){}
|
|
||||||
uint128( int32_t l ):hi( -(l<0) ),lo(l){}
|
|
||||||
uint128( int64_t l ):hi( -(l<0) ),lo(l){}
|
|
||||||
uint128( uint64_t l ):hi(0),lo(l){}
|
|
||||||
uint128( const std::string& s );
|
|
||||||
uint128( uint64_t _h, uint64_t _l )
|
|
||||||
:hi(_h),lo(_l){}
|
|
||||||
uint128( const fc::bigint& bi );
|
|
||||||
|
|
||||||
operator std::string()const;
|
|
||||||
operator fc::bigint()const;
|
|
||||||
|
|
||||||
bool operator == ( const uint128& o )const{ return hi == o.hi && lo == o.lo; }
|
|
||||||
bool operator != ( const uint128& o )const{ return hi != o.hi || lo != o.lo; }
|
|
||||||
bool operator < ( const uint128& o )const { return (hi == o.hi) ? lo < o.lo : hi < o.hi; }
|
|
||||||
bool operator < ( const int64_t& o )const { return *this < uint128(o); }
|
|
||||||
bool operator !()const { return !(hi !=0 || lo != 0); }
|
|
||||||
uint128 operator -()const { return ++uint128( ~hi, ~lo ); }
|
|
||||||
uint128 operator ~()const { return uint128( ~hi, ~lo ); }
|
|
||||||
|
|
||||||
uint128& operator++() { hi += (++lo == 0); return *this; }
|
|
||||||
uint128& operator--() { hi -= (lo-- == 0); return *this; }
|
|
||||||
uint128 operator++(int) { auto tmp = *this; ++(*this); return tmp; }
|
|
||||||
uint128 operator--(int) { auto tmp = *this; --(*this); return tmp; }
|
|
||||||
|
|
||||||
uint128& operator |= ( const uint128& u ) { hi |= u.hi; lo |= u.lo; return *this; }
|
|
||||||
uint128& operator &= ( const uint128& u ) { hi &= u.hi; lo &= u.lo; return *this; }
|
|
||||||
uint128& operator ^= ( const uint128& u ) { hi ^= u.hi; lo ^= u.lo; return *this; }
|
|
||||||
uint128& operator <<= ( const uint128& u );
|
|
||||||
uint128& operator >>= ( const uint128& u );
|
|
||||||
|
|
||||||
uint128& operator += ( const uint128& u ) { const uint64_t old = lo; lo += u.lo; hi += u.hi + (lo < old); return *this; }
|
|
||||||
uint128& operator -= ( const uint128& u ) { return *this += -u; }
|
|
||||||
uint128& operator *= ( const uint128& u );
|
|
||||||
uint128& operator /= ( const uint128& u );
|
|
||||||
uint128& operator %= ( const uint128& u );
|
|
||||||
|
|
||||||
|
|
||||||
friend uint128 operator + ( const uint128& l, const uint128& r ) { return uint128(l)+=r; }
|
|
||||||
friend uint128 operator - ( const uint128& l, const uint128& r ) { return uint128(l)-=r; }
|
|
||||||
friend uint128 operator * ( const uint128& l, const uint128& r ) { return uint128(l)*=r; }
|
|
||||||
friend uint128 operator / ( const uint128& l, const uint128& r ) { return uint128(l)/=r; }
|
|
||||||
friend uint128 operator % ( const uint128& l, const uint128& r ) { return uint128(l)%=r; }
|
|
||||||
friend uint128 operator | ( const uint128& l, const uint128& r ) { return uint128(l)=(r); }
|
|
||||||
friend uint128 operator & ( const uint128& l, const uint128& r ) { return uint128(l)&=r; }
|
|
||||||
friend uint128 operator ^ ( const uint128& l, const uint128& r ) { return uint128(l)^=r; }
|
|
||||||
friend uint128 operator << ( const uint128& l, const uint128& r ) { return uint128(l)<<=r; }
|
|
||||||
friend uint128 operator >> ( const uint128& l, const uint128& r ) { return uint128(l)>>=r; }
|
|
||||||
friend bool operator > ( const uint128& l, const uint128& r ) { return r < l; }
|
|
||||||
friend bool operator > ( const uint128& l, const int64_t& r ) { return uint128(r) < l; }
|
|
||||||
friend bool operator > ( const int64_t& l, const uint128& r ) { return r < uint128(l); }
|
|
||||||
|
|
||||||
friend bool operator >= ( const uint128& l, const uint128& r ) { return l == r || l > r; }
|
|
||||||
friend bool operator >= ( const uint128& l, const int64_t& r ) { return l >= uint128(r); }
|
|
||||||
friend bool operator >= ( const int64_t& l, const uint128& r ) { return uint128(l) >= r; }
|
|
||||||
friend bool operator <= ( const uint128& l, const uint128& r ) { return l == r || l < r; }
|
|
||||||
friend bool operator <= ( const uint128& l, const int64_t& r ) { return l <= uint128(r); }
|
|
||||||
friend bool operator <= ( const int64_t& l, const uint128& r ) { return uint128(l) <= r; }
|
|
||||||
|
|
||||||
friend std::size_t hash_value( const uint128& v ) { return city_hash_size_t((const char*)&v, sizeof(v)); }
|
|
||||||
|
|
||||||
uint32_t to_integer()const
|
|
||||||
{
|
|
||||||
FC_ASSERT( hi == 0 );
|
|
||||||
uint32_t lo32 = (uint32_t) lo;
|
|
||||||
FC_ASSERT( lo == lo32 );
|
|
||||||
return lo32;
|
|
||||||
}
|
|
||||||
uint64_t to_uint64()const
|
|
||||||
{
|
|
||||||
FC_ASSERT( hi == 0 );
|
|
||||||
return lo;
|
|
||||||
}
|
|
||||||
uint32_t low_32_bits()const { return (uint32_t) lo; }
|
|
||||||
uint64_t low_bits()const { return lo; }
|
|
||||||
uint64_t high_bits()const { return hi; }
|
|
||||||
|
|
||||||
static uint128 max_value() {
|
|
||||||
const uint64_t max64 = std::numeric_limits<uint64_t>::max();
|
|
||||||
return uint128( max64, max64 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void full_product( const uint128& a, const uint128& b, uint128& result_hi, uint128& result_lo );
|
|
||||||
|
|
||||||
uint8_t popcount() const;
|
|
||||||
|
|
||||||
// fields must be public for serialization
|
|
||||||
uint64_t hi;
|
|
||||||
uint64_t lo;
|
|
||||||
};
|
|
||||||
static_assert( sizeof(uint128) == 2*sizeof(uint64_t), "validate packing assumptions" );
|
|
||||||
|
|
||||||
typedef uint128 uint128_t;
|
|
||||||
|
|
||||||
class variant;
|
|
||||||
|
|
||||||
void to_variant( const uint128& var, variant& vo, uint32_t max_depth = 1 );
|
|
||||||
void from_variant( const variant& var, uint128& vo, uint32_t max_depth = 1 );
|
|
||||||
|
|
||||||
namespace raw
|
|
||||||
{
|
|
||||||
template<typename Stream>
|
|
||||||
inline void pack( Stream& s, const uint128& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
|
|
||||||
pack( s, u.hi, _max_depth );
|
|
||||||
pack( s, u.lo, _max_depth );
|
|
||||||
}
|
|
||||||
template<typename Stream>
|
|
||||||
inline void unpack( Stream& s, uint128& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
|
|
||||||
unpack( s, u.hi, _max_depth );
|
|
||||||
unpack( s, u.lo, _max_depth );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t city_hash_size_t(const char *buf, size_t len);
|
|
||||||
} // namespace fc
|
|
||||||
|
|
||||||
namespace std
|
|
||||||
{
|
|
||||||
template<>
|
|
||||||
struct hash<fc::uint128>
|
|
||||||
{
|
|
||||||
size_t operator()( const fc::uint128& s )const;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FC_REFLECT( fc::uint128_t, (hi)(lo) )
|
} // namespace fc
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#else // __SIZEOF_INT128__
|
||||||
#pragma warning (pop)
|
|
||||||
#endif ///_MSC_VER
|
#include <boost/multiprecision/integer.hpp>
|
||||||
|
|
||||||
|
namespace fc {
|
||||||
|
|
||||||
|
using boost::multiprecision::int128_t;
|
||||||
|
using boost::multiprecision::uint128_t;
|
||||||
|
|
||||||
|
inline uint64_t uint128_lo64(const uint128_t& x) {
|
||||||
|
return static_cast<uint64_t>(x & 0xffffffffffffffffULL);
|
||||||
|
}
|
||||||
|
inline uint64_t uint128_hi64(const uint128_t& x) {
|
||||||
|
return static_cast<uint64_t>( x >> 64 );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fc
|
||||||
|
|
||||||
|
#endif // __SIZEOF_INT128__
|
||||||
|
|
||||||
|
namespace fc {
|
||||||
|
|
||||||
|
inline uint128_t uint128( const uint64_t hi, const uint64_t lo ) {
|
||||||
|
return ( uint128_t(hi) << 64 ) + lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fc
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
/// This file contains general purpose utilities related to UTF-8 <-> Unicode conversions
|
// This file contains general purpose utilities related to UTF-8 <-> Unicode conversions
|
||||||
|
|
||||||
namespace fc
|
namespace fc
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <new>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(disable: 4482) // nonstandard extension used enum Name::Val, standard in C++11
|
|
||||||
#define NO_RETURN __declspec(noreturn)
|
|
||||||
#else
|
|
||||||
#define NO_RETURN __attribute__((noreturn))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//namespace std {
|
|
||||||
// typedef decltype(sizeof(int)) size_t;
|
|
||||||
// typedef decltype(nullptr) nullptr_t;
|
|
||||||
//}
|
|
||||||
|
|
||||||
namespace fc {
|
|
||||||
using std::size_t;
|
|
||||||
typedef decltype(nullptr) nullptr_t;
|
|
||||||
|
|
||||||
template<typename T> struct deduce { typedef T type; };
|
|
||||||
template<typename T> struct deduce<T&> { typedef T type; };
|
|
||||||
template<typename T> struct deduce<const T&> { typedef T type; };
|
|
||||||
template<typename T> struct deduce<T&&> { typedef T type; };
|
|
||||||
template<typename T> struct deduce<const T&&>{ typedef T type; };
|
|
||||||
|
|
||||||
template<typename T, typename U>
|
|
||||||
inline T&& forward( U&& u ) { return static_cast<T&&>(u); }
|
|
||||||
|
|
||||||
struct true_type { enum _value { value = 1 }; };
|
|
||||||
struct false_type { enum _value { value = 0 }; };
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template<typename T> fc::true_type is_class_helper(void(T::*)());
|
|
||||||
template<typename T> fc::false_type is_class_helper(...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct is_class { typedef decltype(detail::is_class_helper<T>(0)) type; enum value_enum { value = type::value }; };
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
@ -11,7 +13,9 @@
|
||||||
#include <string.h> // memset
|
#include <string.h> // memset
|
||||||
|
|
||||||
#include <fc/optional.hpp>
|
#include <fc/optional.hpp>
|
||||||
|
#include <fc/uint128.hpp>
|
||||||
#include <fc/container/flat_fwd.hpp>
|
#include <fc/container/flat_fwd.hpp>
|
||||||
|
#include <fc/crypto/hex.hpp>
|
||||||
#include <boost/endian/buffers.hpp>
|
#include <boost/endian/buffers.hpp>
|
||||||
#include <boost/multi_index_container_fwd.hpp>
|
#include <boost/multi_index_container_fwd.hpp>
|
||||||
|
|
||||||
|
|
@ -23,7 +27,7 @@ namespace fc
|
||||||
{
|
{
|
||||||
void throw_assertion_failure( const std::string& message );
|
void throw_assertion_failure( const std::string& message );
|
||||||
}
|
}
|
||||||
#define _FC_ASSERT( cond, msg ) { if( !(cond) ) { fc::throw_assertion_failure( #cond ": " msg ); } }
|
#define _FC_ASSERT( cond, msg ) { if( !(cond) ) { char t[] = #cond ": " msg; fc::throw_assertion_failure( t ); } }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace fc
|
namespace fc
|
||||||
|
|
@ -146,9 +150,12 @@ namespace fc
|
||||||
void to_variant( const microseconds& input_microseconds, variant& output_variant, uint32_t max_depth );
|
void to_variant( const microseconds& input_microseconds, variant& output_variant, uint32_t max_depth );
|
||||||
void from_variant( const variant& input_variant, microseconds& output_microseconds, uint32_t max_depth );
|
void from_variant( const variant& input_variant, microseconds& output_microseconds, uint32_t max_depth );
|
||||||
|
|
||||||
#ifdef __APPLE__
|
void to_variant( const uint128_t& var, variant& vo, uint32_t max_depth = 1 );
|
||||||
|
void from_variant( const variant& var, uint128_t& vo, uint32_t max_depth = 1 );
|
||||||
|
|
||||||
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
||||||
void to_variant( size_t s, variant& v, uint32_t max_depth = 1 );
|
void to_variant( size_t s, variant& v, uint32_t max_depth = 1 );
|
||||||
#elif !defined(_MSC_VER)
|
#elif !defined(_WIN32)
|
||||||
void to_variant( long long int s, variant& v, uint32_t max_depth = 1 );
|
void to_variant( long long int s, variant& v, uint32_t max_depth = 1 );
|
||||||
void to_variant( unsigned long long int s, variant& v, uint32_t max_depth = 1 );
|
void to_variant( unsigned long long int s, variant& v, uint32_t max_depth = 1 );
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -207,7 +214,7 @@ namespace fc
|
||||||
/// Constructs a null_type variant
|
/// Constructs a null_type variant
|
||||||
variant();
|
variant();
|
||||||
/// Constructs a null_type variant
|
/// Constructs a null_type variant
|
||||||
variant( nullptr_t, uint32_t max_depth = 1 );
|
variant( std::nullptr_t, uint32_t max_depth = 1 );
|
||||||
|
|
||||||
/// @param str - UTF8 string
|
/// @param str - UTF8 string
|
||||||
variant( const char* str, uint32_t max_depth = 1 );
|
variant( const char* str, uint32_t max_depth = 1 );
|
||||||
|
|
@ -222,7 +229,7 @@ namespace fc
|
||||||
variant( uint32_t val, uint32_t max_depth = 1 );
|
variant( uint32_t val, uint32_t max_depth = 1 );
|
||||||
variant( int32_t val, uint32_t max_depth = 1 );
|
variant( int32_t val, uint32_t max_depth = 1 );
|
||||||
variant( uint64_t val, uint32_t max_depth = 1 );
|
variant( uint64_t val, uint32_t max_depth = 1 );
|
||||||
#ifdef __APPLE__
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
||||||
variant( size_t val, uint32_t max_depth = 1 );
|
variant( size_t val, uint32_t max_depth = 1 );
|
||||||
#endif
|
#endif
|
||||||
variant( int64_t val, uint32_t max_depth = 1 );
|
variant( int64_t val, uint32_t max_depth = 1 );
|
||||||
|
|
@ -345,7 +352,7 @@ namespace fc
|
||||||
template<typename T>
|
template<typename T>
|
||||||
variant& operator=( T&& v )
|
variant& operator=( T&& v )
|
||||||
{
|
{
|
||||||
return *this = variant( fc::forward<T>(v) );
|
return *this = variant( std::forward<T>(v) );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
@ -574,9 +581,7 @@ namespace fc
|
||||||
memset( this, 0, sizeof(*this) );
|
memset( this, 0, sizeof(*this) );
|
||||||
to_variant( val, *this, max_depth );
|
to_variant( val, *this, max_depth );
|
||||||
}
|
}
|
||||||
#ifdef __APPLE__
|
|
||||||
inline void to_variant( size_t s, variant& v, uint32_t max_depth ) { v = variant(uint64_t(s)); }
|
|
||||||
#endif
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void to_variant( const std::shared_ptr<T>& var, variant& vo, uint32_t max_depth )
|
void to_variant( const std::shared_ptr<T>& var, variant& vo, uint32_t max_depth )
|
||||||
{
|
{
|
||||||
|
|
@ -625,7 +630,7 @@ namespace fc
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void to_variant( const safe<T>& s, variant& v, uint32_t max_depth ) {
|
void to_variant( const safe<T>& s, variant& v, uint32_t max_depth ) {
|
||||||
to_variant( s.value, v, max_depth );
|
to_variant( static_cast<T>(s.value), v, max_depth );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
@ -654,6 +659,36 @@ namespace fc
|
||||||
c.insert( item.as<T>( max_depth - 1 ) );
|
c.insert( item.as<T>( max_depth - 1 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
void to_variant( const std::array<char,N>& bi, variant& v, uint32_t max_depth = 1 )
|
||||||
|
{
|
||||||
|
v = variant( to_hex( bi.data(), N ) );
|
||||||
|
}
|
||||||
|
template<size_t N>
|
||||||
|
void from_variant( const variant& v, std::array<char,N>& bi, uint32_t max_depth = 1 )
|
||||||
|
{
|
||||||
|
std::string ve = v.as_string();
|
||||||
|
if( ve.size() )
|
||||||
|
from_hex( ve, bi.data(), std::min<size_t>( ve.size() / 2, bi.size() ) );
|
||||||
|
else
|
||||||
|
memset( bi.data(), 0, bi.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
void to_variant( const std::array<unsigned char,N>& bi, variant& v, uint32_t max_depth = 1 )
|
||||||
|
{
|
||||||
|
v = variant( to_hex( (char*) bi.data(), N ) );
|
||||||
|
}
|
||||||
|
template<size_t N>
|
||||||
|
void from_variant( const variant& v, std::array<unsigned char,N>& bi, uint32_t max_depth = 1 )
|
||||||
|
{
|
||||||
|
std::string ve = v.as_string();
|
||||||
|
if( ve.size() )
|
||||||
|
from_hex( ve, (char*)bi.data(), std::min<size_t>( ve.size() / 2, bi.size() ) );
|
||||||
|
else
|
||||||
|
memset( bi.data(), 0, bi.size() );
|
||||||
|
}
|
||||||
|
|
||||||
variant operator + ( const variant& a, const variant& b );
|
variant operator + ( const variant& a, const variant& b );
|
||||||
variant operator - ( const variant& a, const variant& b );
|
variant operator - ( const variant& a, const variant& b );
|
||||||
variant operator * ( const variant& a, const variant& b );
|
variant operator * ( const variant& a, const variant& b );
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fc/variant.hpp>
|
#include <fc/variant.hpp>
|
||||||
#include <fc/shared_ptr.hpp>
|
#include <memory>
|
||||||
|
|
||||||
namespace fc
|
namespace fc
|
||||||
{
|
{
|
||||||
|
|
@ -70,7 +70,7 @@ namespace fc
|
||||||
variant_object( string key, T&& val )
|
variant_object( string key, T&& val )
|
||||||
:_key_value( std::make_shared<std::vector<entry> >() )
|
:_key_value( std::make_shared<std::vector<entry> >() )
|
||||||
{
|
{
|
||||||
*this = variant_object( std::move(key), variant(forward<T>(val)) );
|
*this = variant_object( std::move(key), variant(std::forward<T>(val)) );
|
||||||
}
|
}
|
||||||
variant_object( const variant_object& );
|
variant_object( const variant_object& );
|
||||||
variant_object( variant_object&& );
|
variant_object( variant_object&& );
|
||||||
|
|
@ -173,7 +173,7 @@ namespace fc
|
||||||
mutable_variant_object& operator()( string key, T&& var, uint32_t max_depth )
|
mutable_variant_object& operator()( string key, T&& var, uint32_t max_depth )
|
||||||
{
|
{
|
||||||
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
|
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
|
||||||
set( std::move(key), variant( fc::forward<T>(var), max_depth - 1 ) );
|
set( std::move(key), variant( std::forward<T>(var), max_depth - 1 ) );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|
@ -191,7 +191,7 @@ namespace fc
|
||||||
explicit mutable_variant_object( T&& v )
|
explicit mutable_variant_object( T&& v )
|
||||||
:_key_value( new std::vector<entry>() )
|
:_key_value( new std::vector<entry>() )
|
||||||
{
|
{
|
||||||
*this = variant(fc::forward<T>(v)).get_object();
|
*this = variant(std::forward<T>(v)).get_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
mutable_variant_object();
|
mutable_variant_object();
|
||||||
|
|
@ -202,7 +202,7 @@ namespace fc
|
||||||
mutable_variant_object( string key, T&& val )
|
mutable_variant_object( string key, T&& val )
|
||||||
:_key_value( new std::vector<entry>() )
|
:_key_value( new std::vector<entry>() )
|
||||||
{
|
{
|
||||||
set( std::move(key), variant(forward<T>(val)) );
|
set( std::move(key), variant(std::forward<T>(val)) );
|
||||||
}
|
}
|
||||||
|
|
||||||
mutable_variant_object( mutable_variant_object&& );
|
mutable_variant_object( mutable_variant_object&& );
|
||||||
|
|
@ -232,7 +232,7 @@ namespace fc
|
||||||
optional<variant> v;
|
optional<variant> v;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
v = variant( fc::forward<T>(var), _max_depth );
|
v = variant( std::forward<T>(var), _max_depth );
|
||||||
}
|
}
|
||||||
catch( ... )
|
catch( ... )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ namespace fc {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
resolver res( fc::asio::default_io_service() );
|
resolver res( fc::asio::default_io_service() );
|
||||||
promise<std::vector<boost::asio::ip::tcp::endpoint> >::ptr p( new promise<std::vector<boost::asio::ip::tcp::endpoint> >("tcp::resolve completion") );
|
promise<std::vector<boost::asio::ip::tcp::endpoint> >::ptr p = promise<std::vector<boost::asio::ip::tcp::endpoint> >::create("tcp::resolve completion");
|
||||||
res.async_resolve( boost::asio::ip::tcp::resolver::query(hostname,port),
|
res.async_resolve( boost::asio::ip::tcp::resolver::query(hostname,port),
|
||||||
boost::bind( detail::resolve_handler<boost::asio::ip::tcp::endpoint,resolver_iterator>, p, _1, _2 ) );
|
boost::bind( detail::resolve_handler<boost::asio::ip::tcp::endpoint,resolver_iterator>, p, _1, _2 ) );
|
||||||
return p->wait();
|
return p->wait();
|
||||||
|
|
@ -204,7 +204,7 @@ namespace fc {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
resolver res( fc::asio::default_io_service() );
|
resolver res( fc::asio::default_io_service() );
|
||||||
promise<std::vector<endpoint> >::ptr p( new promise<std::vector<endpoint> >("udp::resolve completion") );
|
promise<std::vector<endpoint> >::ptr p = promise<std::vector<endpoint> >::create("udp::resolve completion");
|
||||||
res.async_resolve( resolver::query(hostname,port),
|
res.async_resolve( resolver::query(hostname,port),
|
||||||
boost::bind( detail::resolve_handler<endpoint,resolver_iterator>, p, _1, _2 ) );
|
boost::bind( detail::resolve_handler<endpoint,resolver_iterator>, p, _1, _2 ) );
|
||||||
return p->wait();
|
return p->wait();
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@
|
||||||
#include <fc/fwd_impl.hpp>
|
#include <fc/fwd_impl.hpp>
|
||||||
|
|
||||||
#include <fc/io/fstream.hpp>
|
#include <fc/io/fstream.hpp>
|
||||||
#include <fc/io/raw.hpp>
|
|
||||||
|
|
||||||
#include <fc/log/logger.hpp>
|
#include <fc/log/logger.hpp>
|
||||||
|
|
||||||
#include <fc/thread/thread.hpp>
|
#include <fc/thread/thread.hpp>
|
||||||
|
#include <fc/io/raw.hpp>
|
||||||
#include <boost/endian/buffers.hpp>
|
#include <boost/endian/buffers.hpp>
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <openssl/opensslconf.h>
|
#include <openssl/opensslconf.h>
|
||||||
|
|
@ -38,7 +38,7 @@ aes_encoder::~aes_encoder()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void aes_encoder::init( const fc::sha256& key, const fc::uint128& init_value )
|
void aes_encoder::init( const fc::sha256& key, const uint128_t& init_value )
|
||||||
{
|
{
|
||||||
my->ctx.obj = EVP_CIPHER_CTX_new();
|
my->ctx.obj = EVP_CIPHER_CTX_new();
|
||||||
/* Create and initialise the context */
|
/* Create and initialise the context */
|
||||||
|
|
@ -54,8 +54,8 @@ void aes_encoder::init( const fc::sha256& key, const fc::uint128& init_value )
|
||||||
* IV size for *most* modes is the same as the block size. For AES this
|
* IV size for *most* modes is the same as the block size. For AES this
|
||||||
* is 128 bits */
|
* is 128 bits */
|
||||||
boost::endian::little_uint64_buf_t iv[2];
|
boost::endian::little_uint64_buf_t iv[2];
|
||||||
iv[0] = init_value.hi;
|
iv[0] = uint128_hi64( init_value );
|
||||||
iv[1] = init_value.lo;
|
iv[1] = uint128_lo64( init_value );
|
||||||
if(1 != EVP_EncryptInit_ex(my->ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)&key, (const unsigned char*)iv[0].data()))
|
if(1 != EVP_EncryptInit_ex(my->ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)&key, (const unsigned char*)iv[0].data()))
|
||||||
{
|
{
|
||||||
FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc encryption init",
|
FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc encryption init",
|
||||||
|
|
@ -106,7 +106,7 @@ aes_decoder::aes_decoder()
|
||||||
(void)init;
|
(void)init;
|
||||||
}
|
}
|
||||||
|
|
||||||
void aes_decoder::init( const fc::sha256& key, const fc::uint128& init_value )
|
void aes_decoder::init( const fc::sha256& key, const uint128_t& init_value )
|
||||||
{
|
{
|
||||||
my->ctx.obj = EVP_CIPHER_CTX_new();
|
my->ctx.obj = EVP_CIPHER_CTX_new();
|
||||||
/* Create and initialise the context */
|
/* Create and initialise the context */
|
||||||
|
|
@ -122,8 +122,8 @@ void aes_decoder::init( const fc::sha256& key, const fc::uint128& init_value )
|
||||||
* IV size for *most* modes is the same as the block size. For AES this
|
* IV size for *most* modes is the same as the block size. For AES this
|
||||||
* is 128 bits */
|
* is 128 bits */
|
||||||
boost::endian::little_uint64_buf_t iv[2];
|
boost::endian::little_uint64_buf_t iv[2];
|
||||||
iv[0] = init_value.hi;
|
iv[0] = uint128_hi64( init_value );
|
||||||
iv[1] = init_value.lo;
|
iv[1] = uint128_lo64( init_value );
|
||||||
if(1 != EVP_DecryptInit_ex(my->ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)&key, (const unsigned char*)iv[0].data()))
|
if(1 != EVP_DecryptInit_ex(my->ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)&key, (const unsigned char*)iv[0].data()))
|
||||||
{
|
{
|
||||||
FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc encryption init",
|
FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc encryption init",
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
|
|
||||||
|
namespace fc { namespace detail {
|
||||||
|
|
||||||
/** Errors thrown by the bignum class */
|
/** Errors thrown by the bignum class */
|
||||||
class bignum_error : public std::runtime_error
|
class bignum_error : public std::runtime_error
|
||||||
{
|
{
|
||||||
|
|
@ -605,11 +607,10 @@ inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vch
|
||||||
return DecodeBase58(str.c_str(), vchRet);
|
return DecodeBase58(str.c_str(), vchRet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
namespace fc {
|
|
||||||
|
|
||||||
std::string to_base58( const char* d, size_t s ) {
|
std::string to_base58( const char* d, size_t s ) {
|
||||||
return EncodeBase58( (const unsigned char*)d, (const unsigned char*)d+s ).c_str();
|
return fc::detail::EncodeBase58( (const unsigned char*)d, (const unsigned char*)d+s ).c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_base58( const std::vector<char>& d )
|
std::string to_base58( const std::vector<char>& d )
|
||||||
|
|
@ -620,8 +621,9 @@ std::string to_base58( const std::vector<char>& d )
|
||||||
}
|
}
|
||||||
std::vector<char> from_base58( const std::string& base58_str ) {
|
std::vector<char> from_base58( const std::string& base58_str ) {
|
||||||
std::vector<unsigned char> out;
|
std::vector<unsigned char> out;
|
||||||
if( !DecodeBase58( base58_str.c_str(), out ) ) {
|
if( !fc::detail::DecodeBase58( base58_str.c_str(), out ) ) {
|
||||||
FC_THROW_EXCEPTION( parse_error_exception, "Unable to decode base58 string ${base58_str}", ("base58_str",base58_str) );
|
FC_THROW_EXCEPTION( parse_error_exception, "Unable to decode base58 string ${base58_str}",
|
||||||
|
("base58_str",base58_str) );
|
||||||
}
|
}
|
||||||
return std::vector<char>((const char*)out.data(), ((const char*)out.data())+out.size() );
|
return std::vector<char>((const char*)out.data(), ((const char*)out.data())+out.size() );
|
||||||
}
|
}
|
||||||
|
|
@ -629,10 +631,10 @@ std::vector<char> from_base58( const std::string& base58_str ) {
|
||||||
* @return the number of bytes decoded
|
* @return the number of bytes decoded
|
||||||
*/
|
*/
|
||||||
size_t from_base58( const std::string& base58_str, char* out_data, size_t out_data_len ) {
|
size_t from_base58( const std::string& base58_str, char* out_data, size_t out_data_len ) {
|
||||||
//slog( "%s", base58_str.c_str() );
|
|
||||||
std::vector<unsigned char> out;
|
std::vector<unsigned char> out;
|
||||||
if( !DecodeBase58( base58_str.c_str(), out ) ) {
|
if( !fc::detail::DecodeBase58( base58_str.c_str(), out ) ) {
|
||||||
FC_THROW_EXCEPTION( parse_error_exception, "Unable to decode base58 string ${base58_str}", ("base58_str",base58_str) );
|
FC_THROW_EXCEPTION( parse_error_exception, "Unable to decode base58 string ${base58_str}",
|
||||||
|
("base58_str",base58_str) );
|
||||||
}
|
}
|
||||||
FC_ASSERT( out.size() <= out_data_len );
|
FC_ASSERT( out.size() <= out_data_len );
|
||||||
if (!out.empty()) {
|
if (!out.empty()) {
|
||||||
|
|
@ -640,6 +642,7 @@ size_t from_base58( const std::string& base58_str, char* out_data, size_t out_da
|
||||||
}
|
}
|
||||||
return out.size();
|
return out.size();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
} // fc
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -31,34 +31,30 @@
|
||||||
//#include <city.h>
|
//#include <city.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <string.h> // for memcpy and memset
|
#include <string.h> // for memcpy and memset
|
||||||
#include <fc/crypto/city.hpp>
|
#include <fc/crypto/city.hpp>
|
||||||
#include <fc/uint128.hpp>
|
|
||||||
#include <fc/array.hpp>
|
|
||||||
#include <boost/endian/buffers.hpp>
|
#include <boost/endian/buffers.hpp>
|
||||||
|
|
||||||
#if defined(__SSE4_2__) && defined(__x86_64__)
|
#if defined(__SSE4_2__) && defined(__x86_64__)
|
||||||
#include <nmmintrin.h>
|
#include <nmmintrin.h>
|
||||||
|
#define _mm_crc32_u64_impl _mm_crc32_u64
|
||||||
#else
|
#else
|
||||||
uint64_t _mm_crc32_u64(uint64_t a, uint64_t b );
|
uint64_t _mm_crc32_u64_impl(uint64_t a, uint64_t b );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
inline uint64_t Uint128Low64(const uint128& x) { return x.low_bits(); }
|
|
||||||
inline uint64_t Uint128High64(const uint128& x) { return x.high_bits(); }
|
|
||||||
|
|
||||||
// Hash 128 input bits down to 64 bits of output.
|
// Hash 128 input bits down to 64 bits of output.
|
||||||
// This is intended to be a reasonably good hash function.
|
// This is intended to be a reasonably good hash function.
|
||||||
inline uint64_t Hash128to64(const uint128& x) {
|
inline uint64_t Hash128to64(const uint128_t& x) {
|
||||||
// Murmur-inspired hashing.
|
// Murmur-inspired hashing.
|
||||||
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
||||||
uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
|
uint64_t a = (uint128_lo64(x) ^ uint128_hi64(x)) * kMul;
|
||||||
a ^= (a >> 47);
|
a ^= (a >> 47);
|
||||||
uint64_t b = (Uint128High64(x) ^ a) * kMul;
|
uint64_t b = (uint128_hi64(x) ^ a) * kMul;
|
||||||
b ^= (b >> 47);
|
b ^= (b >> 47);
|
||||||
b *= kMul;
|
b *= kMul;
|
||||||
return b;
|
return b;
|
||||||
|
|
@ -280,7 +276,7 @@ static uint64_t ShiftMix(uint64_t val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t HashLen16(uint64_t u, uint64_t v) {
|
static uint64_t HashLen16(uint64_t u, uint64_t v) {
|
||||||
return Hash128to64(uint128(u, v));
|
return Hash128to64( uint128( u, v) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) {
|
static uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) {
|
||||||
|
|
@ -425,9 +421,9 @@ uint64_t CityHash64WithSeed(const char *s, size_t len, uint64_t seed) {
|
||||||
|
|
||||||
// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
|
// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
|
||||||
// of any length representable in signed long. Based on City and Murmur.
|
// of any length representable in signed long. Based on City and Murmur.
|
||||||
static uint128 CityMurmur(const char *s, size_t len, uint128 seed) {
|
uint128_t CityMurmur(const char *s, size_t len, uint128_t seed) {
|
||||||
uint64_t a = Uint128Low64(seed);
|
uint64_t a = uint128_lo64(seed);
|
||||||
uint64_t b = Uint128High64(seed);
|
uint64_t b = uint128_hi64(seed);
|
||||||
uint64_t c = 0;
|
uint64_t c = 0;
|
||||||
uint64_t d = 0;
|
uint64_t d = 0;
|
||||||
signed long l = len - 16;
|
signed long l = len - 16;
|
||||||
|
|
@ -452,10 +448,10 @@ static uint128 CityMurmur(const char *s, size_t len, uint128 seed) {
|
||||||
}
|
}
|
||||||
a = HashLen16(a, c);
|
a = HashLen16(a, c);
|
||||||
b = HashLen16(d, b);
|
b = HashLen16(d, b);
|
||||||
return uint128(a ^ b, HashLen16(b, a));
|
return uint128( a ^ b, HashLen16(b, a) );
|
||||||
}
|
}
|
||||||
|
|
||||||
uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
|
uint128_t CityHash128WithSeed(const char *s, size_t len, uint128_t seed) {
|
||||||
if (len < 128) {
|
if (len < 128) {
|
||||||
return CityMurmur(s, len, seed);
|
return CityMurmur(s, len, seed);
|
||||||
}
|
}
|
||||||
|
|
@ -463,8 +459,8 @@ uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
|
||||||
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
|
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
|
||||||
// v, w, x, y, and z.
|
// v, w, x, y, and z.
|
||||||
pair<uint64_t, uint64_t> v, w;
|
pair<uint64_t, uint64_t> v, w;
|
||||||
uint64_t x = Uint128Low64(seed);
|
uint64_t x = uint128_lo64(seed);
|
||||||
uint64_t y = Uint128High64(seed);
|
uint64_t y = uint128_hi64(seed);
|
||||||
uint64_t z = len * k1;
|
uint64_t z = len * k1;
|
||||||
v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
|
v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
|
||||||
v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
|
v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
|
||||||
|
|
@ -514,15 +510,13 @@ uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
|
||||||
// different 56-byte-to-8-byte hashes to get a 16-byte final result.
|
// different 56-byte-to-8-byte hashes to get a 16-byte final result.
|
||||||
x = HashLen16(x, v.first);
|
x = HashLen16(x, v.first);
|
||||||
y = HashLen16(y + z, w.first);
|
y = HashLen16(y + z, w.first);
|
||||||
return uint128(HashLen16(x + v.second, w.second) + y,
|
return uint128( HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second) );
|
||||||
HashLen16(x + w.second, y + v.second));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint128 city_hash128(const char *s, size_t len) {
|
uint128_t city_hash128(const char *s, size_t len) {
|
||||||
return len >= 16 ?
|
return len >= 16 ?
|
||||||
CityHash128WithSeed(s + 16, len - 16,
|
CityHash128WithSeed( s + 16, len - 16, uint128( Fetch64(s), Fetch64(s + 8) + k0 ) ) :
|
||||||
uint128(Fetch64(s), Fetch64(s + 8) + k0)) :
|
CityHash128WithSeed( s, len, uint128( k0, k1 ) );
|
||||||
CityHash128WithSeed(s, len, uint128(k0, k1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#ifdef __SSE4_2__
|
//#ifdef __SSE4_2__
|
||||||
|
|
@ -563,9 +557,9 @@ static void CityHashCrc256Long(const char *s, size_t len,
|
||||||
g += e; \
|
g += e; \
|
||||||
e += z; \
|
e += z; \
|
||||||
g += x; \
|
g += x; \
|
||||||
z = _mm_crc32_u64(z, b + g); \
|
z = _mm_crc32_u64_impl(z, b + g); \
|
||||||
y = _mm_crc32_u64(y, e + h); \
|
y = _mm_crc32_u64_impl(y, e + h); \
|
||||||
x = _mm_crc32_u64(x, f + a); \
|
x = _mm_crc32_u64_impl(x, f + a); \
|
||||||
e = Rotate(e, r); \
|
e = Rotate(e, r); \
|
||||||
c += e; \
|
c += e; \
|
||||||
s += 40
|
s += 40
|
||||||
|
|
@ -640,26 +634,25 @@ array<uint64_t,4> city_hash_crc_256(const char *s, size_t len)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed) {
|
uint128_t CityHashCrc128WithSeed(const char *s, size_t len, uint128_t seed) {
|
||||||
if (len <= 900) {
|
if (len <= 900) {
|
||||||
return CityHash128WithSeed(s, len, seed);
|
return CityHash128WithSeed(s, len, seed);
|
||||||
} else {
|
} else {
|
||||||
uint64_t result[4];
|
uint64_t result[4];
|
||||||
CityHashCrc256(s, len, result);
|
CityHashCrc256(s, len, result);
|
||||||
uint64_t u = Uint128High64(seed) + result[0];
|
uint64_t u = uint128_hi64(seed) + result[0];
|
||||||
uint64_t v = Uint128Low64(seed) + result[1];
|
uint64_t v = uint128_lo64(seed) + result[1];
|
||||||
return uint128(HashLen16(u, v + result[2]),
|
return uint128( HashLen16(u, v + result[2]), HashLen16(Rotate(v, 32), u * k0 + result[3]) );
|
||||||
HashLen16(Rotate(v, 32), u * k0 + result[3]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint128 city_hash_crc_128(const char *s, size_t len) {
|
uint128_t city_hash_crc_128(const char *s, size_t len) {
|
||||||
if (len <= 900) {
|
if (len <= 900) {
|
||||||
return city_hash128(s, len);
|
return city_hash128(s, len);
|
||||||
} else {
|
} else {
|
||||||
uint64_t result[4];
|
uint64_t result[4];
|
||||||
CityHashCrc256(s, len, result);
|
CityHashCrc256(s, len, result);
|
||||||
return uint128(result[2], result[3]);
|
return uint128( result[2], result[3] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -604,7 +604,7 @@ static const uint32_t crc_c[256] = {
|
||||||
#if !defined __SSE4_2__ || (defined __SSE4_2__ && !defined __x86_64__)
|
#if !defined __SSE4_2__ || (defined __SSE4_2__ && !defined __x86_64__)
|
||||||
|
|
||||||
|
|
||||||
uint64_t _mm_crc32_u64(uint64_t a, uint64_t b )
|
uint64_t _mm_crc32_u64_impl(uint64_t a, uint64_t b )
|
||||||
{
|
{
|
||||||
// Squelch warning about unusued variable crc_c
|
// Squelch warning about unusued variable crc_c
|
||||||
(void)(crc_c);
|
(void)(crc_c);
|
||||||
|
|
@ -619,7 +619,7 @@ int main( int argc, char** argv )
|
||||||
{
|
{
|
||||||
uint64_t f = 0x1234;
|
uint64_t f = 0x1234;
|
||||||
uint64_t a = 0x5678;
|
uint64_t a = 0x5678;
|
||||||
uint32_t f1 = _mm_crc32_u64(f, a);
|
uint32_t f1 = _mm_crc32_u64_impl(f, a);
|
||||||
uint32_t f4 = crc32cSlicingBy8(f, (unsigned char*)&a, sizeof(a));
|
uint32_t f4 = crc32cSlicingBy8(f, (unsigned char*)&a, sizeof(a));
|
||||||
std::cout<<std::hex<<f1<<"\n"<<f2<<"\n"<<f3<<"\n"<<f4<<"\n";
|
std::cout<<std::hex<<f1<<"\n"<<f2<<"\n"<<f3<<"\n"<<f4<<"\n";
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
#include <fc/crypto/dh.hpp>
|
#include <fc/crypto/dh.hpp>
|
||||||
#include <openssl/dh.h>
|
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
SSL_TYPE(ssl_dh, DH, DH_free)
|
|
||||||
|
|
||||||
static bool validate( const ssl_dh& dh, bool& valid ) {
|
static bool validate( const ssl_dh& dh, bool& valid ) {
|
||||||
int check;
|
int check;
|
||||||
DH_check(dh,&check);
|
DH_check(dh,&check);
|
||||||
|
|
@ -36,7 +33,7 @@ namespace fc {
|
||||||
{
|
{
|
||||||
if( !p.size() )
|
if( !p.size() )
|
||||||
return valid = false;
|
return valid = false;
|
||||||
ssl_dh dh = DH_new();
|
ssl_dh dh(DH_new());
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||||
const auto bn_p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL );
|
const auto bn_p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL );
|
||||||
const auto bn_g = BN_bin2bn( (unsigned char*)&g, 1, NULL );
|
const auto bn_g = BN_bin2bn( (unsigned char*)&g, 1, NULL );
|
||||||
|
|
@ -52,7 +49,7 @@ namespace fc {
|
||||||
{
|
{
|
||||||
if( !p.size() )
|
if( !p.size() )
|
||||||
return valid = false;
|
return valid = false;
|
||||||
ssl_dh dh = DH_new();
|
ssl_dh dh(DH_new());
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||||
const auto bn_p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL );
|
const auto bn_p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL );
|
||||||
const auto bn_g = BN_bin2bn( (unsigned char*)&g, 1, NULL );
|
const auto bn_g = BN_bin2bn( (unsigned char*)&g, 1, NULL );
|
||||||
|
|
@ -90,7 +87,7 @@ namespace fc {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool diffie_hellman::compute_shared_key( const char* buf, uint32_t s ) {
|
bool diffie_hellman::compute_shared_key( const char* buf, uint32_t s ) {
|
||||||
ssl_dh dh = DH_new();
|
ssl_dh dh(DH_new());
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||||
auto bn_p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL );
|
auto bn_p = BN_bin2bn( (unsigned char*)&p.front(), p.size(), NULL );
|
||||||
auto bn_pub_key = BN_bin2bn( (unsigned char*)&pub_key.front(), pub_key.size(), NULL );
|
auto bn_pub_key = BN_bin2bn( (unsigned char*)&pub_key.front(), pub_key.size(), NULL );
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <malloc.h>
|
# include <malloc.h>
|
||||||
#else
|
|
||||||
# include <alloca.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* stuff common to all ecc implementations */
|
/* stuff common to all ecc implementations */
|
||||||
|
|
@ -19,7 +17,7 @@
|
||||||
namespace fc { namespace ecc {
|
namespace fc { namespace ecc {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
typedef fc::array<char,37> chr37;
|
typedef zero_initialized_array<unsigned char,37> chr37;
|
||||||
|
|
||||||
fc::sha256 _left( const fc::sha512& v )
|
fc::sha256 _left( const fc::sha512& v )
|
||||||
{
|
{
|
||||||
|
|
@ -52,10 +50,10 @@ namespace fc { namespace ecc {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static chr37 _derive_message( char first, const char* key32, int i )
|
static chr37 _derive_message( unsigned char first, const unsigned char* key32, int i )
|
||||||
{
|
{
|
||||||
chr37 result;
|
chr37 result;
|
||||||
unsigned char* dest = (unsigned char*) result.begin();
|
unsigned char* dest = result.data();
|
||||||
*dest++ = first;
|
*dest++ = first;
|
||||||
memcpy( dest, key32, 32 ); dest += 32;
|
memcpy( dest, key32, 32 ); dest += 32;
|
||||||
_put( &dest, i );
|
_put( &dest, i );
|
||||||
|
|
@ -64,12 +62,12 @@ namespace fc { namespace ecc {
|
||||||
|
|
||||||
chr37 _derive_message( const public_key_data& key, int i )
|
chr37 _derive_message( const public_key_data& key, int i )
|
||||||
{
|
{
|
||||||
return _derive_message( *key.begin(), key.begin() + 1, i );
|
return _derive_message( *key.data(), key.data() + 1, i );
|
||||||
}
|
}
|
||||||
|
|
||||||
static chr37 _derive_message( const private_key_secret& key, int i )
|
static chr37 _derive_message( const private_key_secret& key, int i )
|
||||||
{
|
{
|
||||||
return _derive_message( 0, key.data(), i );
|
return _derive_message( 0, (unsigned char*) key.data(), i );
|
||||||
}
|
}
|
||||||
|
|
||||||
const ec_group& get_curve()
|
const ec_group& get_curve()
|
||||||
|
|
@ -139,40 +137,40 @@ namespace fc { namespace ecc {
|
||||||
|
|
||||||
std::string public_key::to_base58( const public_key_data &key )
|
std::string public_key::to_base58( const public_key_data &key )
|
||||||
{
|
{
|
||||||
sha256 check = sha256::hash(key.data, sizeof(key));
|
sha256 check = sha256::hash((char*) key.data(), sizeof(key));
|
||||||
static_assert(sizeof(key) + 4 == 37, "Elliptic public key size (or its hash) is incorrect");
|
static_assert(sizeof(key) + 4 == 37, "Elliptic public key size (or its hash) is incorrect");
|
||||||
array<char, 37> data;
|
detail::chr37 data;
|
||||||
memcpy(data.data, key.begin(), key.size());
|
memcpy(data.data(), key.data(), key.size());
|
||||||
memcpy(data.begin() + key.size(), (const char*)check._hash, 4);
|
memcpy(data.data() + key.size(), (const char*)check._hash, 4);
|
||||||
return fc::to_base58(data.begin(), data.size());
|
return fc::to_base58((char*) data.data(), data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public_key public_key::from_base58( const std::string& b58 )
|
public_key public_key::from_base58( const std::string& b58 )
|
||||||
{
|
{
|
||||||
array<char, 37> data;
|
detail::chr37 data;
|
||||||
size_t s = fc::from_base58(b58, (char*)&data, sizeof(data) );
|
size_t s = fc::from_base58(b58, (char*)&data, sizeof(data) );
|
||||||
FC_ASSERT( s == sizeof(data) );
|
FC_ASSERT( s == sizeof(data) );
|
||||||
|
|
||||||
public_key_data key;
|
public_key_data key;
|
||||||
sha256 check = sha256::hash(data.data, sizeof(key));
|
sha256 check = sha256::hash((char*) data.data(), sizeof(key));
|
||||||
FC_ASSERT( memcmp( (char*)check._hash, data.data + sizeof(key), 4 ) == 0 );
|
FC_ASSERT( memcmp( (char*)check._hash, data.data() + key.size(), 4 ) == 0 );
|
||||||
memcpy( (char*)key.data, data.data, sizeof(key) );
|
memcpy( (char*)key.data(), data.data(), key.size() );
|
||||||
return from_key_data(key);
|
return from_key_data(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int public_key::fingerprint() const
|
unsigned int public_key::fingerprint() const
|
||||||
{
|
{
|
||||||
public_key_data key = serialize();
|
public_key_data key = serialize();
|
||||||
ripemd160 hash = ripemd160::hash( sha256::hash( key.begin(), key.size() ) );
|
ripemd160 hash = ripemd160::hash( sha256::hash( (char*) key.data(), key.size() ) );
|
||||||
unsigned char* fp = (unsigned char*) hash._hash;
|
unsigned char* fp = (unsigned char*) hash._hash;
|
||||||
return (fp[0] << 24) | (fp[1] << 16) | (fp[2] << 8) | fp[3];
|
return (fp[0] << 24) | (fp[1] << 16) | (fp[2] << 8) | fp[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool public_key::is_canonical( const compact_signature& c ) {
|
bool public_key::is_canonical( const compact_signature& c ) {
|
||||||
return !(c.data[1] & 0x80)
|
return !(c[1] & 0x80)
|
||||||
&& !(c.data[1] == 0 && !(c.data[2] & 0x80))
|
&& !(c[1] == 0 && !(c[2] & 0x80))
|
||||||
&& !(c.data[33] & 0x80)
|
&& !(c[33] & 0x80)
|
||||||
&& !(c.data[33] == 0 && !(c.data[34] & 0x80));
|
&& !(c[33] == 0 && !(c[34] & 0x80));
|
||||||
}
|
}
|
||||||
|
|
||||||
private_key private_key::generate_from_seed( const fc::sha256& seed, const fc::sha256& offset )
|
private_key private_key::generate_from_seed( const fc::sha256& seed, const fc::sha256& offset )
|
||||||
|
|
@ -231,12 +229,11 @@ namespace fc { namespace ecc {
|
||||||
|
|
||||||
static std::string _to_base58( const extended_key_data& key )
|
static std::string _to_base58( const extended_key_data& key )
|
||||||
{
|
{
|
||||||
size_t buf_len = key.size() + 4;
|
char buffer[std::tuple_size<extended_key_data>::value + 4]; // it's a small static array => allocate on stack
|
||||||
char *buffer = (char*)alloca(buf_len);
|
memcpy( buffer, key.data(), key.size() );
|
||||||
memcpy( buffer, key.begin(), key.size() );
|
fc::sha256 double_hash = fc::sha256::hash( fc::sha256::hash( (char*)key.data(), key.size() ));
|
||||||
fc::sha256 double_hash = fc::sha256::hash( fc::sha256::hash( key.begin(), key.size() ));
|
|
||||||
memcpy( buffer + key.size(), double_hash.data(), 4 );
|
memcpy( buffer + key.size(), double_hash.data(), 4 );
|
||||||
return fc::to_base58( buffer, buf_len );
|
return fc::to_base58( buffer, sizeof(buffer) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _parse_extended_data( unsigned char* buffer, std::string base58 )
|
static void _parse_extended_data( unsigned char* buffer, std::string base58 )
|
||||||
|
|
@ -260,14 +257,14 @@ namespace fc { namespace ecc {
|
||||||
extended_key_data extended_public_key::serialize_extended() const
|
extended_key_data extended_public_key::serialize_extended() const
|
||||||
{
|
{
|
||||||
extended_key_data result;
|
extended_key_data result;
|
||||||
unsigned char* dest = (unsigned char*) result.begin();
|
unsigned char* dest = (unsigned char*) result.data();
|
||||||
detail::_put( &dest, BTC_EXT_PUB_MAGIC );
|
detail::_put( &dest, BTC_EXT_PUB_MAGIC );
|
||||||
*dest++ = depth;
|
*dest++ = depth;
|
||||||
detail::_put( &dest, parent_fp );
|
detail::_put( &dest, parent_fp );
|
||||||
detail::_put( &dest, child_num );
|
detail::_put( &dest, child_num );
|
||||||
memcpy( dest, c.data(), c.data_size() ); dest += 32;
|
memcpy( dest, c.data(), c.data_size() ); dest += 32;
|
||||||
public_key_data key = serialize();
|
public_key_data key = serialize();
|
||||||
memcpy( dest, key.begin(), key.size() );
|
memcpy( dest, key.data(), key.size() );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,7 +290,7 @@ namespace fc { namespace ecc {
|
||||||
fc::sha256 chain;
|
fc::sha256 chain;
|
||||||
memcpy( chain.data(), ptr, chain.data_size() ); ptr += chain.data_size();
|
memcpy( chain.data(), ptr, chain.data_size() ); ptr += chain.data_size();
|
||||||
public_key_data key;
|
public_key_data key;
|
||||||
memcpy( key.begin(), ptr, key.size() );
|
memcpy( key.data(), ptr, key.size() );
|
||||||
return extended_public_key( key, chain, cn, fp, d );
|
return extended_public_key( key, chain, cn, fp, d );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -311,7 +308,7 @@ namespace fc { namespace ecc {
|
||||||
{
|
{
|
||||||
const detail::chr37 data = detail::_derive_message( get_public_key().serialize(), i );
|
const detail::chr37 data = detail::_derive_message( get_public_key().serialize(), i );
|
||||||
hmac_sha512 mac;
|
hmac_sha512 mac;
|
||||||
fc::sha512 l = mac.digest( c.data(), c.data_size(), data.begin(), data.size() );
|
fc::sha512 l = mac.digest( c.data(), c.data_size(), (char*) data.data(), data.size() );
|
||||||
return private_derive_rest( l, i );
|
return private_derive_rest( l, i );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,14 +317,14 @@ namespace fc { namespace ecc {
|
||||||
hmac_sha512 mac;
|
hmac_sha512 mac;
|
||||||
private_key_secret key = get_secret();
|
private_key_secret key = get_secret();
|
||||||
const detail::chr37 data = detail::_derive_message( key, i );
|
const detail::chr37 data = detail::_derive_message( key, i );
|
||||||
fc::sha512 l = mac.digest( c.data(), c.data_size(), data.begin(), data.size() );
|
fc::sha512 l = mac.digest( c.data(), c.data_size(), (char*) data.data(), data.size() );
|
||||||
return private_derive_rest( l, i );
|
return private_derive_rest( l, i );
|
||||||
}
|
}
|
||||||
|
|
||||||
extended_key_data extended_private_key::serialize_extended() const
|
extended_key_data extended_private_key::serialize_extended() const
|
||||||
{
|
{
|
||||||
extended_key_data result;
|
extended_key_data result;
|
||||||
unsigned char* dest = (unsigned char*) result.begin();
|
unsigned char* dest = (unsigned char*) result.data();
|
||||||
detail::_put( &dest, BTC_EXT_PRIV_MAGIC );
|
detail::_put( &dest, BTC_EXT_PRIV_MAGIC );
|
||||||
*dest++ = depth;
|
*dest++ = depth;
|
||||||
detail::_put( &dest, parent_fp );
|
detail::_put( &dest, parent_fp );
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,8 @@ namespace fc { namespace ecc {
|
||||||
FC_ASSERT( my->_key != empty_priv );
|
FC_ASSERT( my->_key != empty_priv );
|
||||||
public_key_data pub;
|
public_key_data pub;
|
||||||
unsigned int pk_len;
|
unsigned int pk_len;
|
||||||
FC_ASSERT( secp256k1_ec_pubkey_create( detail::_get_context(), (unsigned char*) pub.begin(), (int*) &pk_len, (unsigned char*) my->_key.data(), 1 ) );
|
FC_ASSERT( secp256k1_ec_pubkey_create( detail::_get_context(), pub.data(), (int*) &pk_len,
|
||||||
|
(unsigned char*) my->_key.data(), 1 ) );
|
||||||
FC_ASSERT( pk_len == pub.size() );
|
FC_ASSERT( pk_len == pub.size() );
|
||||||
return public_key(pub);
|
return public_key(pub);
|
||||||
}
|
}
|
||||||
|
|
@ -93,9 +94,11 @@ namespace fc { namespace ecc {
|
||||||
unsigned int counter = 0;
|
unsigned int counter = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
FC_ASSERT( secp256k1_ecdsa_sign_compact( detail::_get_context(), (unsigned char*) digest.data(), (unsigned char*) result.begin() + 1, (unsigned char*) my->_key.data(), extended_nonce_function, &counter, &recid ));
|
FC_ASSERT( secp256k1_ecdsa_sign_compact( detail::_get_context(), (unsigned char*) digest.data(),
|
||||||
|
result.data() + 1, (unsigned char*) my->_key.data(),
|
||||||
|
extended_nonce_function, &counter, &recid ));
|
||||||
} while( require_canonical && !public_key::is_canonical( result ) );
|
} while( require_canonical && !public_key::is_canonical( result ) );
|
||||||
result.begin()[0] = 27 + 4 + recid;
|
result.data()[0] = 27 + 4 + recid;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
# include <malloc.h>
|
# include <malloc.h>
|
||||||
#else
|
|
||||||
# include <alloca.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "_elliptic_impl_priv.hpp"
|
#include "_elliptic_impl_priv.hpp"
|
||||||
|
|
@ -41,6 +39,7 @@ namespace fc { namespace ecc {
|
||||||
public_key_impl() BOOST_NOEXCEPT
|
public_key_impl() BOOST_NOEXCEPT
|
||||||
{
|
{
|
||||||
_init_lib();
|
_init_lib();
|
||||||
|
memset( _key.data(), 0, _key.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public_key_impl( const public_key_impl& cpy ) BOOST_NOEXCEPT
|
public_key_impl( const public_key_impl& cpy ) BOOST_NOEXCEPT
|
||||||
|
|
@ -52,16 +51,16 @@ namespace fc { namespace ecc {
|
||||||
public_key_data _key;
|
public_key_data _key;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef fc::array<char,37> chr37;
|
typedef zero_initialized_array<unsigned char,37> chr37;
|
||||||
chr37 _derive_message( const public_key_data& key, int i );
|
chr37 _derive_message( const public_key_data& key, int i );
|
||||||
fc::sha256 _left( const fc::sha512& v );
|
fc::sha256 _left( const fc::sha512& v );
|
||||||
fc::sha256 _right( const fc::sha512& v );
|
fc::sha256 _right( const fc::sha512& v );
|
||||||
const ec_group& get_curve();
|
const ec_group& get_curve();
|
||||||
const private_key_secret& get_curve_order();
|
const private_key_secret& get_curve_order();
|
||||||
const private_key_secret& get_half_curve_order();
|
const private_key_secret& get_half_curve_order();
|
||||||
}
|
} // detail
|
||||||
|
|
||||||
static const public_key_data empty_pub;
|
static const public_key_data empty_pub = detail::public_key_impl()._key;
|
||||||
static const private_key_secret empty_priv;
|
static const private_key_secret empty_priv;
|
||||||
|
|
||||||
fc::sha512 private_key::get_shared_secret( const public_key& other )const
|
fc::sha512 private_key::get_shared_secret( const public_key& other )const
|
||||||
|
|
@ -69,8 +68,9 @@ namespace fc { namespace ecc {
|
||||||
FC_ASSERT( my->_key != empty_priv );
|
FC_ASSERT( my->_key != empty_priv );
|
||||||
FC_ASSERT( other.my->_key != empty_pub );
|
FC_ASSERT( other.my->_key != empty_pub );
|
||||||
public_key_data pub(other.my->_key);
|
public_key_data pub(other.my->_key);
|
||||||
FC_ASSERT( secp256k1_ec_pubkey_tweak_mul( detail::_get_context(), (unsigned char*) pub.begin(), pub.size(), (unsigned char*) my->_key.data() ) );
|
FC_ASSERT( secp256k1_ec_pubkey_tweak_mul( detail::_get_context(), pub.data(), pub.size(),
|
||||||
return fc::sha512::hash( pub.begin() + 1, pub.size() - 1 );
|
(unsigned char*) my->_key.data() ) );
|
||||||
|
return fc::sha512::hash( (char*) pub.data() + 1, pub.size() - 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -103,8 +103,9 @@ namespace fc { namespace ecc {
|
||||||
{
|
{
|
||||||
FC_ASSERT( my->_key != empty_pub );
|
FC_ASSERT( my->_key != empty_pub );
|
||||||
public_key_data new_key;
|
public_key_data new_key;
|
||||||
memcpy( new_key.begin(), my->_key.begin(), new_key.size() );
|
memcpy( new_key.data(), my->_key.data(), new_key.size() );
|
||||||
FC_ASSERT( secp256k1_ec_pubkey_tweak_add( detail::_get_context(), (unsigned char*) new_key.begin(), new_key.size(), (unsigned char*) digest.data() ) );
|
FC_ASSERT( secp256k1_ec_pubkey_tweak_add( detail::_get_context(), new_key.data(), new_key.size(),
|
||||||
|
(unsigned char*) digest.data() ) );
|
||||||
return public_key( new_key );
|
return public_key( new_key );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,23 +126,23 @@ namespace fc { namespace ecc {
|
||||||
FC_ASSERT( my->_key != empty_pub );
|
FC_ASSERT( my->_key != empty_pub );
|
||||||
public_key_point_data dat;
|
public_key_point_data dat;
|
||||||
unsigned int pk_len = my->_key.size();
|
unsigned int pk_len = my->_key.size();
|
||||||
memcpy( dat.begin(), my->_key.begin(), pk_len );
|
memcpy( dat.data(), my->_key.data(), pk_len );
|
||||||
FC_ASSERT( secp256k1_ec_pubkey_decompress( detail::_get_context(), (unsigned char *) dat.begin(), (int*) &pk_len ) );
|
FC_ASSERT( secp256k1_ec_pubkey_decompress( detail::_get_context(), dat.data(), (int*) &pk_len ) );
|
||||||
FC_ASSERT( pk_len == dat.size() );
|
FC_ASSERT( pk_len == dat.size() );
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public_key::public_key( const public_key_point_data& dat )
|
public_key::public_key( const public_key_point_data& dat )
|
||||||
{
|
{
|
||||||
const char* front = &dat.data[0];
|
const unsigned char* front = dat.data();
|
||||||
if( *front == 0 ){}
|
if( *front == 0 ){}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EC_KEY *key = EC_KEY_new_by_curve_name( NID_secp256k1 );
|
EC_KEY *key = EC_KEY_new_by_curve_name( NID_secp256k1 );
|
||||||
key = o2i_ECPublicKey( &key, (const unsigned char**)&front, sizeof(dat) );
|
key = o2i_ECPublicKey( &key, &front, sizeof(dat) );
|
||||||
FC_ASSERT( key );
|
FC_ASSERT( key );
|
||||||
EC_KEY_set_conv_form( key, POINT_CONVERSION_COMPRESSED );
|
EC_KEY_set_conv_form( key, POINT_CONVERSION_COMPRESSED );
|
||||||
unsigned char* buffer = (unsigned char*) my->_key.begin();
|
unsigned char* buffer = my->_key.data();
|
||||||
i2o_ECPublicKey( key, &buffer ); // FIXME: questionable memory handling
|
i2o_ECPublicKey( key, &buffer ); // FIXME: questionable memory handling
|
||||||
EC_KEY_free( key );
|
EC_KEY_free( key );
|
||||||
}
|
}
|
||||||
|
|
@ -154,7 +155,7 @@ namespace fc { namespace ecc {
|
||||||
|
|
||||||
public_key::public_key( const compact_signature& c, const fc::sha256& digest, bool check_canonical )
|
public_key::public_key( const compact_signature& c, const fc::sha256& digest, bool check_canonical )
|
||||||
{
|
{
|
||||||
int nV = c.data[0];
|
int nV = c[0];
|
||||||
if (nV<27 || nV>=35)
|
if (nV<27 || nV>=35)
|
||||||
FC_THROW_EXCEPTION( exception, "unable to reconstruct public key from signature" );
|
FC_THROW_EXCEPTION( exception, "unable to reconstruct public key from signature" );
|
||||||
|
|
||||||
|
|
@ -164,7 +165,9 @@ namespace fc { namespace ecc {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int pk_len;
|
unsigned int pk_len;
|
||||||
FC_ASSERT( secp256k1_ecdsa_recover_compact( detail::_get_context(), (unsigned char*) digest.data(), (unsigned char*) c.begin() + 1, (unsigned char*) my->_key.begin(), (int*) &pk_len, 1, (*c.begin() - 27) & 3 ) );
|
FC_ASSERT( secp256k1_ecdsa_recover_compact( detail::_get_context(), (unsigned char*) digest.data(),
|
||||||
|
c.data() + 1, my->_key.data(), (int*) &pk_len, 1,
|
||||||
|
(*c.data() - 27) & 3 ) );
|
||||||
FC_ASSERT( pk_len == my->_key.size() );
|
FC_ASSERT( pk_len == my->_key.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,10 +180,11 @@ namespace fc { namespace ecc {
|
||||||
hmac_sha512 mac;
|
hmac_sha512 mac;
|
||||||
public_key_data key = serialize();
|
public_key_data key = serialize();
|
||||||
const detail::chr37 data = detail::_derive_message( key, i );
|
const detail::chr37 data = detail::_derive_message( key, i );
|
||||||
fc::sha512 l = mac.digest( c.data(), c.data_size(), data.begin(), data.size() );
|
fc::sha512 l = mac.digest( c.data(), c.data_size(), (const char*) data.data(), data.size() );
|
||||||
fc::sha256 left = detail::_left(l);
|
fc::sha256 left = detail::_left(l);
|
||||||
FC_ASSERT( left < detail::get_curve_order() );
|
FC_ASSERT( left < detail::get_curve_order() );
|
||||||
FC_ASSERT( secp256k1_ec_pubkey_tweak_add( detail::_get_context(), (unsigned char*) key.begin(), key.size(), (unsigned char*) left.data() ) > 0 );
|
FC_ASSERT( secp256k1_ec_pubkey_tweak_add( detail::_get_context(), key.data(), key.size(),
|
||||||
|
(unsigned char*) left.data() ) > 0 );
|
||||||
// FIXME: check validity - if left + key == infinity then invalid
|
// FIXME: check validity - if left + key == infinity then invalid
|
||||||
extended_public_key result( key, detail::_right(l), i, fingerprint(), depth + 1 );
|
extended_public_key result( key, detail::_right(l), i, fingerprint(), depth + 1 );
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -204,7 +208,7 @@ namespace fc { namespace ecc {
|
||||||
commitment_type blind( const blind_factor_type& blind, uint64_t value )
|
commitment_type blind( const blind_factor_type& blind, uint64_t value )
|
||||||
{
|
{
|
||||||
commitment_type result;
|
commitment_type result;
|
||||||
FC_ASSERT( secp256k1_pedersen_commit( detail::_get_context(), (unsigned char*)&result, (unsigned char*)&blind, value ) );
|
FC_ASSERT( secp256k1_pedersen_commit( detail::_get_context(), result.data(), (unsigned char*) blind.data(), value ) );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,8 +216,8 @@ namespace fc { namespace ecc {
|
||||||
{
|
{
|
||||||
blind_factor_type result;
|
blind_factor_type result;
|
||||||
std::vector<const unsigned char*> blinds(blinds_in.size());
|
std::vector<const unsigned char*> blinds(blinds_in.size());
|
||||||
for( uint32_t i = 0; i < blinds_in.size(); ++i ) blinds[i] = (const unsigned char*)&blinds_in[i];
|
for( uint32_t i = 0; i < blinds_in.size(); ++i ) blinds[i] = (unsigned char*) blinds_in[i].data();
|
||||||
FC_ASSERT( secp256k1_pedersen_blind_sum( detail::_get_context(), (unsigned char*)&result, blinds.data(), blinds_in.size(), non_neg ) );
|
FC_ASSERT( secp256k1_pedersen_blind_sum( detail::_get_context(), (unsigned char*) result.data(), blinds.data(), blinds_in.size(), non_neg ) );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,16 +225,16 @@ namespace fc { namespace ecc {
|
||||||
bool verify_sum( const std::vector<commitment_type>& commits_in, const std::vector<commitment_type>& neg_commits_in, int64_t excess )
|
bool verify_sum( const std::vector<commitment_type>& commits_in, const std::vector<commitment_type>& neg_commits_in, int64_t excess )
|
||||||
{
|
{
|
||||||
std::vector<const unsigned char*> commits(commits_in.size());
|
std::vector<const unsigned char*> commits(commits_in.size());
|
||||||
for( uint32_t i = 0; i < commits_in.size(); ++i ) commits[i] = (const unsigned char*)&commits_in[i];
|
for( uint32_t i = 0; i < commits_in.size(); ++i ) commits[i] = commits_in[i].data();
|
||||||
std::vector<const unsigned char*> neg_commits(neg_commits_in.size());
|
std::vector<const unsigned char*> neg_commits(neg_commits_in.size());
|
||||||
for( uint32_t i = 0; i < neg_commits_in.size(); ++i ) neg_commits[i] = (const unsigned char*)&neg_commits_in[i];
|
for( uint32_t i = 0; i < neg_commits_in.size(); ++i ) neg_commits[i] = neg_commits_in[i].data();
|
||||||
|
|
||||||
return secp256k1_pedersen_verify_tally( detail::_get_context(), commits.data(), commits.size(), neg_commits.data(), neg_commits.size(), excess );
|
return secp256k1_pedersen_verify_tally( detail::_get_context(), commits.data(), commits.size(), neg_commits.data(), neg_commits.size(), excess );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verify_range( uint64_t& min_val, uint64_t& max_val, const commitment_type& commit, const std::vector<char>& proof )
|
bool verify_range( uint64_t& min_val, uint64_t& max_val, const commitment_type& commit, const std::vector<char>& proof )
|
||||||
{
|
{
|
||||||
return secp256k1_rangeproof_verify( detail::_get_context(), &min_val, &max_val, (const unsigned char*)&commit, (const unsigned char*)proof.data(), proof.size() );
|
return secp256k1_rangeproof_verify( detail::_get_context(), &min_val, &max_val, commit.data(), (const unsigned char*)proof.data(), proof.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> range_proof_sign( uint64_t min_value,
|
std::vector<char> range_proof_sign( uint64_t min_value,
|
||||||
|
|
@ -245,12 +249,12 @@ namespace fc { namespace ecc {
|
||||||
int proof_len = 5134;
|
int proof_len = 5134;
|
||||||
std::vector<char> proof(proof_len);
|
std::vector<char> proof(proof_len);
|
||||||
|
|
||||||
FC_ASSERT( secp256k1_rangeproof_sign( detail::_get_context(),
|
FC_ASSERT( secp256k1_rangeproof_sign( detail::_get_context(),
|
||||||
(unsigned char*)proof.data(),
|
(unsigned char*)proof.data(),
|
||||||
&proof_len, min_value,
|
&proof_len, min_value,
|
||||||
(const unsigned char*)&commit,
|
commit.data(),
|
||||||
(const unsigned char*)&commit_blind,
|
(unsigned char*) commit_blind.data(),
|
||||||
(const unsigned char*)&nonce,
|
(unsigned char*) nonce.data(),
|
||||||
base10_exp, min_bits, actual_value ) );
|
base10_exp, min_bits, actual_value ) );
|
||||||
proof.resize(proof_len);
|
proof.resize(proof_len);
|
||||||
return proof;
|
return proof;
|
||||||
|
|
@ -269,14 +273,14 @@ namespace fc { namespace ecc {
|
||||||
char msg[4096];
|
char msg[4096];
|
||||||
int mlen = 0;
|
int mlen = 0;
|
||||||
FC_ASSERT( secp256k1_rangeproof_rewind( detail::_get_context(),
|
FC_ASSERT( secp256k1_rangeproof_rewind( detail::_get_context(),
|
||||||
(unsigned char*)&blind_out,
|
(unsigned char*) blind_out.data(),
|
||||||
&value_out,
|
&value_out,
|
||||||
(unsigned char*)msg,
|
(unsigned char*) msg,
|
||||||
&mlen,
|
&mlen,
|
||||||
(const unsigned char*)&nonce,
|
(unsigned char*) nonce.data(),
|
||||||
&min_val,
|
&min_val,
|
||||||
&max_val,
|
&max_val,
|
||||||
(const unsigned char*)&commit,
|
commit.data(),
|
||||||
(const unsigned char*)proof.data(),
|
(const unsigned char*)proof.data(),
|
||||||
proof.size() ) );
|
proof.size() ) );
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,11 @@ namespace fc
|
||||||
|
|
||||||
~openssl_scope()
|
~openssl_scope()
|
||||||
{
|
{
|
||||||
|
#if not defined(LIBRESSL_VERSION_NUMBER)
|
||||||
|
// No FIPS in LibreSSL.
|
||||||
|
// https://marc.info/?l=openbsd-misc&m=139819485423701&w=2
|
||||||
FIPS_mode_set(0);
|
FIPS_mode_set(0);
|
||||||
|
#endif
|
||||||
CONF_modules_unload(1);
|
CONF_modules_unload(1);
|
||||||
EVP_cleanup();
|
EVP_cleanup();
|
||||||
CRYPTO_cleanup_all_ex_data();
|
CRYPTO_cleanup_all_ex_data();
|
||||||
|
|
@ -59,4 +63,34 @@ namespace fc
|
||||||
static openssl_scope ossl;
|
static openssl_scope ossl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SSL_TYPE_IMPL(name, ssl_type, free_func) \
|
||||||
|
name::name( ssl_type* obj ) : ssl_wrapper(obj) {} \
|
||||||
|
name::name( name&& move ) : ssl_wrapper( move.obj ) \
|
||||||
|
{ \
|
||||||
|
move.obj = nullptr; \
|
||||||
|
} \
|
||||||
|
name::~name() \
|
||||||
|
{ \
|
||||||
|
if( obj != nullptr ) \
|
||||||
|
free_func(obj); \
|
||||||
|
} \
|
||||||
|
name& name::operator=( name&& move ) \
|
||||||
|
{ \
|
||||||
|
if( this != &move ) \
|
||||||
|
{ \
|
||||||
|
if( obj != nullptr ) \
|
||||||
|
free_func(obj); \
|
||||||
|
obj = move.obj; \
|
||||||
|
move.obj = nullptr; \
|
||||||
|
} \
|
||||||
|
return *this; \
|
||||||
|
}
|
||||||
|
|
||||||
|
SSL_TYPE_IMPL(ec_group, EC_GROUP, EC_GROUP_free)
|
||||||
|
SSL_TYPE_IMPL(ec_point, EC_POINT, EC_POINT_free)
|
||||||
|
SSL_TYPE_IMPL(ecdsa_sig, ECDSA_SIG, ECDSA_SIG_free)
|
||||||
|
SSL_TYPE_IMPL(bn_ctx, BN_CTX, BN_CTX_free)
|
||||||
|
SSL_TYPE_IMPL(evp_cipher_ctx, EVP_CIPHER_CTX, EVP_CIPHER_CTX_free )
|
||||||
|
SSL_TYPE_IMPL(ssl_dh, DH, DH_free)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ namespace fc
|
||||||
|
|
||||||
std::exception_ptr unhandled_exception::get_inner_exception()const { return _inner; }
|
std::exception_ptr unhandled_exception::get_inner_exception()const { return _inner; }
|
||||||
|
|
||||||
NO_RETURN void unhandled_exception::dynamic_rethrow_exception()const
|
[[noreturn]] void unhandled_exception::dynamic_rethrow_exception()const
|
||||||
{
|
{
|
||||||
if( !(_inner == std::exception_ptr()) ) std::rethrow_exception( _inner );
|
if( !(_inner == std::exception_ptr()) ) std::rethrow_exception( _inner );
|
||||||
else { fc::exception::dynamic_rethrow_exception(); }
|
else { fc::exception::dynamic_rethrow_exception(); }
|
||||||
|
|
@ -182,22 +182,41 @@ namespace fc
|
||||||
*/
|
*/
|
||||||
string exception::to_detail_string( log_level ll )const
|
string exception::to_detail_string( log_level ll )const
|
||||||
{
|
{
|
||||||
fc::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << variant(my->_code).as_string() <<" " << my->_name << ": " <<my->_what<<"\n";
|
try {
|
||||||
for( auto itr = my->_elog.begin(); itr != my->_elog.end(); )
|
try {
|
||||||
{
|
ss << variant( my->_code ).as_string();
|
||||||
ss << itr->get_message() <<"\n";
|
} catch( std::bad_alloc& ) {
|
||||||
try
|
throw;
|
||||||
{
|
} catch( ... ) {
|
||||||
ss << " " << json::to_string( itr->get_data() )<<"\n";
|
ss << "<- exception in to_detail_string.";
|
||||||
}
|
}
|
||||||
catch( const fc::assert_exception& e )
|
ss << " " << my->_name << ": " << my->_what << "\n";
|
||||||
|
for( auto itr = my->_elog.begin(); itr != my->_elog.end(); )
|
||||||
{
|
{
|
||||||
ss << "ERROR: Failed to convert log data to string!\n";
|
try {
|
||||||
|
ss << itr->get_message() <<"\n";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ss << " " << json::to_string( itr->get_data() )<<"\n";
|
||||||
|
}
|
||||||
|
catch( const fc::assert_exception& e )
|
||||||
|
{
|
||||||
|
ss << "ERROR: Failed to convert log data to string!\n";
|
||||||
|
}
|
||||||
|
ss << " " << itr->get_context().to_string();
|
||||||
|
} catch( std::bad_alloc& ) {
|
||||||
|
throw;
|
||||||
|
} catch( ... ) {
|
||||||
|
ss << "<- exception in to_detail_string.";
|
||||||
|
}
|
||||||
|
++itr;
|
||||||
|
if( itr != my->_elog.end() ) ss<<"\n";
|
||||||
}
|
}
|
||||||
ss << " " << itr->get_context().to_string();
|
} catch( std::bad_alloc& ) {
|
||||||
++itr;
|
throw;
|
||||||
if( itr != my->_elog.end() ) ss<<"\n";
|
} catch( ... ) {
|
||||||
|
ss << "<- exception in to_detail_string.\n";
|
||||||
}
|
}
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
@ -207,17 +226,28 @@ namespace fc
|
||||||
*/
|
*/
|
||||||
string exception::to_string( log_level ll )const
|
string exception::to_string( log_level ll )const
|
||||||
{
|
{
|
||||||
fc::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << what() << ":";
|
try {
|
||||||
for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ++itr )
|
ss << what() << ":";
|
||||||
{
|
for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ++itr ) {
|
||||||
if( itr->get_format().size() )
|
if( itr->get_format().size() )
|
||||||
ss << " " << fc::format_string( itr->get_format(), itr->get_data() );
|
try {
|
||||||
|
ss << " " << fc::format_string( itr->get_format(), itr->get_data() );
|
||||||
|
} catch( std::bad_alloc& ) {
|
||||||
|
throw;
|
||||||
|
} catch( ... ) {
|
||||||
|
ss << "<- exception in to_string.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch( std::bad_alloc& ) {
|
||||||
|
throw;
|
||||||
|
} catch( ... ) {
|
||||||
|
ss << "<- exception in to_string.\n";
|
||||||
}
|
}
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NO_RETURN exception_factory::rethrow( const exception& e )const
|
[[noreturn]] void exception_factory::rethrow( const exception& e )const
|
||||||
{
|
{
|
||||||
auto itr = _registered_exceptions.find( e.code() );
|
auto itr = _registered_exceptions.find( e.code() );
|
||||||
if( itr != _registered_exceptions.end() )
|
if( itr != _registered_exceptions.end() )
|
||||||
|
|
@ -229,7 +259,7 @@ namespace fc
|
||||||
* the error code. This is used to propagate exception types
|
* the error code. This is used to propagate exception types
|
||||||
* across conversions to/from JSON
|
* across conversions to/from JSON
|
||||||
*/
|
*/
|
||||||
NO_RETURN void exception::dynamic_rethrow_exception()const
|
[[noreturn]] void exception::dynamic_rethrow_exception()const
|
||||||
{
|
{
|
||||||
exception_factory::instance().rethrow( *this );
|
exception_factory::instance().rethrow( *this );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include <fc/io/datastream.hpp>
|
#include <fc/io/datastream.hpp>
|
||||||
#include <fc/exception/exception.hpp>
|
#include <fc/exception/exception.hpp>
|
||||||
|
|
||||||
NO_RETURN void fc::detail::throw_datastream_range_error(char const* method, size_t len, int64_t over)
|
[[noreturn]] void fc::detail::throw_datastream_range_error(char const* method, size_t len, int64_t over)
|
||||||
{
|
{
|
||||||
FC_THROW_EXCEPTION( out_of_range_exception, "${method} datastream of length ${len} over by ${over}", ("method",std::string(method))("len",len)("over",over) );
|
FC_THROW_EXCEPTION( out_of_range_exception, "${method} datastream of length ${len} over by ${over}", ("method",std::string(method))("len",len)("over",over) );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,11 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
class ofstream::impl : public fc::retainable {
|
class ofstream::impl {
|
||||||
public:
|
public:
|
||||||
boost::filesystem::ofstream ofs;
|
boost::filesystem::ofstream ofs;
|
||||||
};
|
};
|
||||||
class ifstream::impl : public fc::retainable {
|
class ifstream::impl {
|
||||||
public:
|
public:
|
||||||
boost::filesystem::ifstream ifs;
|
boost::filesystem::ifstream ifs;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace fc {
|
||||||
std::cin.read(&c,1);
|
std::cin.read(&c,1);
|
||||||
while( !std::cin.eof() ) {
|
while( !std::cin.eof() ) {
|
||||||
while( write_pos - read_pos > 0xfffff ) {
|
while( write_pos - read_pos > 0xfffff ) {
|
||||||
fc::promise<void>::ptr wr( new fc::promise<void>("cin_buffer::write_ready") );
|
fc::promise<void>::ptr wr = fc::promise<void>::create("cin_buffer::write_ready");
|
||||||
write_ready = wr;
|
write_ready = wr;
|
||||||
if( write_pos - read_pos <= 0xfffff ) {
|
if( write_pos - read_pos <= 0xfffff ) {
|
||||||
wr->wait();
|
wr->wait();
|
||||||
|
|
@ -138,7 +138,7 @@ namespace fc {
|
||||||
do {
|
do {
|
||||||
while( !b.eof && (b.write_pos - b.read_pos)==0 ){
|
while( !b.eof && (b.write_pos - b.read_pos)==0 ){
|
||||||
// wait for more...
|
// wait for more...
|
||||||
fc::promise<void>::ptr rr( new fc::promise<void>("cin_buffer::read_ready") );
|
fc::promise<void>::ptr rr = fc::promise<void>::create("cin_buffer::read_ready");
|
||||||
{ // copy read_ready because it is accessed from multiple threads
|
{ // copy read_ready because it is accessed from multiple threads
|
||||||
fc::scoped_lock<boost::mutex> lock( b.read_ready_mutex );
|
fc::scoped_lock<boost::mutex> lock( b.read_ready_mutex );
|
||||||
b.read_ready = rr;
|
b.read_ready = rr;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
class file_appender::impl : public fc::retainable
|
class file_appender::impl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
config cfg;
|
config cfg;
|
||||||
|
|
@ -21,18 +21,13 @@ namespace fc {
|
||||||
boost::mutex slock;
|
boost::mutex slock;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
future<void> _rotation_task;
|
future<void> _deletion_task;
|
||||||
time_point_sec _current_file_start_time;
|
boost::atomic<int64_t> _current_file_number;
|
||||||
|
const int64_t _interval_seconds;
|
||||||
time_point_sec get_file_start_time( const time_point_sec& timestamp, const microseconds& interval )
|
time_point _next_file_time;
|
||||||
{
|
|
||||||
int64_t interval_seconds = interval.to_seconds();
|
|
||||||
int64_t file_number = timestamp.sec_since_epoch() / interval_seconds;
|
|
||||||
return time_point_sec( (uint32_t)(file_number * interval_seconds) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
impl( const config& c) : cfg( c )
|
impl( const config& c) : cfg( c ), _interval_seconds( cfg.rotation_interval.to_seconds() )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -44,6 +39,7 @@ namespace fc {
|
||||||
FC_ASSERT( cfg.rotation_limit >= cfg.rotation_interval );
|
FC_ASSERT( cfg.rotation_limit >= cfg.rotation_interval );
|
||||||
|
|
||||||
rotate_files( true );
|
rotate_files( true );
|
||||||
|
delete_files();
|
||||||
} else {
|
} else {
|
||||||
out.open( cfg.filename, std::ios_base::out | std::ios_base::app);
|
out.open( cfg.filename, std::ios_base::out | std::ios_base::app);
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +54,7 @@ namespace fc {
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_rotation_task.cancel_and_wait("file_appender is destructing");
|
_deletion_task.cancel_and_wait("file_appender is destructing");
|
||||||
}
|
}
|
||||||
catch( ... )
|
catch( ... )
|
||||||
{
|
{
|
||||||
|
|
@ -67,9 +63,22 @@ namespace fc {
|
||||||
|
|
||||||
void rotate_files( bool initializing = false )
|
void rotate_files( bool initializing = false )
|
||||||
{
|
{
|
||||||
FC_ASSERT( cfg.rotate );
|
if( !cfg.rotate ) return;
|
||||||
|
|
||||||
fc::time_point now = time_point::now();
|
fc::time_point now = time_point::now();
|
||||||
fc::time_point_sec start_time = get_file_start_time( now, cfg.rotation_interval );
|
if( now < _next_file_time ) return;
|
||||||
|
|
||||||
|
int64_t new_file_number = now.sec_since_epoch() / _interval_seconds;
|
||||||
|
if( initializing )
|
||||||
|
_current_file_number.store( new_file_number );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int64_t prev_file_number = _current_file_number.load();
|
||||||
|
if( prev_file_number >= new_file_number ) return;
|
||||||
|
if( !_current_file_number.compare_exchange_weak( prev_file_number, new_file_number ) ) return;
|
||||||
|
}
|
||||||
|
fc::time_point_sec start_time = time_point_sec( (uint32_t)(new_file_number * _interval_seconds) );
|
||||||
|
_next_file_time = start_time + _interval_seconds;
|
||||||
string timestamp_string = start_time.to_non_delimited_iso_string();
|
string timestamp_string = start_time.to_non_delimited_iso_string();
|
||||||
fc::path link_filename = cfg.filename;
|
fc::path link_filename = cfg.filename;
|
||||||
fc::path log_filename = link_filename.parent_path() / (link_filename.filename().string() + "." + timestamp_string);
|
fc::path log_filename = link_filename.parent_path() / (link_filename.filename().string() + "." + timestamp_string);
|
||||||
|
|
@ -79,14 +88,6 @@ namespace fc {
|
||||||
|
|
||||||
if( !initializing )
|
if( !initializing )
|
||||||
{
|
{
|
||||||
if( start_time <= _current_file_start_time )
|
|
||||||
{
|
|
||||||
_rotation_task = schedule( [this]() { rotate_files(); },
|
|
||||||
_current_file_start_time + cfg.rotation_interval.to_seconds(),
|
|
||||||
"rotate_files(2)" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
|
|
@ -94,29 +95,34 @@ namespace fc {
|
||||||
out.open( log_filename, std::ios_base::out | std::ios_base::app );
|
out.open( log_filename, std::ios_base::out | std::ios_base::app );
|
||||||
create_hard_link(log_filename, link_filename);
|
create_hard_link(log_filename, link_filename);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_files()
|
||||||
|
{
|
||||||
/* Delete old log files */
|
/* Delete old log files */
|
||||||
fc::time_point limit_time = now - cfg.rotation_limit;
|
auto current_file = _current_file_number.load();
|
||||||
|
fc::time_point_sec start_time = time_point_sec( (uint32_t)(current_file * _interval_seconds) );
|
||||||
|
fc::time_point limit_time = time_point::now() - cfg.rotation_limit;
|
||||||
|
fc::path link_filename = cfg.filename;
|
||||||
string link_filename_string = link_filename.filename().string();
|
string link_filename_string = link_filename.filename().string();
|
||||||
directory_iterator itr(link_filename.parent_path());
|
directory_iterator itr(link_filename.parent_path());
|
||||||
|
string timestamp_string = start_time.to_non_delimited_iso_string();
|
||||||
for( ; itr != directory_iterator(); itr++ )
|
for( ; itr != directory_iterator(); itr++ )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string current_filename = itr->filename().string();
|
string current_filename = itr->filename().string();
|
||||||
if (current_filename.compare(0, link_filename_string.size(), link_filename_string) != 0 ||
|
if( current_filename.compare(0, link_filename_string.size(), link_filename_string) != 0
|
||||||
current_filename.size() <= link_filename_string.size() + 1)
|
|| current_filename.size() <= link_filename_string.size() + 1 )
|
||||||
continue;
|
continue;
|
||||||
string current_timestamp_str = current_filename.substr(link_filename_string.size() + 1,
|
string current_timestamp_str = current_filename.substr(link_filename_string.size() + 1,
|
||||||
timestamp_string.size());
|
timestamp_string.size());
|
||||||
fc::time_point_sec current_timestamp = fc::time_point_sec::from_iso_string( current_timestamp_str );
|
fc::time_point_sec current_timestamp = fc::time_point_sec::from_iso_string( current_timestamp_str );
|
||||||
if( current_timestamp < start_time )
|
if( current_timestamp < start_time
|
||||||
|
&& ( current_timestamp < limit_time || file_size( current_filename ) <= 0 ) )
|
||||||
{
|
{
|
||||||
if( current_timestamp < limit_time || file_size( current_filename ) <= 0 )
|
remove_all( *itr );
|
||||||
{
|
continue;
|
||||||
remove_all( *itr );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const fc::canceled_exception&)
|
catch (const fc::canceled_exception&)
|
||||||
|
|
@ -127,11 +133,10 @@ namespace fc {
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
uint64_t next_file = time_point::now().sec_since_epoch() / _interval_seconds + 1;
|
||||||
_current_file_start_time = start_time;
|
_deletion_task = schedule( [this]() { delete_files(); },
|
||||||
_rotation_task = schedule( [this]() { rotate_files(); },
|
fc::time_point_sec( next_file * _interval_seconds),
|
||||||
_current_file_start_time + cfg.rotation_interval.to_seconds(),
|
"delete_files(3)" );
|
||||||
"rotate_files(3)" );
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -151,8 +156,9 @@ namespace fc {
|
||||||
// MS THREAD METHOD MESSAGE \t\t\t File:Line
|
// MS THREAD METHOD MESSAGE \t\t\t File:Line
|
||||||
void file_appender::log( const log_message& m )
|
void file_appender::log( const log_message& m )
|
||||||
{
|
{
|
||||||
|
my->rotate_files();
|
||||||
|
|
||||||
std::stringstream line;
|
std::stringstream line;
|
||||||
//line << (m.get_context().get_timestamp().time_since_epoch().count() % (1000ll*1000ll*60ll*60))/1000 <<"ms ";
|
|
||||||
line << string(m.get_context().get_timestamp()) << " ";
|
line << string(m.get_context().get_timestamp()) << " ";
|
||||||
line << std::setw( 21 ) << (m.get_context().get_thread_name().substr(0,9) + string(":") + m.get_context().get_task_name()).c_str() << " ";
|
line << std::setw( 21 ) << (m.get_context().get_thread_name().substr(0,9) + string(":") + m.get_context().get_task_name()).c_str() << " ";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
namespace fc
|
namespace fc
|
||||||
{
|
{
|
||||||
|
|
||||||
class gelf_appender::impl : public retainable
|
class gelf_appender::impl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
config cfg;
|
config cfg;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
class logger::impl : public fc::retainable {
|
class logger::impl {
|
||||||
public:
|
public:
|
||||||
impl()
|
impl()
|
||||||
:_parent(nullptr),_enabled(true),_additivity(false),_level(log_level::warn){}
|
:_parent(nullptr),_enabled(true),_additivity(false),_level(log_level::warn){}
|
||||||
|
|
@ -28,7 +28,7 @@ namespace fc {
|
||||||
logger::logger()
|
logger::logger()
|
||||||
:my( new impl() ){}
|
:my( new impl() ){}
|
||||||
|
|
||||||
logger::logger(nullptr_t){}
|
logger::logger(std::nullptr_t){}
|
||||||
|
|
||||||
logger::logger( const string& name, const logger& parent )
|
logger::logger( const string& name, const logger& parent )
|
||||||
:my( new impl() )
|
:my( new impl() )
|
||||||
|
|
@ -54,8 +54,8 @@ namespace fc {
|
||||||
std::swap(my,l.my);
|
std::swap(my,l.my);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
bool operator==( const logger& l, std::nullptr_t ) { return !l.my; }
|
bool operator==( const logger& l, std::nullptr_t ) { return !(bool)l.my; }
|
||||||
bool operator!=( const logger& l, std::nullptr_t ) { return l.my; }
|
bool operator!=( const logger& l, std::nullptr_t ) { return (bool)l.my; }
|
||||||
|
|
||||||
bool logger::is_enabled( log_level e )const {
|
bool logger::is_enabled( log_level e )const {
|
||||||
return e >= my->_level;
|
return e >= my->_level;
|
||||||
|
|
@ -96,13 +96,10 @@ namespace fc {
|
||||||
log_level logger::get_log_level()const { return my->_level; }
|
log_level logger::get_log_level()const { return my->_level; }
|
||||||
logger& logger::set_log_level(log_level ll) { my->_level = ll; return *this; }
|
logger& logger::set_log_level(log_level ll) { my->_level = ll; return *this; }
|
||||||
|
|
||||||
void logger::add_appender( const fc::shared_ptr<appender>& a )
|
void logger::add_appender( const appender::ptr& a )
|
||||||
{ my->_appenders.push_back(a); }
|
{ my->_appenders.push_back(a); }
|
||||||
|
|
||||||
// void logger::remove_appender( const fc::shared_ptr<appender>& a )
|
std::vector<appender::ptr> logger::get_appenders()const
|
||||||
// { my->_appenders.erase(a); }
|
|
||||||
|
|
||||||
std::vector<fc::shared_ptr<appender> > logger::get_appenders()const
|
|
||||||
{
|
{
|
||||||
return my->_appenders;
|
return my->_appenders;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,207 +0,0 @@
|
||||||
#include <fc/network/http/server.hpp>
|
|
||||||
#include <fc/thread/thread.hpp>
|
|
||||||
#include <fc/network/tcp_socket.hpp>
|
|
||||||
#include <fc/io/sstream.hpp>
|
|
||||||
#include <fc/network/ip.hpp>
|
|
||||||
#include <fc/io/stdio.hpp>
|
|
||||||
#include <fc/log/logger.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
namespace fc { namespace http {
|
|
||||||
|
|
||||||
class server::response::impl : public fc::retainable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
impl( const fc::http::connection_ptr& c, const std::function<void()>& cont = std::function<void()>() )
|
|
||||||
:body_bytes_sent(0),body_length(0),con(c),handle_next_req(cont)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void send_header() {
|
|
||||||
//ilog( "sending header..." );
|
|
||||||
fc::stringstream ss;
|
|
||||||
ss << "HTTP/1.1 " << rep.status << " ";
|
|
||||||
switch( rep.status ) {
|
|
||||||
case fc::http::reply::OK: ss << "OK\r\n"; break;
|
|
||||||
case fc::http::reply::RecordCreated: ss << "Record Created\r\n"; break;
|
|
||||||
case fc::http::reply::NotFound: ss << "Not Found\r\n"; break;
|
|
||||||
case fc::http::reply::Found: ss << "Found\r\n"; break;
|
|
||||||
default: ss << "Internal Server Error\r\n"; break;
|
|
||||||
}
|
|
||||||
for( uint32_t i = 0; i < rep.headers.size(); ++i ) {
|
|
||||||
ss << rep.headers[i].key <<": "<<rep.headers[i].val <<"\r\n";
|
|
||||||
}
|
|
||||||
ss << "Content-Length: "<<body_length<<"\r\n\r\n";
|
|
||||||
auto s = ss.str();
|
|
||||||
//fc::cerr<<s<<"\n";
|
|
||||||
con->get_socket().write( s.c_str(), s.size() );
|
|
||||||
}
|
|
||||||
|
|
||||||
http::reply rep;
|
|
||||||
int64_t body_bytes_sent;
|
|
||||||
uint64_t body_length;
|
|
||||||
http::connection_ptr con;
|
|
||||||
std::function<void()> handle_next_req;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class server::impl
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
impl(){}
|
|
||||||
|
|
||||||
impl(const fc::ip::endpoint& p )
|
|
||||||
{
|
|
||||||
tcp_serv.set_reuse_address();
|
|
||||||
tcp_serv.listen(p);
|
|
||||||
accept_complete = fc::async([this](){ this->accept_loop(); }, "http_server accept_loop");
|
|
||||||
}
|
|
||||||
|
|
||||||
~impl()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
tcp_serv.close();
|
|
||||||
if (accept_complete.valid())
|
|
||||||
accept_complete.wait();
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
for (fc::future<void>& request_in_progress : requests_in_progress)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
request_in_progress.cancel_and_wait();
|
|
||||||
}
|
|
||||||
catch (const fc::exception& e)
|
|
||||||
{
|
|
||||||
wlog("Caught exception while canceling http request task: ${error}", ("error", e));
|
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
wlog("Caught exception while canceling http request task: ${error}", ("error", e.what()));
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
wlog("Caught unknown exception while canceling http request task");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
requests_in_progress.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void accept_loop()
|
|
||||||
{
|
|
||||||
while( !accept_complete.canceled() )
|
|
||||||
{
|
|
||||||
http::connection_ptr con = std::make_shared<http::connection>();
|
|
||||||
tcp_serv.accept( con->get_socket() );
|
|
||||||
//ilog( "Accept Connection" );
|
|
||||||
// clean up futures for any completed requests
|
|
||||||
for (auto iter = requests_in_progress.begin(); iter != requests_in_progress.end();)
|
|
||||||
if (!iter->valid() || iter->ready())
|
|
||||||
iter = requests_in_progress.erase(iter);
|
|
||||||
else
|
|
||||||
++iter;
|
|
||||||
requests_in_progress.emplace_back(fc::async([=](){ handle_connection(con, on_req); }, "http_server handle_connection"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_connection( const http::connection_ptr& c,
|
|
||||||
std::function<void(const http::request&, const server::response& s )> do_on_req )
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
http::server::response rep( fc::shared_ptr<response::impl>( new response::impl(c) ) );
|
|
||||||
request req = c->read_request();
|
|
||||||
if( do_on_req )
|
|
||||||
do_on_req( req, rep );
|
|
||||||
c->get_socket().close();
|
|
||||||
}
|
|
||||||
catch ( fc::exception& e )
|
|
||||||
{
|
|
||||||
wlog( "unable to read request ${1}", ("1", e.to_detail_string() ) );//fc::except_str().c_str());
|
|
||||||
}
|
|
||||||
//wlog( "done handle connection" );
|
|
||||||
}
|
|
||||||
|
|
||||||
fc::future<void> accept_complete;
|
|
||||||
std::function<void(const http::request&, const server::response& s)> on_req;
|
|
||||||
std::vector<fc::future<void> > requests_in_progress;
|
|
||||||
fc::tcp_server tcp_serv;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
server::server():my( new impl() ){}
|
|
||||||
server::server( uint16_t port ) :my( new impl(fc::ip::endpoint( fc::ip::address(),port)) ){}
|
|
||||||
server::server( server&& s ):my(std::move(s.my)){}
|
|
||||||
|
|
||||||
server& server::operator=(server&& s) { std::swap(my,s.my); return *this; }
|
|
||||||
|
|
||||||
server::~server(){}
|
|
||||||
|
|
||||||
void server::listen( const fc::ip::endpoint& p )
|
|
||||||
{
|
|
||||||
my.reset( new impl(p) );
|
|
||||||
}
|
|
||||||
|
|
||||||
fc::ip::endpoint server::get_local_endpoint() const
|
|
||||||
{
|
|
||||||
return my->tcp_serv.get_local_endpoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
server::response::response(){}
|
|
||||||
server::response::response( const server::response& s ):my(s.my){}
|
|
||||||
server::response::response( server::response&& s ):my(std::move(s.my)){}
|
|
||||||
server::response::response( const fc::shared_ptr<server::response::impl>& m ):my(m){}
|
|
||||||
|
|
||||||
server::response& server::response::operator=(const server::response& s) { my = s.my; return *this; }
|
|
||||||
server::response& server::response::operator=(server::response&& s) { std::swap(my,s.my); return *this; }
|
|
||||||
|
|
||||||
void server::response::add_header( const std::string& key, const std::string& val )const {
|
|
||||||
my->rep.headers.push_back( fc::http::header( key, val ) );
|
|
||||||
}
|
|
||||||
void server::response::set_status( const http::reply::status_code& s )const {
|
|
||||||
if( my->body_bytes_sent != 0 ) {
|
|
||||||
wlog( "Attempt to set status after sending headers" );
|
|
||||||
}
|
|
||||||
my->rep.status = s;
|
|
||||||
}
|
|
||||||
void server::response::set_length( uint64_t s )const {
|
|
||||||
if( my->body_bytes_sent != 0 ) {
|
|
||||||
wlog( "Attempt to set length after sending headers" );
|
|
||||||
}
|
|
||||||
my->body_length = s;
|
|
||||||
}
|
|
||||||
void server::response::write( const char* data, uint64_t len )const {
|
|
||||||
if( my->body_bytes_sent + len > my->body_length ) {
|
|
||||||
wlog( "Attempt to send to many bytes.." );
|
|
||||||
len = my->body_bytes_sent + len - my->body_length;
|
|
||||||
}
|
|
||||||
if( my->body_bytes_sent == 0 ) {
|
|
||||||
my->send_header();
|
|
||||||
}
|
|
||||||
my->body_bytes_sent += len;
|
|
||||||
my->con->get_socket().write( data, static_cast<size_t>(len) );
|
|
||||||
if( my->body_bytes_sent == int64_t(my->body_length) ) {
|
|
||||||
if( false || my->handle_next_req ) {
|
|
||||||
ilog( "handle next request..." );
|
|
||||||
//fc::async( std::function<void()>(my->handle_next_req) );
|
|
||||||
fc::async( my->handle_next_req, "http_server handle_next_req" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
server::response::~response(){}
|
|
||||||
|
|
||||||
void server::on_request( const std::function<void(const http::request&, const server::response& s )>& cb )
|
|
||||||
{
|
|
||||||
my->on_req = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} }
|
|
||||||
|
|
@ -20,6 +20,10 @@
|
||||||
#include <fc/thread/thread.hpp>
|
#include <fc/thread/thread.hpp>
|
||||||
#include <fc/asio.hpp>
|
#include <fc/asio.hpp>
|
||||||
|
|
||||||
|
#if WIN32
|
||||||
|
#include <wincrypt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DEFAULT_LOGGER
|
#ifdef DEFAULT_LOGGER
|
||||||
# undef DEFAULT_LOGGER
|
# undef DEFAULT_LOGGER
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -28,7 +32,33 @@
|
||||||
namespace fc { namespace http {
|
namespace fc { namespace http {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
#if WIN32
|
||||||
|
// taken from https://stackoverflow.com/questions/39772878/reliable-way-to-get-root-ca-certificates-on-windows/40710806
|
||||||
|
static void add_windows_root_certs(boost::asio::ssl::context &ctx)
|
||||||
|
{
|
||||||
|
HCERTSTORE hStore = CertOpenSystemStore( 0, "ROOT" );
|
||||||
|
if( hStore == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
X509_STORE *store = X509_STORE_new();
|
||||||
|
PCCERT_CONTEXT pContext = NULL;
|
||||||
|
while( (pContext = CertEnumCertificatesInStore( hStore, pContext )) != NULL )
|
||||||
|
{
|
||||||
|
X509 *x509 = d2i_X509( NULL, (const unsigned char **)&pContext->pbCertEncoded,
|
||||||
|
pContext->cbCertEncoded);
|
||||||
|
if( x509 != NULL )
|
||||||
|
{
|
||||||
|
X509_STORE_add_cert( store, x509 );
|
||||||
|
X509_free( x509 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CertFreeCertificateContext( pContext );
|
||||||
|
CertCloseStore( hStore, 0 );
|
||||||
|
|
||||||
|
SSL_CTX_set_cert_store( ctx.native_handle(), store );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
struct asio_with_stub_log : public websocketpp::config::asio {
|
struct asio_with_stub_log : public websocketpp::config::asio {
|
||||||
|
|
||||||
typedef asio_with_stub_log type;
|
typedef asio_with_stub_log type;
|
||||||
|
|
@ -292,8 +322,8 @@ namespace fc { namespace http {
|
||||||
if( _server.is_listening() )
|
if( _server.is_listening() )
|
||||||
_server.stop_listening();
|
_server.stop_listening();
|
||||||
|
|
||||||
if ( _connections.size() )
|
if( _connections.size() )
|
||||||
_closed = new fc::promise<void>();
|
_closed = promise<void>::create();
|
||||||
|
|
||||||
auto cpy_con = _connections;
|
auto cpy_con = _connections;
|
||||||
for( auto item : cpy_con )
|
for( auto item : cpy_con )
|
||||||
|
|
@ -550,7 +580,13 @@ namespace fc { namespace http {
|
||||||
return;
|
return;
|
||||||
ctx->set_verify_mode( boost::asio::ssl::verify_peer );
|
ctx->set_verify_mode( boost::asio::ssl::verify_peer );
|
||||||
if( ca_filename == "_default" )
|
if( ca_filename == "_default" )
|
||||||
|
{
|
||||||
|
#if WIN32
|
||||||
|
add_windows_root_certs( *ctx );
|
||||||
|
#else
|
||||||
ctx->set_default_verify_paths();
|
ctx->set_default_verify_paths();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ctx->load_verify_file( ca_filename );
|
ctx->load_verify_file( ca_filename );
|
||||||
ctx->set_verify_depth(10);
|
ctx->set_verify_depth(10);
|
||||||
|
|
@ -642,13 +678,13 @@ namespace fc { namespace http {
|
||||||
websocketpp::lib::error_code ec;
|
websocketpp::lib::error_code ec;
|
||||||
|
|
||||||
my->_uri = uri;
|
my->_uri = uri;
|
||||||
my->_connected = fc::promise<void>::ptr( new fc::promise<void>("websocket::connect") );
|
my->_connected = promise<void>::create("websocket::connect");
|
||||||
|
|
||||||
my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){
|
my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){
|
||||||
my->_hdl = hdl;
|
my->_hdl = hdl;
|
||||||
auto con = my->_client.get_con_from_hdl(hdl);
|
auto con = my->_client.get_con_from_hdl(hdl);
|
||||||
my->_connection = std::make_shared<detail::websocket_connection_impl<detail::websocket_client_connection_type>>( con );
|
my->_connection = std::make_shared<detail::websocket_connection_impl<detail::websocket_client_connection_type>>( con );
|
||||||
my->_closed = fc::promise<void>::ptr( new fc::promise<void>("websocket::closed") );
|
my->_closed = promise<void>::create("websocket::closed");
|
||||||
my->_connected->set_value();
|
my->_connected->set_value();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -670,12 +706,12 @@ namespace fc { namespace http {
|
||||||
websocketpp::lib::error_code ec;
|
websocketpp::lib::error_code ec;
|
||||||
|
|
||||||
smy->_uri = uri;
|
smy->_uri = uri;
|
||||||
smy->_connected = fc::promise<void>::ptr( new fc::promise<void>("websocket::connect") );
|
smy->_connected = promise<void>::create("websocket::connect");
|
||||||
|
|
||||||
smy->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){
|
smy->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){
|
||||||
auto con = smy->_client.get_con_from_hdl(hdl);
|
auto con = smy->_client.get_con_from_hdl(hdl);
|
||||||
smy->_connection = std::make_shared<detail::websocket_connection_impl<detail::websocket_tls_client_connection_type>>( con );
|
smy->_connection = std::make_shared<detail::websocket_connection_impl<detail::websocket_tls_client_connection_type>>( con );
|
||||||
smy->_closed = fc::promise<void>::ptr( new fc::promise<void>("websocket::closed") );
|
smy->_closed = promise<void>::create("websocket::closed");
|
||||||
smy->_connected->set_value();
|
smy->_connected->set_value();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -705,12 +741,12 @@ namespace fc { namespace http {
|
||||||
// wlog( "connecting to ${uri}", ("uri",uri));
|
// wlog( "connecting to ${uri}", ("uri",uri));
|
||||||
websocketpp::lib::error_code ec;
|
websocketpp::lib::error_code ec;
|
||||||
|
|
||||||
my->_connected = fc::promise<void>::ptr( new fc::promise<void>("websocket::connect") );
|
my->_connected = promise<void>::create("websocket::connect");
|
||||||
|
|
||||||
my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){
|
my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){
|
||||||
auto con = my->_client.get_con_from_hdl(hdl);
|
auto con = my->_client.get_con_from_hdl(hdl);
|
||||||
my->_connection = std::make_shared<detail::websocket_connection_impl<detail::websocket_tls_client_connection_type>>( con );
|
my->_connection = std::make_shared<detail::websocket_connection_impl<detail::websocket_tls_client_connection_type>>( con );
|
||||||
my->_closed = fc::promise<void>::ptr( new fc::promise<void>("websocket::closed") );
|
my->_closed = promise<void>::create("websocket::closed");
|
||||||
my->_connected->set_value();
|
my->_connected->set_value();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -284,7 +284,7 @@ namespace fc
|
||||||
size_t bytes_read;
|
size_t bytes_read;
|
||||||
if (_download_bytes_per_second)
|
if (_download_bytes_per_second)
|
||||||
{
|
{
|
||||||
promise<size_t>::ptr completion_promise(new promise<size_t>("rate_limiting_group_impl::readsome"));
|
promise<size_t>::ptr completion_promise = promise<size_t>::create("rate_limiting_group_impl::readsome");
|
||||||
rate_limited_tcp_read_operation read_operation(socket, buffer, length, offset, completion_promise);
|
rate_limited_tcp_read_operation read_operation(socket, buffer, length, offset, completion_promise);
|
||||||
_read_operations_for_next_iteration.push_back(&read_operation);
|
_read_operations_for_next_iteration.push_back(&read_operation);
|
||||||
|
|
||||||
|
|
@ -330,7 +330,7 @@ namespace fc
|
||||||
size_t bytes_written;
|
size_t bytes_written;
|
||||||
if (_upload_bytes_per_second)
|
if (_upload_bytes_per_second)
|
||||||
{
|
{
|
||||||
promise<size_t>::ptr completion_promise(new promise<size_t>("rate_limiting_group_impl::writesome"));
|
promise<size_t>::ptr completion_promise = promise<size_t>::create("rate_limiting_group_impl::writesome");
|
||||||
rate_limited_tcp_write_operation write_operation(socket, buffer, length, offset, completion_promise);
|
rate_limited_tcp_write_operation write_operation(socket, buffer, length, offset, completion_promise);
|
||||||
_write_operations_for_next_iteration.push_back(&write_operation);
|
_write_operations_for_next_iteration.push_back(&write_operation);
|
||||||
|
|
||||||
|
|
@ -367,7 +367,7 @@ namespace fc
|
||||||
process_pending_operations(_last_read_iteration_time, _download_bytes_per_second,
|
process_pending_operations(_last_read_iteration_time, _download_bytes_per_second,
|
||||||
_read_operations_in_progress, _read_operations_for_next_iteration, _read_tokens, _unused_read_tokens);
|
_read_operations_in_progress, _read_operations_for_next_iteration, _read_tokens, _unused_read_tokens);
|
||||||
|
|
||||||
_new_read_operation_available_promise = new promise<void>("rate_limiting_group_impl::process_pending_reads");
|
_new_read_operation_available_promise = promise<void>::create("rate_limiting_group_impl::process_pending_reads");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_read_operations_in_progress.empty())
|
if (_read_operations_in_progress.empty())
|
||||||
|
|
@ -388,7 +388,7 @@ namespace fc
|
||||||
process_pending_operations(_last_write_iteration_time, _upload_bytes_per_second,
|
process_pending_operations(_last_write_iteration_time, _upload_bytes_per_second,
|
||||||
_write_operations_in_progress, _write_operations_for_next_iteration, _write_tokens, _unused_write_tokens);
|
_write_operations_in_progress, _write_operations_for_next_iteration, _write_tokens, _unused_write_tokens);
|
||||||
|
|
||||||
_new_write_operation_available_promise = new promise<void>("rate_limiting_group_impl::process_pending_writes");
|
_new_write_operation_available_promise = promise<void>::create("rate_limiting_group_impl::process_pending_writes");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_write_operations_in_progress.empty())
|
if (_write_operations_in_progress.empty())
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,13 @@
|
||||||
# include <mstcpip.h>
|
# include <mstcpip.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined __OpenBSD__
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <sys/sysctl.h>
|
||||||
|
# include <netinet/tcp_timer.h>
|
||||||
|
# include <netinet/tcp_var.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
|
|
@ -186,16 +193,37 @@ namespace fc {
|
||||||
if (setsockopt(my->_sock.native_handle(), IPPROTO_TCP,
|
if (setsockopt(my->_sock.native_handle(), IPPROTO_TCP,
|
||||||
#if defined( __APPLE__ )
|
#if defined( __APPLE__ )
|
||||||
TCP_KEEPALIVE,
|
TCP_KEEPALIVE,
|
||||||
|
#elif defined( __OpenBSD__ )
|
||||||
|
SO_KEEPALIVE,
|
||||||
#else
|
#else
|
||||||
TCP_KEEPIDLE,
|
TCP_KEEPIDLE,
|
||||||
#endif
|
#endif
|
||||||
(char*)&timeout_sec, sizeof(timeout_sec)) < 0)
|
(char*)&timeout_sec, sizeof(timeout_sec)) < 0)
|
||||||
wlog("Error setting TCP keepalive idle time");
|
wlog("Error setting TCP keepalive idle time");
|
||||||
# if !defined(__APPLE__) || defined(TCP_KEEPINTVL) // TCP_KEEPINTVL not defined before 10.9
|
# if defined(__OpenBSD__)
|
||||||
|
int name[4];
|
||||||
|
name[0] = CTL_NET;
|
||||||
|
name[1] = PF_INET;
|
||||||
|
name[2] = IPPROTO_TCP;
|
||||||
|
|
||||||
|
int value;
|
||||||
|
size_t sz;
|
||||||
|
|
||||||
|
// get tics per second
|
||||||
|
name[3] = TCPCTL_SLOWHZ;
|
||||||
|
if (sysctl(name, 4, &value, &sz, NULL, 0) == -1)
|
||||||
|
wlog("Error setting TCP keepalive interval");
|
||||||
|
|
||||||
|
// set interval
|
||||||
|
value *= timeout_sec;
|
||||||
|
name[3] = TCPCTL_KEEPINTVL;
|
||||||
|
if (sysctl(name, 4, NULL, NULL, &value, sizeof(value)) == -1)
|
||||||
|
wlog("Error setting TCP keepalive interval");
|
||||||
|
# elif !defined(__APPLE__) || defined(TCP_KEEPINTVL) // TCP_KEEPINTVL not defined before 10.9
|
||||||
if (setsockopt(my->_sock.native_handle(), IPPROTO_TCP, TCP_KEEPINTVL,
|
if (setsockopt(my->_sock.native_handle(), IPPROTO_TCP, TCP_KEEPINTVL,
|
||||||
(char*)&timeout_sec, sizeof(timeout_sec)) < 0)
|
(char*)&timeout_sec, sizeof(timeout_sec)) < 0)
|
||||||
wlog("Error setting TCP keepalive interval");
|
wlog("Error setting TCP keepalive interval");
|
||||||
# endif // !__APPLE__ || TCP_KEEPINTVL
|
# endif // (__OpenBSD__) or (!__APPLE__ || TCP_KEEPINTVL)
|
||||||
#endif // !WIN32
|
#endif // !WIN32
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
class udp_socket::impl : public fc::retainable {
|
class udp_socket::impl {
|
||||||
public:
|
public:
|
||||||
impl():_sock( fc::asio::default_io_service() ){}
|
impl():_sock( fc::asio::default_io_service() ){}
|
||||||
~impl(){
|
~impl(){
|
||||||
|
|
@ -56,7 +56,7 @@ namespace fc {
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
promise<size_t>::ptr completion_promise(new promise<size_t>("udp_socket::send_to"));
|
promise<size_t>::ptr completion_promise = promise<size_t>::create("udp_socket::send_to");
|
||||||
my->_sock.async_send_to( boost::asio::buffer(buffer, length), to_asio_ep(to),
|
my->_sock.async_send_to( boost::asio::buffer(buffer, length), to_asio_ep(to),
|
||||||
asio::detail::read_write_handler(completion_promise) );
|
asio::detail::read_write_handler(completion_promise) );
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ namespace fc {
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
promise<size_t>::ptr completion_promise(new promise<size_t>("udp_socket::send_to"));
|
promise<size_t>::ptr completion_promise = promise<size_t>::create("udp_socket::send_to");
|
||||||
my->_sock.async_send_to( boost::asio::buffer(buffer.get(), length), to_asio_ep(to),
|
my->_sock.async_send_to( boost::asio::buffer(buffer.get(), length), to_asio_ep(to),
|
||||||
asio::detail::read_write_handler_with_buffer(completion_promise, buffer) );
|
asio::detail::read_write_handler_with_buffer(completion_promise, buffer) );
|
||||||
|
|
||||||
|
|
@ -111,7 +111,7 @@ namespace fc {
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::ip::udp::endpoint boost_from_endpoint;
|
boost::asio::ip::udp::endpoint boost_from_endpoint;
|
||||||
promise<size_t>::ptr completion_promise(new promise<size_t>("udp_socket::receive_from"));
|
promise<size_t>::ptr completion_promise = promise<size_t>::create("udp_socket::receive_from");
|
||||||
my->_sock.async_receive_from( boost::asio::buffer(receive_buffer.get(), receive_buffer_length),
|
my->_sock.async_receive_from( boost::asio::buffer(receive_buffer.get(), receive_buffer_length),
|
||||||
boost_from_endpoint,
|
boost_from_endpoint,
|
||||||
asio::detail::read_write_handler_with_buffer(completion_promise, receive_buffer) );
|
asio::detail::read_write_handler_with_buffer(completion_promise, receive_buffer) );
|
||||||
|
|
@ -137,7 +137,7 @@ namespace fc {
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::ip::udp::endpoint boost_from_endpoint;
|
boost::asio::ip::udp::endpoint boost_from_endpoint;
|
||||||
promise<size_t>::ptr completion_promise(new promise<size_t>("udp_socket::receive_from"));
|
promise<size_t>::ptr completion_promise = promise<size_t>::create("udp_socket::receive_from");
|
||||||
my->_sock.async_receive_from( boost::asio::buffer(receive_buffer, receive_buffer_length), boost_from_endpoint,
|
my->_sock.async_receive_from( boost::asio::buffer(receive_buffer, receive_buffer_length), boost_from_endpoint,
|
||||||
asio::detail::read_write_handler(completion_promise) );
|
asio::detail::read_write_handler(completion_promise) );
|
||||||
size_t bytes_read = completion_promise->wait();
|
size_t bytes_read = completion_promise->wait();
|
||||||
|
|
|
||||||
54
src/popcount.cpp
Normal file
54
src/popcount.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 BitShares Blockchain Foundation, and contributors.
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fc/popcount.hpp>
|
||||||
|
|
||||||
|
namespace fc {
|
||||||
|
|
||||||
|
#if _MSC_VER || __GNUC__ || __clang__
|
||||||
|
#else
|
||||||
|
uint8_t popcount( uint64_t v )
|
||||||
|
{
|
||||||
|
// Public Domain code taken from http://graphics.stanford.edu/~seander/bithacks.html
|
||||||
|
uint8_t c;
|
||||||
|
static const int S[] = {1, 2, 4, 8, 16, 32};
|
||||||
|
static const uint64_t B[] = {0x5555555555555555, 0x3333333333333333, 0x0F0F0F0F0F0F0F0F,
|
||||||
|
0x00FF00FF00FF00FF, 0x0000FFFF0000FFFF, 0x00000000FFFFFFFF };
|
||||||
|
|
||||||
|
c = v - ((v >> 1) & B[0]);
|
||||||
|
c = ((c >> S[1]) & B[1]) + (c & B[1]);
|
||||||
|
c = ((c >> S[2]) + c) & B[2];
|
||||||
|
c = ((c >> S[3]) + c) & B[3];
|
||||||
|
c = ((c >> S[4]) + c) & B[4];
|
||||||
|
return ((c >> S[5]) + c) & B[5];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t popcount( const uint128_t& v )
|
||||||
|
{
|
||||||
|
return popcount( static_cast<uint64_t>(v >> 64) )
|
||||||
|
+ popcount( static_cast<uint64_t>(v & 0xffffffffffffffffULL) );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fc
|
||||||
130
src/real128.cpp
130
src/real128.cpp
|
|
@ -1,130 +0,0 @@
|
||||||
#include <fc/real128.hpp>
|
|
||||||
#include <fc/crypto/bigint.hpp>
|
|
||||||
#include <fc/exception/exception.hpp>
|
|
||||||
#include <sstream>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace fc
|
|
||||||
{
|
|
||||||
uint64_t real128::to_uint64()const
|
|
||||||
{
|
|
||||||
return (fixed/ FC_REAL128_PRECISION).to_uint64();
|
|
||||||
}
|
|
||||||
|
|
||||||
real128::real128( uint64_t integer )
|
|
||||||
{
|
|
||||||
fixed = uint128(integer) * FC_REAL128_PRECISION;
|
|
||||||
}
|
|
||||||
real128& real128::operator += ( const real128& o )
|
|
||||||
{
|
|
||||||
fixed += o.fixed;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
real128& real128::operator -= ( const real128& o )
|
|
||||||
{
|
|
||||||
fixed -= o.fixed;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
real128& real128::operator /= ( const real128& o )
|
|
||||||
{ try {
|
|
||||||
FC_ASSERT( o.fixed > uint128(0), "Divide by Zero" );
|
|
||||||
|
|
||||||
fc::bigint self(fixed);
|
|
||||||
fc::bigint other(o.fixed);
|
|
||||||
self *= FC_REAL128_PRECISION;
|
|
||||||
self /= other;
|
|
||||||
fixed = self;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
} FC_CAPTURE_AND_RETHROW( (*this)(o) ) }
|
|
||||||
|
|
||||||
real128& real128::operator *= ( const real128& o )
|
|
||||||
{ try {
|
|
||||||
fc::bigint self(fixed);
|
|
||||||
fc::bigint other(o.fixed);
|
|
||||||
self *= other;
|
|
||||||
self /= FC_REAL128_PRECISION;
|
|
||||||
fixed = self;
|
|
||||||
return *this;
|
|
||||||
} FC_CAPTURE_AND_RETHROW( (*this)(o) ) }
|
|
||||||
|
|
||||||
|
|
||||||
real128::real128( const std::string& ratio_str )
|
|
||||||
{
|
|
||||||
const char* c = ratio_str.c_str();
|
|
||||||
int digit = *c - '0';
|
|
||||||
if (digit >= 0 && digit <= 9)
|
|
||||||
{
|
|
||||||
uint64_t int_part = digit;
|
|
||||||
++c;
|
|
||||||
digit = *c - '0';
|
|
||||||
while (digit >= 0 && digit <= 9)
|
|
||||||
{
|
|
||||||
int_part = int_part * 10 + digit;
|
|
||||||
++c;
|
|
||||||
digit = *c - '0';
|
|
||||||
}
|
|
||||||
*this = real128(int_part);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if the string doesn't look like "123.45" or ".45", this code isn't designed to parse it correctly
|
|
||||||
// in particular, we don't try to handle leading whitespace or '+'/'-' indicators at the beginning
|
|
||||||
assert(*c == '.');
|
|
||||||
fixed = fc::uint128();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (*c == '.')
|
|
||||||
{
|
|
||||||
c++;
|
|
||||||
digit = *c - '0';
|
|
||||||
if (digit >= 0 && digit <= 9)
|
|
||||||
{
|
|
||||||
int64_t frac_part = digit;
|
|
||||||
int64_t frac_magnitude = 10;
|
|
||||||
++c;
|
|
||||||
digit = *c - '0';
|
|
||||||
while (digit >= 0 && digit <= 9)
|
|
||||||
{
|
|
||||||
frac_part = frac_part * 10 + digit;
|
|
||||||
frac_magnitude *= 10;
|
|
||||||
++c;
|
|
||||||
digit = *c - '0';
|
|
||||||
}
|
|
||||||
*this += real128( frac_part ) / real128( frac_magnitude );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
real128::operator std::string()const
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << std::string(fixed / FC_REAL128_PRECISION);
|
|
||||||
ss << '.';
|
|
||||||
auto frac = (fixed % FC_REAL128_PRECISION) + FC_REAL128_PRECISION;
|
|
||||||
ss << std::string( frac ).substr(1);
|
|
||||||
|
|
||||||
auto number = ss.str();
|
|
||||||
while( number.back() == '0' ) number.pop_back();
|
|
||||||
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
real128 real128::from_fixed( const uint128& fixed )
|
|
||||||
{
|
|
||||||
real128 result;
|
|
||||||
result.fixed = fixed;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void to_variant( const real128& var, variant& vo, uint32_t max_depth )
|
|
||||||
{
|
|
||||||
vo = std::string(var);
|
|
||||||
}
|
|
||||||
void from_variant( const variant& var, real128& vo, uint32_t max_depth )
|
|
||||||
{
|
|
||||||
vo = real128(var.as_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fc
|
|
||||||
|
|
@ -1,141 +0,0 @@
|
||||||
|
|
||||||
#include <fc/rpc/http_api.hpp>
|
|
||||||
|
|
||||||
namespace fc { namespace rpc {
|
|
||||||
|
|
||||||
http_api_connection::~http_api_connection()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
http_api_connection::http_api_connection(uint32_t max_depth)
|
|
||||||
:api_connection(max_depth)
|
|
||||||
{
|
|
||||||
_rpc_state.add_method( "call", [this]( const variants& args ) -> variant
|
|
||||||
{
|
|
||||||
// TODO: This logic is duplicated between http_api_connection and websocket_api_connection
|
|
||||||
// it should be consolidated into one place instead of copy-pasted
|
|
||||||
FC_ASSERT( args.size() == 3 && args[2].is_array() );
|
|
||||||
api_id_type api_id;
|
|
||||||
if( args[0].is_string() )
|
|
||||||
{
|
|
||||||
variant subresult = this->receive_call( 1, args[0].as_string() );
|
|
||||||
api_id = subresult.as_uint64();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
api_id = args[0].as_uint64();
|
|
||||||
|
|
||||||
return this->receive_call(
|
|
||||||
api_id,
|
|
||||||
args[1].as_string(),
|
|
||||||
args[2].get_array() );
|
|
||||||
} );
|
|
||||||
|
|
||||||
_rpc_state.add_method( "notice", [this]( const variants& args ) -> variant
|
|
||||||
{
|
|
||||||
FC_ASSERT( args.size() == 2 && args[1].is_array() );
|
|
||||||
this->receive_notice(
|
|
||||||
args[0].as_uint64(),
|
|
||||||
args[1].get_array() );
|
|
||||||
return variant();
|
|
||||||
} );
|
|
||||||
|
|
||||||
_rpc_state.add_method( "callback", [this]( const variants& args ) -> variant
|
|
||||||
{
|
|
||||||
FC_ASSERT( args.size() == 2 && args[1].is_array() );
|
|
||||||
this->receive_callback(
|
|
||||||
args[0].as_uint64(),
|
|
||||||
args[1].get_array() );
|
|
||||||
return variant();
|
|
||||||
} );
|
|
||||||
|
|
||||||
_rpc_state.on_unhandled( [&]( const std::string& method_name, const variants& args )
|
|
||||||
{
|
|
||||||
return this->receive_call( 0, method_name, args );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
variant http_api_connection::send_call(
|
|
||||||
api_id_type api_id,
|
|
||||||
string method_name,
|
|
||||||
variants args /* = variants() */ )
|
|
||||||
{
|
|
||||||
// HTTP has no way to do this, so do nothing
|
|
||||||
return variant();
|
|
||||||
}
|
|
||||||
|
|
||||||
variant http_api_connection::send_callback(
|
|
||||||
uint64_t callback_id,
|
|
||||||
variants args /* = variants() */ )
|
|
||||||
{
|
|
||||||
// HTTP has no way to do this, so do nothing
|
|
||||||
return variant();
|
|
||||||
}
|
|
||||||
|
|
||||||
void http_api_connection::send_notice(
|
|
||||||
uint64_t callback_id,
|
|
||||||
variants args /* = variants() */ )
|
|
||||||
{
|
|
||||||
// HTTP has no way to do this, so do nothing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void http_api_connection::on_request( const fc::http::request& req, const fc::http::server::response& resp )
|
|
||||||
{
|
|
||||||
// this must be called by outside HTTP server's on_request method
|
|
||||||
std::string resp_body;
|
|
||||||
http::reply::status_code resp_status;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
resp.add_header( "Content-Type", "application/json" );
|
|
||||||
std::string req_body( req.body.begin(), req.body.end() );
|
|
||||||
auto var = fc::json::from_string( req_body, fc::json::legacy_parser, _max_conversion_depth );
|
|
||||||
const auto& var_obj = var.get_object();
|
|
||||||
|
|
||||||
if( var_obj.contains( "method" ) )
|
|
||||||
{
|
|
||||||
auto call = var.as<fc::rpc::request>(_max_conversion_depth);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fc::variant result( _rpc_state.local_call( call.method, call.params ), _max_conversion_depth );
|
|
||||||
resp_body = fc::json::to_string( fc::variant( fc::rpc::response( *call.id, result ), _max_conversion_depth),
|
|
||||||
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth );
|
|
||||||
resp_status = http::reply::OK;
|
|
||||||
}
|
|
||||||
FC_CAPTURE_AND_RETHROW( (call.method)(call.params) );
|
|
||||||
}
|
|
||||||
catch ( const fc::exception& e )
|
|
||||||
{
|
|
||||||
resp_body = fc::json::to_string( fc::variant( fc::rpc::response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(e, _max_conversion_depth)} ), _max_conversion_depth),
|
|
||||||
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth );
|
|
||||||
resp_status = http::reply::InternalServerError;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
resp_status = http::reply::BadRequest;
|
|
||||||
resp_body = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch ( const fc::exception& e )
|
|
||||||
{
|
|
||||||
resp_status = http::reply::InternalServerError;
|
|
||||||
resp_body = "";
|
|
||||||
wdump((e.to_detail_string()));
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
resp.set_status( resp_status );
|
|
||||||
resp.set_length( resp_body.length() );
|
|
||||||
resp.write( resp_body.c_str(), resp_body.length() );
|
|
||||||
}
|
|
||||||
catch( const fc::exception& e )
|
|
||||||
{
|
|
||||||
wdump((e.to_detail_string()));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
} } // namespace fc::rpc
|
|
||||||
|
|
@ -46,7 +46,7 @@ void state::handle_reply( const response& response )
|
||||||
request state::start_remote_call( const string& method_name, variants args )
|
request state::start_remote_call( const string& method_name, variants args )
|
||||||
{
|
{
|
||||||
request request{ _next_id++, method_name, std::move(args) };
|
request request{ _next_id++, method_name, std::move(args) };
|
||||||
_awaiting[*request.id] = fc::promise<variant>::ptr( new fc::promise<variant>("json_connection::async_call") );
|
_awaiting[*request.id] = fc::promise<variant>::create("json_connection::async_call");
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
variant state::wait_for_response( const variant& request_id )
|
variant state::wait_for_response( const variant& request_id )
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,10 @@ websocket_api_connection::websocket_api_connection( const std::shared_ptr<fc::ht
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} );
|
} );
|
||||||
_connection->closed.connect( [this](){ closed(); } );
|
_connection->closed.connect( [this](){
|
||||||
|
closed();
|
||||||
|
_connection = nullptr;
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
variant websocket_api_connection::send_call(
|
variant websocket_api_connection::send_call(
|
||||||
|
|
@ -218,7 +221,8 @@ response websocket_api_connection::on_request( const variant& var )
|
||||||
catch ( const fc::exception& e )
|
catch ( const fc::exception& e )
|
||||||
{
|
{
|
||||||
if( has_id )
|
if( has_id )
|
||||||
return response( call.id, error_object{ e.code(), "Execution error", variant( e, _max_conversion_depth ) },
|
return response( call.id, error_object{ e.code(), "Execution error: " + e.to_string(),
|
||||||
|
variant( e, _max_conversion_depth ) },
|
||||||
call.jsonrpc );
|
call.jsonrpc );
|
||||||
}
|
}
|
||||||
catch ( const std::exception& e )
|
catch ( const std::exception& e )
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
#include <fc/shared_ptr.hpp>
|
|
||||||
#include <boost/atomic.hpp>
|
|
||||||
#include <boost/memory_order.hpp>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
namespace fc {
|
|
||||||
retainable::retainable()
|
|
||||||
:_ref_count(1) {
|
|
||||||
static_assert( sizeof(_ref_count) == sizeof(boost::atomic<int32_t>), "failed to reserve enough space" );
|
|
||||||
}
|
|
||||||
|
|
||||||
retainable::~retainable() {
|
|
||||||
assert( _ref_count <= 0 );
|
|
||||||
assert( _ref_count == 0 );
|
|
||||||
}
|
|
||||||
void retainable::retain() {
|
|
||||||
((boost::atomic<int32_t>*)&_ref_count)->fetch_add(1, boost::memory_order_relaxed );
|
|
||||||
}
|
|
||||||
|
|
||||||
void retainable::release() {
|
|
||||||
boost::atomic_thread_fence(boost::memory_order_acquire);
|
|
||||||
if( 1 == ((boost::atomic<int32_t>*)&_ref_count)->fetch_sub(1, boost::memory_order_release ) ) {
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t retainable::retain_count()const {
|
|
||||||
return _ref_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -8,6 +8,9 @@
|
||||||
#if BOOST_VERSION / 100 >= 1065 && !defined(__APPLE__)
|
#if BOOST_VERSION / 100 >= 1065 && !defined(__APPLE__)
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <fc/log/logger.hpp>
|
#include <fc/log/logger.hpp>
|
||||||
|
#if defined(__OpenBSD__)
|
||||||
|
#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
|
||||||
|
#endif
|
||||||
#include <boost/stacktrace.hpp>
|
#include <boost/stacktrace.hpp>
|
||||||
|
|
||||||
namespace fc
|
namespace fc
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@
|
||||||
namespace bc = boost::context::detail;
|
namespace bc = boost::context::detail;
|
||||||
namespace bco = boost::coroutines;
|
namespace bco = boost::coroutines;
|
||||||
typedef bco::stack_allocator stack_allocator;
|
typedef bco::stack_allocator stack_allocator;
|
||||||
#elif BOOST_VERSION >= 105400
|
#else
|
||||||
# include <boost/coroutine/stack_context.hpp>
|
# include <boost/coroutine/stack_context.hpp>
|
||||||
namespace bc = boost::context;
|
namespace bc = boost::context;
|
||||||
namespace bco = boost::coroutines;
|
namespace bco = boost::coroutines;
|
||||||
# if BOOST_VERSION >= 105600 && !defined(NDEBUG)
|
# if !defined(NDEBUG)
|
||||||
# include <boost/assert.hpp>
|
# include <boost/assert.hpp>
|
||||||
# include <boost/coroutine/protected_stack_allocator.hpp>
|
# include <boost/coroutine/protected_stack_allocator.hpp>
|
||||||
typedef bco::protected_stack_allocator stack_allocator;
|
typedef bco::protected_stack_allocator stack_allocator;
|
||||||
|
|
@ -32,16 +32,7 @@
|
||||||
typedef bco::stack_allocator stack_allocator;
|
typedef bco::stack_allocator stack_allocator;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#elif BOOST_VERSION >= 105300
|
#endif // BOOST_VERSION >= 106100
|
||||||
#include <boost/coroutine/stack_allocator.hpp>
|
|
||||||
namespace bc = boost::context;
|
|
||||||
namespace bco = boost::coroutines;
|
|
||||||
#elif BOOST_VERSION >= 105200
|
|
||||||
namespace bc = boost::context;
|
|
||||||
#else
|
|
||||||
namespace bc = boost::ctx;
|
|
||||||
namespace bco = boost::coroutine;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
class thread;
|
class thread;
|
||||||
|
|
@ -55,10 +46,7 @@ namespace fc {
|
||||||
*/
|
*/
|
||||||
struct context {
|
struct context {
|
||||||
typedef fc::context* ptr;
|
typedef fc::context* ptr;
|
||||||
|
|
||||||
#if BOOST_VERSION >= 105400
|
|
||||||
bco::stack_context stack_ctx;
|
bco::stack_context stack_ctx;
|
||||||
#endif
|
|
||||||
|
|
||||||
#if BOOST_VERSION >= 106100
|
#if BOOST_VERSION >= 106100
|
||||||
using context_fn = void (*)(bc::transfer_t);
|
using context_fn = void (*)(bc::transfer_t);
|
||||||
|
|
@ -81,32 +69,13 @@ namespace fc {
|
||||||
cur_task(0),
|
cur_task(0),
|
||||||
context_posted_num(0)
|
context_posted_num(0)
|
||||||
{
|
{
|
||||||
#if BOOST_VERSION >= 105600
|
|
||||||
size_t stack_size = FC_CONTEXT_STACK_SIZE;
|
size_t stack_size = FC_CONTEXT_STACK_SIZE;
|
||||||
alloc.allocate(stack_ctx, stack_size);
|
alloc.allocate(stack_ctx, stack_size);
|
||||||
my_context = bc::make_fcontext( stack_ctx.sp, stack_ctx.size, sf);
|
my_context = bc::make_fcontext( stack_ctx.sp, stack_ctx.size, sf);
|
||||||
#elif BOOST_VERSION >= 105400
|
|
||||||
size_t stack_size = FC_CONTEXT_STACK_SIZE;
|
|
||||||
alloc.allocate(stack_ctx, stack_size);
|
|
||||||
my_context = bc::make_fcontext( stack_ctx.sp, stack_ctx.size, sf);
|
|
||||||
#elif BOOST_VERSION >= 105300
|
|
||||||
size_t stack_size = FC_CONTEXT_STACK_SIZE;
|
|
||||||
void* stackptr = alloc.allocate(stack_size);
|
|
||||||
my_context = bc::make_fcontext( stackptr, stack_size, sf);
|
|
||||||
#else
|
|
||||||
size_t stack_size = FC_CONTEXT_STACK_SIZE;
|
|
||||||
my_context.fc_stack.base = alloc.allocate( stack_size );
|
|
||||||
my_context.fc_stack.limit = static_cast<char*>( my_context.fc_stack.base) - stack_size;
|
|
||||||
make_fcontext( &my_context, sf );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context( fc::thread* t) :
|
context( fc::thread* t) :
|
||||||
#if BOOST_VERSION >= 105600
|
|
||||||
my_context(nullptr),
|
my_context(nullptr),
|
||||||
#elif BOOST_VERSION >= 105300
|
|
||||||
my_context(new bc::fcontext_t),
|
|
||||||
#endif
|
|
||||||
caller_context(0),
|
caller_context(0),
|
||||||
stack_alloc(0),
|
stack_alloc(0),
|
||||||
next_blocked(0),
|
next_blocked(0),
|
||||||
|
|
@ -123,23 +92,8 @@ namespace fc {
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~context() {
|
~context() {
|
||||||
#if BOOST_VERSION >= 105600
|
|
||||||
if(stack_alloc)
|
if(stack_alloc)
|
||||||
stack_alloc->deallocate( stack_ctx );
|
stack_alloc->deallocate( stack_ctx );
|
||||||
#elif BOOST_VERSION >= 105400
|
|
||||||
if(stack_alloc)
|
|
||||||
stack_alloc->deallocate( stack_ctx );
|
|
||||||
else
|
|
||||||
delete my_context;
|
|
||||||
#elif BOOST_VERSION >= 105300
|
|
||||||
if(stack_alloc)
|
|
||||||
stack_alloc->deallocate( my_context->fc_stack.sp, FC_CONTEXT_STACK_SIZE);
|
|
||||||
else
|
|
||||||
delete my_context;
|
|
||||||
#else
|
|
||||||
if(stack_alloc)
|
|
||||||
stack_alloc->deallocate( my_context.fc_stack.base, FC_CONTEXT_STACK_SIZE );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reinitialize()
|
void reinitialize()
|
||||||
|
|
@ -225,13 +179,7 @@ namespace fc {
|
||||||
|
|
||||||
bool is_complete()const { return complete; }
|
bool is_complete()const { return complete; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if BOOST_VERSION >= 105300 && BOOST_VERSION < 105600
|
|
||||||
bc::fcontext_t* my_context;
|
|
||||||
#else
|
|
||||||
bc::fcontext_t my_context;
|
bc::fcontext_t my_context;
|
||||||
#endif
|
|
||||||
fc::context* caller_context;
|
fc::context* caller_context;
|
||||||
stack_allocator* stack_alloc;
|
stack_allocator* stack_alloc;
|
||||||
priority prio;
|
priority prio;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
|
|
||||||
promise_base::promise_base( const char* desc )
|
promise_base::promise_base( const char* desc )
|
||||||
|
|
@ -22,6 +21,8 @@ namespace fc {
|
||||||
_compl(nullptr)
|
_compl(nullptr)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
promise_base::~promise_base() { }
|
||||||
|
|
||||||
const char* promise_base::get_desc()const{
|
const char* promise_base::get_desc()const{
|
||||||
return _desc;
|
return _desc;
|
||||||
}
|
}
|
||||||
|
|
@ -34,16 +35,14 @@ namespace fc {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
bool promise_base::ready()const {
|
bool promise_base::ready()const {
|
||||||
return _ready;
|
return _ready.load();
|
||||||
}
|
}
|
||||||
bool promise_base::error()const {
|
bool promise_base::error()const {
|
||||||
{ synchronized(_spin_yield)
|
return std::atomic_load( &_exceptp ) != nullptr;
|
||||||
return _exceptp != nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void promise_base::set_exception( const fc::exception_ptr& e ){
|
void promise_base::set_exception( const fc::exception_ptr& e ){
|
||||||
_exceptp = e;
|
std::atomic_store( &_exceptp, e );
|
||||||
_set_value(nullptr);
|
_set_value(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,16 +53,21 @@ namespace fc {
|
||||||
_wait_until( time_point::now() + timeout_us );
|
_wait_until( time_point::now() + timeout_us );
|
||||||
}
|
}
|
||||||
void promise_base::_wait_until( const time_point& timeout_us ){
|
void promise_base::_wait_until( const time_point& timeout_us ){
|
||||||
{ synchronized(_spin_yield)
|
if( _ready.load() ) {
|
||||||
if( _ready ) {
|
fc::exception_ptr ex = std::atomic_load( &_exceptp );
|
||||||
if( _exceptp )
|
if( ex )
|
||||||
_exceptp->dynamic_rethrow_exception();
|
ex->dynamic_rethrow_exception();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_enqueue_thread();
|
_enqueue_thread();
|
||||||
|
// Need to check _ready again to avoid a race condition.
|
||||||
|
if( _ready.load() )
|
||||||
|
{
|
||||||
|
_dequeue_thread();
|
||||||
|
return _wait_until( timeout_us ); // this will simply return or throw _exceptp
|
||||||
}
|
}
|
||||||
std::exception_ptr e;
|
|
||||||
|
|
||||||
|
std::exception_ptr e;
|
||||||
//
|
//
|
||||||
// Create shared_ptr to take ownership of this; i.e. this will
|
// Create shared_ptr to take ownership of this; i.e. this will
|
||||||
// be deleted when p_this goes out of scope. Consequently,
|
// be deleted when p_this goes out of scope. Consequently,
|
||||||
|
|
@ -71,9 +75,7 @@ namespace fc {
|
||||||
// before we're done reading/writing instance variables!
|
// before we're done reading/writing instance variables!
|
||||||
// See https://github.com/cryptonomex/graphene/issues/597
|
// See https://github.com/cryptonomex/graphene/issues/597
|
||||||
//
|
//
|
||||||
|
ptr p_this = shared_from_this();
|
||||||
ptr p_this = ptr( this, true );
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
|
@ -94,61 +96,45 @@ namespace fc {
|
||||||
|
|
||||||
if( e ) std::rethrow_exception(e);
|
if( e ) std::rethrow_exception(e);
|
||||||
|
|
||||||
if( _ready )
|
if( _ready.load() ) return _wait_until( timeout_us ); // this will simply return or throw _exceptp
|
||||||
{
|
|
||||||
if( _exceptp )
|
|
||||||
_exceptp->dynamic_rethrow_exception();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
FC_THROW_EXCEPTION( timeout_exception, "" );
|
FC_THROW_EXCEPTION( timeout_exception, "" );
|
||||||
}
|
}
|
||||||
void promise_base::_enqueue_thread(){
|
void promise_base::_enqueue_thread(){
|
||||||
++_blocked_fiber_count;
|
_blocked_fiber_count.fetch_add( 1 );
|
||||||
|
thread* blocked_thread = _blocked_thread.load();
|
||||||
// only one thread can wait on a promise at any given time
|
// only one thread can wait on a promise at any given time
|
||||||
assert(!_blocked_thread ||
|
do
|
||||||
_blocked_thread == &thread::current());
|
assert( !blocked_thread || blocked_thread == &thread::current() );
|
||||||
_blocked_thread = &thread::current();
|
while( !_blocked_thread.compare_exchange_weak( blocked_thread, &thread::current() ) );
|
||||||
}
|
}
|
||||||
void promise_base::_dequeue_thread(){
|
void promise_base::_dequeue_thread(){
|
||||||
synchronized(_spin_yield)
|
if( _blocked_fiber_count.fetch_add( -1 ) == 1 )
|
||||||
if (!--_blocked_fiber_count)
|
_blocked_thread.store( nullptr );
|
||||||
_blocked_thread = nullptr;
|
|
||||||
}
|
}
|
||||||
void promise_base::_notify(){
|
void promise_base::_notify(){
|
||||||
// copy _blocked_thread into a local so that if the thread unblocks (e.g.,
|
// copy _blocked_thread into a local so that if the thread unblocks (e.g.,
|
||||||
// because of a timeout) before we get a chance to notify it, we won't be
|
// because of a timeout) before we get a chance to notify it, we won't be
|
||||||
// calling notify on a null pointer
|
// calling notify on a null pointer
|
||||||
thread* blocked_thread;
|
thread* blocked_thread = _blocked_thread.load();
|
||||||
{ synchronized(_spin_yield)
|
|
||||||
blocked_thread = _blocked_thread;
|
|
||||||
}
|
|
||||||
if( blocked_thread )
|
if( blocked_thread )
|
||||||
blocked_thread->notify(ptr(this,true));
|
blocked_thread->notify( shared_from_this() );
|
||||||
}
|
|
||||||
promise_base::~promise_base() { }
|
|
||||||
void promise_base::_set_timeout(){
|
|
||||||
if( _ready )
|
|
||||||
return;
|
|
||||||
set_exception( std::make_shared<fc::timeout_exception>() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void promise_base::_set_value(const void* s){
|
void promise_base::_set_value(const void* s){
|
||||||
// slog( "%p == %d", &_ready, int(_ready));
|
bool ready = false;
|
||||||
// BOOST_ASSERT( !_ready );
|
if( !_ready.compare_exchange_strong( ready, true ) ) //don't allow promise to be set more than once
|
||||||
{ synchronized(_spin_yield)
|
|
||||||
if (_ready) //don't allow promise to be set more than once
|
|
||||||
return;
|
return;
|
||||||
_ready = true;
|
_notify();
|
||||||
}
|
auto* hdl = _compl.load();
|
||||||
_notify();
|
if( nullptr != hdl )
|
||||||
if( nullptr != _compl ) {
|
hdl->on_complete( s, std::atomic_load( &_exceptp ) );
|
||||||
_compl->on_complete(s,_exceptp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void promise_base::_on_complete( detail::completion_handler* c ) {
|
void promise_base::_on_complete( detail::completion_handler* c ) {
|
||||||
{ synchronized(_spin_yield)
|
auto* hdl = _compl.load();
|
||||||
delete _compl;
|
while( !_compl.compare_exchange_weak( hdl, c ) );
|
||||||
_compl = c;
|
delete hdl;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -158,8 +158,8 @@ namespace fc {
|
||||||
|
|
||||||
serial_valve::ticket_guard::ticket_guard( boost::atomic<future<void>*>& latch )
|
serial_valve::ticket_guard::ticket_guard( boost::atomic<future<void>*>& latch )
|
||||||
{
|
{
|
||||||
my_promise = new promise<void>();
|
my_promise = promise<void>::create();
|
||||||
future<void>* my_future = new future<void>( promise<void>::ptr( my_promise, true ) );
|
future<void>* my_future = new future<void>( my_promise );
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
|
|
@ -171,7 +171,7 @@ namespace fc {
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
delete my_future; // this takes care of my_promise as well
|
delete my_future;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -190,7 +190,7 @@ namespace fc {
|
||||||
|
|
||||||
serial_valve::serial_valve()
|
serial_valve::serial_valve()
|
||||||
{
|
{
|
||||||
latch.store( new future<void>( promise<void>::ptr( new promise<void>( true ), true ) ) );
|
latch.store( new future<void>( promise<void>::create( true ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
serial_valve::~serial_valve()
|
serial_valve::~serial_valve()
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ namespace fc {
|
||||||
_next(nullptr),
|
_next(nullptr),
|
||||||
_task_specific_data(nullptr),
|
_task_specific_data(nullptr),
|
||||||
_promise_impl(nullptr),
|
_promise_impl(nullptr),
|
||||||
_functor(func){
|
_functor(func),
|
||||||
|
_retain_count(0){
|
||||||
}
|
}
|
||||||
|
|
||||||
void task_base::run() {
|
void task_base::run() {
|
||||||
|
|
@ -101,4 +102,12 @@ namespace fc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void task_base::retain() {
|
||||||
|
if( _retain_count.fetch_add(1, boost::memory_order_relaxed) == 0 )
|
||||||
|
_self = shared_from_this();
|
||||||
|
}
|
||||||
|
void task_base::release() {
|
||||||
|
if( _retain_count.fetch_sub(1, boost::memory_order_release) == 1 )
|
||||||
|
_self.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ namespace fc {
|
||||||
}
|
}
|
||||||
|
|
||||||
thread::thread( const std::string& name, thread_idle_notifier* notifier ) {
|
thread::thread( const std::string& name, thread_idle_notifier* notifier ) {
|
||||||
promise<void>::ptr p(new promise<void>("thread start"));
|
promise<void>::ptr p = promise<void>::create("thread start");
|
||||||
boost::thread* t = new boost::thread( [this,p,name,notifier]() {
|
boost::thread* t = new boost::thread( [this,p,name,notifier]() {
|
||||||
try {
|
try {
|
||||||
set_thread_name(name.c_str()); // set thread's name for the debugger to display
|
set_thread_name(name.c_str()); // set thread's name for the debugger to display
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
#include <fc/thread/thread.hpp>
|
#include <fc/thread/thread.hpp>
|
||||||
|
#include <fc/stacktrace.hpp>
|
||||||
#include <fc/time.hpp>
|
#include <fc/time.hpp>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
#include "context.hpp"
|
#include "context.hpp"
|
||||||
#include <boost/thread/condition_variable.hpp>
|
#include <boost/thread/condition_variable.hpp>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
#include <boost/atomic.hpp>
|
#include <boost/atomic.hpp>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
//#include <fc/logger.hpp>
|
|
||||||
|
|
||||||
namespace fc {
|
namespace fc {
|
||||||
struct sleep_priority_less {
|
struct sleep_priority_less {
|
||||||
|
|
@ -335,7 +337,7 @@ namespace fc {
|
||||||
if( (*task_itr)->canceled() )
|
if( (*task_itr)->canceled() )
|
||||||
{
|
{
|
||||||
(*task_itr)->run();
|
(*task_itr)->run();
|
||||||
(*task_itr)->release();
|
(*task_itr)->release(); // HERE BE DRAGONS
|
||||||
task_itr = task_sch_queue.erase(task_itr);
|
task_itr = task_sch_queue.erase(task_itr);
|
||||||
canceled_task = true;
|
canceled_task = true;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -390,7 +392,14 @@ namespace fc {
|
||||||
/* NB: At least on Win64, this only catches a yield while in the body of
|
/* NB: At least on Win64, this only catches a yield while in the body of
|
||||||
* a catch block; it fails to catch a yield while unwinding the stack, which
|
* a catch block; it fails to catch a yield while unwinding the stack, which
|
||||||
* is probably just as likely to cause crashes */
|
* is probably just as likely to cause crashes */
|
||||||
assert(std::current_exception() == std::exception_ptr());
|
if( std::current_exception() != std::exception_ptr() )
|
||||||
|
{
|
||||||
|
std::stringstream stacktrace;
|
||||||
|
print_stacktrace( stacktrace );
|
||||||
|
elog( "Thread ${name} yielded in exception handler!\n${trace}",
|
||||||
|
("name",thread::current().name())("trace",stacktrace.str()) );
|
||||||
|
assert( std::current_exception() == std::exception_ptr() );
|
||||||
|
}
|
||||||
|
|
||||||
check_for_timeouts();
|
check_for_timeouts();
|
||||||
if( !current )
|
if( !current )
|
||||||
|
|
@ -424,12 +433,8 @@ namespace fc {
|
||||||
auto p = context_pair{nullptr, prev};
|
auto p = context_pair{nullptr, prev};
|
||||||
auto t = bc::jump_fcontext( next->my_context, &p );
|
auto t = bc::jump_fcontext( next->my_context, &p );
|
||||||
static_cast<context_pair*>(t.data)->second->my_context = t.fctx;
|
static_cast<context_pair*>(t.data)->second->my_context = t.fctx;
|
||||||
#elif BOOST_VERSION >= 105600
|
|
||||||
bc::jump_fcontext( &prev->my_context, next->my_context, 0 );
|
|
||||||
#elif BOOST_VERSION >= 105300
|
|
||||||
bc::jump_fcontext( prev->my_context, next->my_context, 0 );
|
|
||||||
#else
|
#else
|
||||||
bc::jump_fcontext( &prev->my_context, &next->my_context, 0 );
|
bc::jump_fcontext( &prev->my_context, next->my_context, 0 );
|
||||||
#endif
|
#endif
|
||||||
BOOST_ASSERT( current );
|
BOOST_ASSERT( current );
|
||||||
BOOST_ASSERT( current == prev );
|
BOOST_ASSERT( current == prev );
|
||||||
|
|
@ -470,12 +475,8 @@ namespace fc {
|
||||||
auto p = context_pair{this, prev};
|
auto p = context_pair{this, prev};
|
||||||
auto t = bc::jump_fcontext( next->my_context, &p );
|
auto t = bc::jump_fcontext( next->my_context, &p );
|
||||||
static_cast<context_pair*>(t.data)->second->my_context = t.fctx;
|
static_cast<context_pair*>(t.data)->second->my_context = t.fctx;
|
||||||
#elif BOOST_VERSION >= 105600
|
|
||||||
bc::jump_fcontext( &prev->my_context, next->my_context, (intptr_t)this );
|
|
||||||
#elif BOOST_VERSION >= 105300
|
|
||||||
bc::jump_fcontext( prev->my_context, next->my_context, (intptr_t)this );
|
|
||||||
#else
|
#else
|
||||||
bc::jump_fcontext( &prev->my_context, &next->my_context, (intptr_t)this );
|
bc::jump_fcontext( &prev->my_context, next->my_context, (intptr_t)this );
|
||||||
#endif
|
#endif
|
||||||
BOOST_ASSERT( current );
|
BOOST_ASSERT( current );
|
||||||
BOOST_ASSERT( current == prev );
|
BOOST_ASSERT( current == prev );
|
||||||
|
|
@ -531,10 +532,10 @@ namespace fc {
|
||||||
|
|
||||||
next->_set_active_context( current );
|
next->_set_active_context( current );
|
||||||
current->cur_task = next;
|
current->cur_task = next;
|
||||||
fc::shared_ptr<task_base> next_ptr(next);
|
next->run();
|
||||||
next_ptr->run();
|
current->cur_task = nullptr;
|
||||||
current->cur_task = 0;
|
next->_set_active_context(nullptr);
|
||||||
next_ptr->_set_active_context(0);
|
next->release(); // HERE BE DRAGONS
|
||||||
current->reinitialize();
|
current->reinitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
398
src/uint128.cpp
398
src/uint128.cpp
|
|
@ -1,398 +0,0 @@
|
||||||
#include <fc/uint128.hpp>
|
|
||||||
#include <fc/variant.hpp>
|
|
||||||
#include <fc/crypto/bigint.hpp>
|
|
||||||
#include <boost/endian/buffers.hpp>
|
|
||||||
#include <boost/multiprecision/cpp_int.hpp>
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace fc
|
|
||||||
{
|
|
||||||
typedef boost::multiprecision::uint128_t m128;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static void divide(const T &numerator, const T &denominator, T "ient, T &remainder)
|
|
||||||
{
|
|
||||||
static const int bits = sizeof(T) * 8;
|
|
||||||
|
|
||||||
if(denominator == 0) {
|
|
||||||
throw std::domain_error("divide by zero");
|
|
||||||
} else {
|
|
||||||
T n = numerator;
|
|
||||||
T d = denominator;
|
|
||||||
T x = 1;
|
|
||||||
T answer = 0;
|
|
||||||
|
|
||||||
|
|
||||||
while((n >= d) && (((d >> (bits - 1)) & 1) == 0)) {
|
|
||||||
x <<= 1;
|
|
||||||
d <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(x != 0) {
|
|
||||||
if(n >= d) {
|
|
||||||
n -= d;
|
|
||||||
answer |= x;
|
|
||||||
}
|
|
||||||
|
|
||||||
x >>= 1;
|
|
||||||
d >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
quotient = answer;
|
|
||||||
remainder = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint128::uint128(const std::string &sz)
|
|
||||||
:hi(0), lo(0)
|
|
||||||
{
|
|
||||||
// do we have at least one character?
|
|
||||||
if(!sz.empty()) {
|
|
||||||
// make some reasonable assumptions
|
|
||||||
int radix = 10;
|
|
||||||
bool minus = false;
|
|
||||||
|
|
||||||
std::string::const_iterator i = sz.begin();
|
|
||||||
|
|
||||||
// check for minus sign, i suppose technically this should only apply
|
|
||||||
// to base 10, but who says that -0x1 should be invalid?
|
|
||||||
if(*i == '-') {
|
|
||||||
++i;
|
|
||||||
minus = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if there is radix changing prefix (0 or 0x)
|
|
||||||
if(i != sz.end()) {
|
|
||||||
if(*i == '0') {
|
|
||||||
radix = 8;
|
|
||||||
++i;
|
|
||||||
if(i != sz.end()) {
|
|
||||||
if(*i == 'x') {
|
|
||||||
radix = 16;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while(i != sz.end()) {
|
|
||||||
unsigned int n = 0;
|
|
||||||
const char ch = *i;
|
|
||||||
|
|
||||||
if(ch >= 'A' && ch <= 'Z') {
|
|
||||||
if(((ch - 'A') + 10) < radix) {
|
|
||||||
n = (ch - 'A') + 10;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if(ch >= 'a' && ch <= 'z') {
|
|
||||||
if(((ch - 'a') + 10) < radix) {
|
|
||||||
n = (ch - 'a') + 10;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if(ch >= '0' && ch <= '9') {
|
|
||||||
if((ch - '0') < radix) {
|
|
||||||
n = (ch - '0');
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* completely invalid character */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*this) *= radix;
|
|
||||||
(*this) += n;
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this was a negative number, do that two's compliment madness :-P
|
|
||||||
if(minus) {
|
|
||||||
*this = -*this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint128::operator bigint()const
|
|
||||||
{
|
|
||||||
boost::endian::big_uint64_buf_t tmp[2];
|
|
||||||
tmp[0] = hi;
|
|
||||||
tmp[1] = lo;
|
|
||||||
bigint bi( (char*)&tmp, sizeof(tmp) );
|
|
||||||
return bi;
|
|
||||||
}
|
|
||||||
uint128::uint128( const fc::bigint& bi )
|
|
||||||
{
|
|
||||||
*this = uint128( std::string(bi) ); // TODO: optimize this...
|
|
||||||
}
|
|
||||||
|
|
||||||
uint128::operator std::string ()const
|
|
||||||
{
|
|
||||||
if(*this == 0) { return "0"; }
|
|
||||||
|
|
||||||
// at worst it will be size digits (base 2) so make our buffer
|
|
||||||
// that plus room for null terminator
|
|
||||||
static char sz [128 + 1];
|
|
||||||
sz[sizeof(sz) - 1] = '\0';
|
|
||||||
|
|
||||||
uint128 ii(*this);
|
|
||||||
int i = 128 - 1;
|
|
||||||
|
|
||||||
while (ii != 0 && i) {
|
|
||||||
|
|
||||||
uint128 remainder;
|
|
||||||
divide(ii, uint128(10), ii, remainder);
|
|
||||||
sz [--i] = "0123456789abcdefghijklmnopqrstuvwxyz"[remainder.to_integer()];
|
|
||||||
}
|
|
||||||
|
|
||||||
return &sz[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint128& uint128::operator<<=(const uint128& rhs)
|
|
||||||
{
|
|
||||||
if(rhs >= 128)
|
|
||||||
{
|
|
||||||
hi = 0;
|
|
||||||
lo = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unsigned int n = rhs.to_integer();
|
|
||||||
const unsigned int halfsize = 128 / 2;
|
|
||||||
|
|
||||||
if(n >= halfsize){
|
|
||||||
n -= halfsize;
|
|
||||||
hi = lo;
|
|
||||||
lo = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(n != 0) {
|
|
||||||
// shift high half
|
|
||||||
hi <<= n;
|
|
||||||
|
|
||||||
const uint64_t mask(~(uint64_t(-1) >> n));
|
|
||||||
|
|
||||||
// and add them to high half
|
|
||||||
hi |= (lo & mask) >> (halfsize - n);
|
|
||||||
|
|
||||||
// and finally shift also low half
|
|
||||||
lo <<= n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint128 & uint128::operator>>=(const uint128& rhs)
|
|
||||||
{
|
|
||||||
if(rhs >= 128)
|
|
||||||
{
|
|
||||||
hi = 0;
|
|
||||||
lo = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unsigned int n = rhs.to_integer();
|
|
||||||
const unsigned int halfsize = 128 / 2;
|
|
||||||
|
|
||||||
if(n >= halfsize) {
|
|
||||||
n -= halfsize;
|
|
||||||
lo = hi;
|
|
||||||
hi = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(n != 0) {
|
|
||||||
// shift low half
|
|
||||||
lo >>= n;
|
|
||||||
|
|
||||||
// get lower N bits of high half
|
|
||||||
const uint64_t mask(~(uint64_t(-1) << n));
|
|
||||||
|
|
||||||
// and add them to low qword
|
|
||||||
lo |= (hi & mask) << (halfsize - n);
|
|
||||||
|
|
||||||
// and finally shift also high half
|
|
||||||
hi >>= n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint128& uint128::operator/=(const uint128 &b)
|
|
||||||
{
|
|
||||||
auto self = (m128(hi) << 64) + m128(lo);
|
|
||||||
auto other = (m128(b.hi) << 64) + m128(b.lo);
|
|
||||||
self /= other;
|
|
||||||
hi = static_cast<uint64_t>(self >> 64);
|
|
||||||
lo = static_cast<uint64_t>((self << 64 ) >> 64);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint128& uint128::operator%=(const uint128 &b)
|
|
||||||
{
|
|
||||||
uint128 quotient;
|
|
||||||
divide(*this, b, quotient, *this);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint128& uint128::operator*=(const uint128 &b)
|
|
||||||
{
|
|
||||||
uint64_t a0 = (uint32_t) (this->lo );
|
|
||||||
uint64_t a1 = (uint32_t) (this->lo >> 0x20);
|
|
||||||
uint64_t a2 = (uint32_t) (this->hi );
|
|
||||||
uint64_t a3 = (uint32_t) (this->hi >> 0x20);
|
|
||||||
|
|
||||||
uint64_t b0 = (uint32_t) (b.lo );
|
|
||||||
uint64_t b1 = (uint32_t) (b.lo >> 0x20);
|
|
||||||
uint64_t b2 = (uint32_t) (b.hi );
|
|
||||||
uint64_t b3 = (uint32_t) (b.hi >> 0x20);
|
|
||||||
|
|
||||||
// (a0 + (a1 << 0x20) + (a2 << 0x40) + (a3 << 0x60)) *
|
|
||||||
// (b0 + (b1 << 0x20) + (b2 << 0x40) + (b3 << 0x60)) =
|
|
||||||
// a0 * b0
|
|
||||||
//
|
|
||||||
// (a1 * b0 + a0 * b1) << 0x20
|
|
||||||
// (a2 * b0 + a1 * b1 + a0 * b2) << 0x40
|
|
||||||
// (a3 * b0 + a2 * b1 + a1 * b2 + a0 * b3) << 0x60
|
|
||||||
//
|
|
||||||
// all other cross terms are << 0x80 or higher, thus do not appear in result
|
|
||||||
|
|
||||||
this->hi = 0;
|
|
||||||
this->lo = a3*b0;
|
|
||||||
(*this) += a2*b1;
|
|
||||||
(*this) += a1*b2;
|
|
||||||
(*this) += a0*b3;
|
|
||||||
(*this) <<= 0x20;
|
|
||||||
(*this) += a2*b0;
|
|
||||||
(*this) += a1*b1;
|
|
||||||
(*this) += a0*b2;
|
|
||||||
(*this) <<= 0x20;
|
|
||||||
(*this) += a1*b0;
|
|
||||||
(*this) += a0*b1;
|
|
||||||
(*this) <<= 0x20;
|
|
||||||
(*this) += a0*b0;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uint128::full_product( const uint128& a, const uint128& b, uint128& result_hi, uint128& result_lo )
|
|
||||||
{
|
|
||||||
// (ah * 2**64 + al) * (bh * 2**64 + bl)
|
|
||||||
// = (ah * bh * 2**128 + al * bh * 2**64 + ah * bl * 2**64 + al * bl
|
|
||||||
// = P * 2**128 + (Q + R) * 2**64 + S
|
|
||||||
// = Ph * 2**192 + Pl * 2**128
|
|
||||||
// + Qh * 2**128 + Ql * 2**64
|
|
||||||
// + Rh * 2**128 + Rl * 2**64
|
|
||||||
// + Sh * 2**64 + Sl
|
|
||||||
//
|
|
||||||
|
|
||||||
uint64_t ah = a.hi;
|
|
||||||
uint64_t al = a.lo;
|
|
||||||
uint64_t bh = b.hi;
|
|
||||||
uint64_t bl = b.lo;
|
|
||||||
|
|
||||||
uint128 s = al;
|
|
||||||
s *= bl;
|
|
||||||
uint128 r = ah;
|
|
||||||
r *= bl;
|
|
||||||
uint128 q = al;
|
|
||||||
q *= bh;
|
|
||||||
uint128 p = ah;
|
|
||||||
p *= bh;
|
|
||||||
|
|
||||||
uint64_t sl = s.lo;
|
|
||||||
uint64_t sh = s.hi;
|
|
||||||
uint64_t rl = r.lo;
|
|
||||||
uint64_t rh = r.hi;
|
|
||||||
uint64_t ql = q.lo;
|
|
||||||
uint64_t qh = q.hi;
|
|
||||||
uint64_t pl = p.lo;
|
|
||||||
uint64_t ph = p.hi;
|
|
||||||
|
|
||||||
uint64_t y[4]; // final result
|
|
||||||
y[0] = sl;
|
|
||||||
|
|
||||||
uint128_t acc = sh;
|
|
||||||
acc += ql;
|
|
||||||
acc += rl;
|
|
||||||
y[1] = acc.lo;
|
|
||||||
acc = acc.hi;
|
|
||||||
acc += qh;
|
|
||||||
acc += rh;
|
|
||||||
acc += pl;
|
|
||||||
y[2] = acc.lo;
|
|
||||||
y[3] = acc.hi + ph;
|
|
||||||
|
|
||||||
result_hi = uint128( y[3], y[2] );
|
|
||||||
result_lo = uint128( y[1], y[0] );
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t _popcount_64( uint64_t x )
|
|
||||||
{
|
|
||||||
static const uint64_t m[] = {
|
|
||||||
0x5555555555555555ULL,
|
|
||||||
0x3333333333333333ULL,
|
|
||||||
0x0F0F0F0F0F0F0F0FULL,
|
|
||||||
0x00FF00FF00FF00FFULL,
|
|
||||||
0x0000FFFF0000FFFFULL,
|
|
||||||
0x00000000FFFFFFFFULL
|
|
||||||
};
|
|
||||||
// TODO future optimization: replace slow, portable version
|
|
||||||
// with fast, non-portable __builtin_popcountll intrinsic
|
|
||||||
// (when available)
|
|
||||||
|
|
||||||
for( int i=0, w=1; i<6; i++, w+=w )
|
|
||||||
{
|
|
||||||
x = (x & m[i]) + ((x >> w) & m[i]);
|
|
||||||
}
|
|
||||||
return uint8_t(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t uint128::popcount()const
|
|
||||||
{
|
|
||||||
return _popcount_64( lo ) + _popcount_64( hi );
|
|
||||||
}
|
|
||||||
|
|
||||||
void to_variant( const uint128& var, variant& vo, uint32_t max_depth )
|
|
||||||
{
|
|
||||||
vo = std::string(var);
|
|
||||||
}
|
|
||||||
void from_variant( const variant& var, uint128& vo, uint32_t max_depth )
|
|
||||||
{
|
|
||||||
vo = uint128(var.as_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fc
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
size_t hash<fc::uint128>::operator()( const fc::uint128& s )const
|
|
||||||
{
|
|
||||||
boost::endian::little_uint64_buf_t tmp[2];
|
|
||||||
tmp[0] = s.hi;
|
|
||||||
tmp[1] = s.lo;
|
|
||||||
return fc::city_hash_size_t((char*)&tmp, sizeof(tmp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Portions of the above code were adapted from the work of Evan Teran.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2008
|
|
||||||
* Evan Teran
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software and its
|
|
||||||
* documentation for any purpose and without fee is hereby granted, provided
|
|
||||||
* that the above copyright notice appears in all copies and that both the
|
|
||||||
* copyright notice and this permission notice appear in supporting
|
|
||||||
* documentation, and that the same name not be used in advertising or
|
|
||||||
* publicity pertaining to distribution of the software without specific,
|
|
||||||
* written prior permission. We make no representations about the
|
|
||||||
* suitability this software for any purpose. It is provided "as is"
|
|
||||||
* without express or implied warranty.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
@ -11,8 +11,13 @@
|
||||||
#include <fc/reflect/variant.hpp>
|
#include <fc/reflect/variant.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
||||||
|
#include <boost/multiprecision/integer.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace fc
|
namespace fc
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The TypeID is stored in the 'last byte' of the variant.
|
* The TypeID is stored in the 'last byte' of the variant.
|
||||||
*/
|
*/
|
||||||
|
|
@ -27,7 +32,7 @@ variant::variant()
|
||||||
set_variant_type( this, null_type );
|
set_variant_type( this, null_type );
|
||||||
}
|
}
|
||||||
|
|
||||||
variant::variant( fc::nullptr_t, uint32_t max_depth )
|
variant::variant( std::nullptr_t, uint32_t max_depth )
|
||||||
{
|
{
|
||||||
set_variant_type( this, null_type );
|
set_variant_type( this, null_type );
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +79,7 @@ variant::variant( uint64_t val, uint32_t max_depth )
|
||||||
set_variant_type( this, uint64_type );
|
set_variant_type( this, uint64_type );
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
||||||
variant::variant( size_t val, uint32_t max_depth )
|
variant::variant( size_t val, uint32_t max_depth )
|
||||||
{
|
{
|
||||||
*reinterpret_cast<uint64_t*>(this) = val;
|
*reinterpret_cast<uint64_t*>(this) = val;
|
||||||
|
|
@ -672,8 +677,33 @@ void from_variant( const variant& var, std::vector<char>& vo, uint32_t max_depth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __APPLE__
|
void to_variant( const uint128_t& var, variant& vo, uint32_t max_depth )
|
||||||
#elif !defined(_MSC_VER)
|
{
|
||||||
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
||||||
|
boost::multiprecision::uint128_t helper = uint128_hi64( var );
|
||||||
|
helper <<= 64;
|
||||||
|
helper += uint128_lo64( var );
|
||||||
|
vo = boost::lexical_cast<std::string>( helper );
|
||||||
|
#else
|
||||||
|
vo = boost::lexical_cast<std::string>( var );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void from_variant( const variant& var, uint128_t& vo, uint32_t max_depth )
|
||||||
|
{
|
||||||
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
||||||
|
boost::multiprecision::uint128_t helper = boost::lexical_cast<boost::multiprecision::uint128_t>( var.as_string() );
|
||||||
|
vo = static_cast<uint64_t>( helper >> 64 );
|
||||||
|
vo <<= 64;
|
||||||
|
vo += static_cast<uint64_t>( helper & 0xffffffffffffffffULL );
|
||||||
|
#else
|
||||||
|
vo = boost::lexical_cast<uint128_t>( var.as_string() );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
||||||
|
void to_variant( size_t s, variant& v, uint32_t max_depth ) { v = variant( uint64_t(s) ); }
|
||||||
|
#elif !defined(_WIN32)
|
||||||
void to_variant( long long int s, variant& v, uint32_t max_depth ) { v = variant( int64_t(s) ); }
|
void to_variant( long long int s, variant& v, uint32_t max_depth ) { v = variant( int64_t(s) ); }
|
||||||
void to_variant( unsigned long long int s, variant& v, uint32_t max_depth ) { v = variant( uint64_t(s)); }
|
void to_variant( unsigned long long int s, variant& v, uint32_t max_depth ) { v = variant( uint64_t(s)); }
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,6 @@ target_link_libraries( task_cancel_test fc )
|
||||||
add_executable( bloom_test all_tests.cpp bloom_test.cpp )
|
add_executable( bloom_test all_tests.cpp bloom_test.cpp )
|
||||||
target_link_libraries( bloom_test fc )
|
target_link_libraries( bloom_test fc )
|
||||||
|
|
||||||
add_executable( real128_test all_tests.cpp real128_test.cpp )
|
|
||||||
target_link_libraries( real128_test fc )
|
|
||||||
|
|
||||||
add_executable( hmac_test hmac_test.cpp )
|
add_executable( hmac_test hmac_test.cpp )
|
||||||
target_link_libraries( hmac_test fc )
|
target_link_libraries( hmac_test fc )
|
||||||
|
|
||||||
|
|
@ -29,6 +26,7 @@ target_link_libraries( ecc_test fc )
|
||||||
add_executable( all_tests all_tests.cpp
|
add_executable( all_tests all_tests.cpp
|
||||||
compress/compress.cpp
|
compress/compress.cpp
|
||||||
crypto/aes_test.cpp
|
crypto/aes_test.cpp
|
||||||
|
crypto/array_initialization_test.cpp
|
||||||
crypto/base_n_tests.cpp
|
crypto/base_n_tests.cpp
|
||||||
crypto/bigint_test.cpp
|
crypto/bigint_test.cpp
|
||||||
crypto/blind.cpp
|
crypto/blind.cpp
|
||||||
|
|
@ -44,7 +42,7 @@ add_executable( all_tests all_tests.cpp
|
||||||
thread/thread_tests.cpp
|
thread/thread_tests.cpp
|
||||||
thread/parallel_tests.cpp
|
thread/parallel_tests.cpp
|
||||||
bloom_test.cpp
|
bloom_test.cpp
|
||||||
real128_test.cpp
|
reflection_tests.cpp
|
||||||
serialization_test.cpp
|
serialization_test.cpp
|
||||||
stacktrace_test.cpp
|
stacktrace_test.cpp
|
||||||
time_test.cpp
|
time_test.cpp
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
#include <fc/rpc/api_connection.hpp>
|
#include <fc/rpc/api_connection.hpp>
|
||||||
#include <fc/rpc/websocket_api.hpp>
|
#include <fc/rpc/websocket_api.hpp>
|
||||||
|
|
||||||
|
namespace fc { namespace test {
|
||||||
|
|
||||||
class calculator
|
class calculator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -15,9 +17,6 @@ class calculator
|
||||||
void on_result2( const std::function<void(int32_t)>& cb, int test );
|
void on_result2( const std::function<void(int32_t)>& cb, int test );
|
||||||
};
|
};
|
||||||
|
|
||||||
FC_API( calculator, (add)(sub)(on_result)(on_result2) )
|
|
||||||
|
|
||||||
|
|
||||||
class login_api
|
class login_api
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -29,8 +28,6 @@ class login_api
|
||||||
fc::optional<fc::api<calculator>> calc;
|
fc::optional<fc::api<calculator>> calc;
|
||||||
std::set<std::string> test( const std::string&, const std::string& ) { return std::set<std::string>(); }
|
std::set<std::string> test( const std::string&, const std::string& ) { return std::set<std::string>(); }
|
||||||
};
|
};
|
||||||
FC_API( login_api, (get_calc)(test) );
|
|
||||||
|
|
||||||
|
|
||||||
class optionals_api
|
class optionals_api
|
||||||
{
|
{
|
||||||
|
|
@ -39,10 +36,11 @@ public:
|
||||||
const fc::optional<std::string>& third ) {
|
const fc::optional<std::string>& third ) {
|
||||||
return fc::json::to_string(fc::variants{first, {second, 2}, {third, 2}});
|
return fc::json::to_string(fc::variants{first, {second, 2}, {third, 2}});
|
||||||
}
|
}
|
||||||
|
std::string bar( fc::optional<std::string> first, fc::optional<std::string> second,
|
||||||
|
fc::optional<std::string> third ) {
|
||||||
|
return fc::json::to_string(fc::variants{{first,2}, {second, 2}, {third, 2}});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
FC_API( optionals_api, (foo) );
|
|
||||||
|
|
||||||
using namespace fc;
|
|
||||||
|
|
||||||
class some_calculator
|
class some_calculator
|
||||||
{
|
{
|
||||||
|
|
@ -54,6 +52,12 @@ class some_calculator
|
||||||
std::function<void(int32_t)> _cb;
|
std::function<void(int32_t)> _cb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}} // fc::test
|
||||||
|
|
||||||
|
FC_API( fc::test::calculator, (add)(sub)(on_result)(on_result2) )
|
||||||
|
FC_API( fc::test::login_api, (get_calc)(test) );
|
||||||
|
FC_API( fc::test::optionals_api, (foo)(bar) );
|
||||||
|
|
||||||
using namespace fc::http;
|
using namespace fc::http;
|
||||||
using namespace fc::rpc;
|
using namespace fc::rpc;
|
||||||
|
|
||||||
|
|
@ -63,14 +67,14 @@ BOOST_AUTO_TEST_SUITE(api_tests)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(login_test) {
|
BOOST_AUTO_TEST_CASE(login_test) {
|
||||||
try {
|
try {
|
||||||
fc::api<calculator> calc_api( std::make_shared<some_calculator>() );
|
fc::api<fc::test::calculator> calc_api( std::make_shared<fc::test::some_calculator>() );
|
||||||
|
|
||||||
auto server = std::make_shared<fc::http::websocket_server>();
|
auto server = std::make_shared<fc::http::websocket_server>();
|
||||||
server->on_connection([&]( const websocket_connection_ptr& c ){
|
server->on_connection([&]( const websocket_connection_ptr& c ){
|
||||||
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
|
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
|
||||||
auto login = std::make_shared<login_api>();
|
auto login = std::make_shared<fc::test::login_api>();
|
||||||
login->calc = calc_api;
|
login->calc = calc_api;
|
||||||
wsc->register_api(fc::api<login_api>(login));
|
wsc->register_api(fc::api<fc::test::login_api>(login));
|
||||||
c->set_session_data( wsc );
|
c->set_session_data( wsc );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -82,7 +86,7 @@ BOOST_AUTO_TEST_CASE(login_test) {
|
||||||
auto con = client->connect( "ws://localhost:" + std::to_string(listen_port) );
|
auto con = client->connect( "ws://localhost:" + std::to_string(listen_port) );
|
||||||
server->stop_listening();
|
server->stop_listening();
|
||||||
auto apic = std::make_shared<websocket_api_connection>(con, MAX_DEPTH);
|
auto apic = std::make_shared<websocket_api_connection>(con, MAX_DEPTH);
|
||||||
auto remote_login_api = apic->get_remote_api<login_api>();
|
auto remote_login_api = apic->get_remote_api<fc::test::login_api>();
|
||||||
auto remote_calc = remote_login_api->get_calc();
|
auto remote_calc = remote_login_api->get_calc();
|
||||||
bool remote_triggered = false;
|
bool remote_triggered = false;
|
||||||
remote_calc->on_result( [&remote_triggered]( uint32_t r ) { remote_triggered = true; } );
|
remote_calc->on_result( [&remote_triggered]( uint32_t r ) { remote_triggered = true; } );
|
||||||
|
|
@ -99,17 +103,23 @@ BOOST_AUTO_TEST_CASE(login_test) {
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(optionals_test) {
|
BOOST_AUTO_TEST_CASE(optionals_test) {
|
||||||
try {
|
try {
|
||||||
auto optionals = std::make_shared<optionals_api>();
|
auto optionals = std::make_shared<fc::test::optionals_api>();
|
||||||
fc::api<optionals_api> oapi(optionals);
|
fc::api<fc::test::optionals_api> oapi(optionals);
|
||||||
BOOST_CHECK_EQUAL(oapi->foo("a"), "[\"a\",null,null]");
|
BOOST_CHECK_EQUAL(oapi->foo("a"), "[\"a\",null,null]");
|
||||||
BOOST_CHECK_EQUAL(oapi->foo("a", "b"), "[\"a\",\"b\",null]");
|
BOOST_CHECK_EQUAL(oapi->foo("a", "b"), "[\"a\",\"b\",null]");
|
||||||
BOOST_CHECK_EQUAL(oapi->foo("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
|
BOOST_CHECK_EQUAL(oapi->foo("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
|
||||||
BOOST_CHECK_EQUAL(oapi->foo("a", {}, "c"), "[\"a\",null,\"c\"]");
|
BOOST_CHECK_EQUAL(oapi->foo("a", {}, "c"), "[\"a\",null,\"c\"]");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(oapi->bar(), "[null,null,null]");
|
||||||
|
BOOST_CHECK_EQUAL(oapi->bar("a"), "[\"a\",null,null]");
|
||||||
|
BOOST_CHECK_EQUAL(oapi->bar("a", "b"), "[\"a\",\"b\",null]");
|
||||||
|
BOOST_CHECK_EQUAL(oapi->bar("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
|
||||||
|
BOOST_CHECK_EQUAL(oapi->bar("a", {}, "c"), "[\"a\",null,\"c\"]");
|
||||||
|
|
||||||
auto server = std::make_shared<fc::http::websocket_server>();
|
auto server = std::make_shared<fc::http::websocket_server>();
|
||||||
server->on_connection([&]( const websocket_connection_ptr& c ){
|
server->on_connection([&]( const websocket_connection_ptr& c ){
|
||||||
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
|
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
|
||||||
wsc->register_api(fc::api<optionals_api>(optionals));
|
wsc->register_api(fc::api<fc::test::optionals_api>(optionals));
|
||||||
c->set_session_data( wsc );
|
c->set_session_data( wsc );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -119,15 +129,45 @@ BOOST_AUTO_TEST_CASE(optionals_test) {
|
||||||
|
|
||||||
auto client = std::make_shared<fc::http::websocket_client>();
|
auto client = std::make_shared<fc::http::websocket_client>();
|
||||||
auto con = client->connect( "ws://localhost:" + std::to_string(listen_port) );
|
auto con = client->connect( "ws://localhost:" + std::to_string(listen_port) );
|
||||||
server->stop_listening();
|
|
||||||
auto apic = std::make_shared<websocket_api_connection>(con, MAX_DEPTH);
|
auto apic = std::make_shared<websocket_api_connection>(con, MAX_DEPTH);
|
||||||
auto remote_optionals = apic->get_remote_api<optionals_api>();
|
auto remote_optionals = apic->get_remote_api<fc::test::optionals_api>();
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(remote_optionals->foo("a"), "[\"a\",null,null]");
|
BOOST_CHECK_EQUAL(remote_optionals->foo("a"), "[\"a\",null,null]");
|
||||||
BOOST_CHECK_EQUAL(remote_optionals->foo("a", "b"), "[\"a\",\"b\",null]");
|
BOOST_CHECK_EQUAL(remote_optionals->foo("a", "b"), "[\"a\",\"b\",null]");
|
||||||
BOOST_CHECK_EQUAL(remote_optionals->foo("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
|
BOOST_CHECK_EQUAL(remote_optionals->foo("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
|
||||||
BOOST_CHECK_EQUAL(remote_optionals->foo("a", {}, "c"), "[\"a\",null,\"c\"]");
|
BOOST_CHECK_EQUAL(remote_optionals->foo("a", {}, "c"), "[\"a\",null,\"c\"]");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(remote_optionals->bar(), "[null,null,null]");
|
||||||
|
BOOST_CHECK_EQUAL(remote_optionals->bar("a"), "[\"a\",null,null]");
|
||||||
|
BOOST_CHECK_EQUAL(remote_optionals->bar("a", "b"), "[\"a\",\"b\",null]");
|
||||||
|
BOOST_CHECK_EQUAL(remote_optionals->bar("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
|
||||||
|
BOOST_CHECK_EQUAL(remote_optionals->bar("a", {}, "c"), "[\"a\",null,\"c\"]");
|
||||||
|
|
||||||
|
auto client2 = std::make_shared<fc::http::websocket_client>();
|
||||||
|
auto con2 = client2->connect( "ws://localhost:" + std::to_string(listen_port) );
|
||||||
|
std::string response;
|
||||||
|
con2->on_message_handler([&response](const std::string& s){
|
||||||
|
response = s;
|
||||||
|
});
|
||||||
|
|
||||||
|
con2->send_message( "{\"id\":1,\"method\":\"call\",\"params\":[0,\"bar\",[\"a\",\"b\",\"c\"]]}" );
|
||||||
|
fc::usleep(fc::milliseconds(50));
|
||||||
|
BOOST_CHECK_EQUAL( response, "{\"id\":1,\"result\":\"[\\\"a\\\",\\\"b\\\",\\\"c\\\"]\"}" );
|
||||||
|
|
||||||
|
con2->send_message( "{\"id\":2,\"method\":\"call\",\"params\":[0,\"bar\",[\"a\",\"b\"]]}" );
|
||||||
|
fc::usleep(fc::milliseconds(50));
|
||||||
|
BOOST_CHECK_EQUAL( response, "{\"id\":2,\"result\":\"[\\\"a\\\",\\\"b\\\",null]\"}" );
|
||||||
|
|
||||||
|
con2->send_message( "{\"id\":3,\"method\":\"call\",\"params\":[0,\"bar\",[\"a\"]]}" );
|
||||||
|
fc::usleep(fc::milliseconds(50));
|
||||||
|
BOOST_CHECK_EQUAL( response, "{\"id\":3,\"result\":\"[\\\"a\\\",null,null]\"}" );
|
||||||
|
|
||||||
|
con2->send_message( "{\"id\":4,\"method\":\"call\",\"params\":[0,\"bar\",[]]}" );
|
||||||
|
fc::usleep(fc::milliseconds(50));
|
||||||
|
BOOST_CHECK_EQUAL( response, "{\"id\":4,\"result\":\"[null,null,null]\"}" );
|
||||||
|
|
||||||
|
server->stop_listening();
|
||||||
|
|
||||||
client->synchronous_close();
|
client->synchronous_close();
|
||||||
server->close();
|
server->close();
|
||||||
fc::usleep(fc::milliseconds(50));
|
fc::usleep(fc::milliseconds(50));
|
||||||
|
|
|
||||||
67
tests/crypto/array_initialization_test.cpp
Normal file
67
tests/crypto/array_initialization_test.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 BitShares Blockchain Foundation, and contributors.
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <fc/crypto/elliptic.hpp>
|
||||||
|
#include <fc/crypto/rand.hpp>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static void check_null_key()
|
||||||
|
{
|
||||||
|
fc::ecc::public_key_data key1;
|
||||||
|
fc::ecc::public_key_data key2;
|
||||||
|
unsigned char zeroes[33];
|
||||||
|
static_assert( key1.size() == sizeof(zeroes), "Wrong array size!" );
|
||||||
|
memset( zeroes, 0, sizeof(zeroes) );
|
||||||
|
BOOST_CHECK( !memcmp( key1.data(), zeroes, sizeof(zeroes) ) );
|
||||||
|
BOOST_CHECK( !memcmp( key2.data(), zeroes, sizeof(zeroes) ) );
|
||||||
|
|
||||||
|
// now "pollute" the keys for the next invocation
|
||||||
|
key1 = fc::ecc::private_key::generate().get_public_key();
|
||||||
|
for( unsigned char c = 0; c < key2.size(); c++ )
|
||||||
|
{
|
||||||
|
key2[c] = c ^ 17;
|
||||||
|
zeroes[c] = c ^ 47;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...and use them to prevent the compiler from optimizing the pollution away.
|
||||||
|
wlog( "Key1: ${k}", ("k",fc::ecc::public_key::to_base58(key1)) );
|
||||||
|
wlog( "Key2: ${k}", ("k",fc::ecc::public_key::to_base58(key2)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(fc_crypto)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(array_init_test)
|
||||||
|
{
|
||||||
|
check_null_key();
|
||||||
|
check_null_key();
|
||||||
|
{
|
||||||
|
char junk[128];
|
||||||
|
fc::rand_bytes( junk, sizeof(junk) );
|
||||||
|
}
|
||||||
|
check_null_key();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
@ -23,7 +23,7 @@ static void interop_do(const char * const data, size_t len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void interop_do(const fc::ecc::public_key_data &data) {
|
static void interop_do(const fc::ecc::public_key_data &data) {
|
||||||
interop_do(data.begin(), data.size());
|
interop_do((char*) data.data(), data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void interop_do(const fc::ecc::private_key_secret &data) {
|
static void interop_do(const fc::ecc::private_key_secret &data) {
|
||||||
|
|
@ -31,7 +31,7 @@ static void interop_do(const fc::ecc::private_key_secret &data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void interop_do(const fc::ecc::public_key_point_data &data) {
|
static void interop_do(const fc::ecc::public_key_point_data &data) {
|
||||||
interop_do(data.begin(), data.size());
|
interop_do((char*) data.data(), data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void interop_do(const std::string &data) {
|
static void interop_do(const std::string &data) {
|
||||||
|
|
@ -44,11 +44,11 @@ static void interop_do(const fc::sha512 &data) {
|
||||||
|
|
||||||
static void interop_do(fc::ecc::compact_signature &data) {
|
static void interop_do(fc::ecc::compact_signature &data) {
|
||||||
if (write_mode) {
|
if (write_mode) {
|
||||||
interop_data.write((char*) data.begin(), data.size());
|
interop_data.write((char*) data.data(), data.size());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
interop_data.read((char*) data.begin(), data.size());
|
interop_data.read((char*) data.data(), data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void interop_file(const char * const name) {
|
static void interop_file(const char * const name) {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
#define BOOST_TEST_MODULE HmacTest
|
#define BOOST_TEST_MODULE HmacTest
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <fc/array.hpp>
|
|
||||||
#include <fc/crypto/hex.hpp>
|
#include <fc/crypto/hex.hpp>
|
||||||
#include <fc/crypto/hmac.hpp>
|
#include <fc/crypto/hmac.hpp>
|
||||||
#include <fc/crypto/sha224.hpp>
|
#include <fc/crypto/sha224.hpp>
|
||||||
#include <fc/crypto/sha256.hpp>
|
#include <fc/crypto/sha256.hpp>
|
||||||
#include <fc/crypto/sha512.hpp>
|
#include <fc/crypto/sha512.hpp>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
// See http://tools.ietf.org/html/rfc4231
|
// See http://tools.ietf.org/html/rfc4231
|
||||||
|
|
||||||
static const std::string TEST1_KEY = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
|
static const std::string TEST1_KEY = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
|
||||||
|
|
@ -77,14 +78,14 @@ static void run_test( const std::string& key, const std::string& data, const std
|
||||||
const std::string& expect_256, const std::string& expect_512 )
|
const std::string& expect_256, const std::string& expect_512 )
|
||||||
{
|
{
|
||||||
|
|
||||||
fc::array<char,N> key_arr;
|
std::array<char,N> key_arr;
|
||||||
BOOST_CHECK_EQUAL( fc::from_hex( key, key_arr.begin(), key_arr.size() ), N );
|
BOOST_CHECK_EQUAL( fc::from_hex( key, key_arr.data(), key_arr.size() ), N );
|
||||||
fc::array<char,M> data_arr;
|
std::array<char,M> data_arr;
|
||||||
BOOST_CHECK_EQUAL( fc::from_hex( data, data_arr.begin(), data_arr.size() ), M );
|
BOOST_CHECK_EQUAL( fc::from_hex( data, data_arr.data(), data_arr.size() ), M );
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL( mac_224.digest( key_arr.begin(), N, data_arr.begin(), M ).str(), expect_224 );
|
BOOST_CHECK_EQUAL( mac_224.digest( key_arr.data(), N, data_arr.data(), M ).str(), expect_224 );
|
||||||
BOOST_CHECK_EQUAL( mac_256.digest( key_arr.begin(), N, data_arr.begin(), M ).str(), expect_256 );
|
BOOST_CHECK_EQUAL( mac_256.digest( key_arr.data(), N, data_arr.data(), M ).str(), expect_256 );
|
||||||
BOOST_CHECK_EQUAL( mac_512.digest( key_arr.begin(), N, data_arr.begin(), M ).str(), expect_512 );
|
BOOST_CHECK_EQUAL( mac_512.digest( key_arr.data(), N, data_arr.data(), M ).str(), expect_512 );
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(hmac_test_1)
|
BOOST_AUTO_TEST_CASE(hmac_test_1)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,16 @@
|
||||||
#include <fc/network/tcp_socket.hpp>
|
#include <fc/network/tcp_socket.hpp>
|
||||||
#include <fc/asio.hpp>
|
#include <fc/asio.hpp>
|
||||||
|
|
||||||
|
namespace fc { namespace test {
|
||||||
|
|
||||||
|
class my_io_class : public fc::asio::default_io_service_scope
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void reset_num_threads() { fc::asio::default_io_service_scope::num_io_threads = 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // fc::test
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(tcp_tests)
|
BOOST_AUTO_TEST_SUITE(tcp_tests)
|
||||||
|
|
||||||
/***
|
/***
|
||||||
|
|
@ -15,23 +25,17 @@ BOOST_AUTO_TEST_CASE(tcpconstructor_test)
|
||||||
fc::tcp_socket socket;
|
fc::tcp_socket socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
class my_io_class : public fc::asio::default_io_service_scope
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void reset_num_threads() { fc::asio::default_io_service_scope::num_io_threads = 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Test the control of number of threads from outside
|
* Test the control of number of threads from outside
|
||||||
*/
|
*/
|
||||||
BOOST_AUTO_TEST_CASE( number_threads_test )
|
BOOST_AUTO_TEST_CASE( number_threads_test )
|
||||||
{
|
{
|
||||||
// to erase leftovers from previous tests
|
// to erase leftovers from previous tests
|
||||||
my_io_class::reset_num_threads();
|
fc::test::my_io_class::reset_num_threads();
|
||||||
|
|
||||||
fc::asio::default_io_service_scope::set_num_threads(12);
|
fc::asio::default_io_service_scope::set_num_threads(12);
|
||||||
|
|
||||||
my_io_class my_class;
|
fc::test::my_io_class my_class;
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL( 12, my_class.get_num_threads() );
|
BOOST_CHECK_EQUAL( 12, my_class.get_num_threads() );
|
||||||
}
|
}
|
||||||
|
|
@ -42,9 +46,9 @@ BOOST_AUTO_TEST_CASE( number_threads_test )
|
||||||
BOOST_AUTO_TEST_CASE( default_number_threads_test )
|
BOOST_AUTO_TEST_CASE( default_number_threads_test )
|
||||||
{
|
{
|
||||||
// to erase leftovers from previous tests
|
// to erase leftovers from previous tests
|
||||||
my_io_class::reset_num_threads();
|
fc::test::my_io_class::reset_num_threads();
|
||||||
|
|
||||||
my_io_class my_class;
|
fc::test::my_io_class my_class;
|
||||||
|
|
||||||
fc::asio::default_io_service();
|
fc::asio::default_io_service();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
#include <fc/real128.hpp>
|
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
#include <fc/log/logger.hpp>
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(fc)
|
|
||||||
|
|
||||||
using fc::real128;
|
|
||||||
using std::string;
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(real128_test)
|
|
||||||
{
|
|
||||||
BOOST_CHECK_EQUAL(string(real128()), string("0."));
|
|
||||||
BOOST_CHECK_EQUAL(string(real128(0)), string("0."));
|
|
||||||
BOOST_CHECK_EQUAL(real128(8).to_uint64(), 8u);
|
|
||||||
BOOST_CHECK_EQUAL(real128(6789).to_uint64(), 6789u);
|
|
||||||
BOOST_CHECK_EQUAL(real128(10000).to_uint64(), 10000u);
|
|
||||||
BOOST_CHECK_EQUAL(string(real128(1)), string("1."));
|
|
||||||
BOOST_CHECK_EQUAL(string(real128(5)), string("5."));
|
|
||||||
BOOST_CHECK_EQUAL(string(real128(12345)), string("12345."));
|
|
||||||
BOOST_CHECK_EQUAL(string(real128(0)), string(real128("0")));
|
|
||||||
|
|
||||||
real128 ten(10);
|
|
||||||
real128 two(2);
|
|
||||||
real128 twenty(20);
|
|
||||||
real128 pi(31415926535);
|
|
||||||
pi /= 10000000000;
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL( string(ten), "10." );
|
|
||||||
BOOST_CHECK_EQUAL( string(two), "2." );
|
|
||||||
BOOST_CHECK_EQUAL( string(ten+two), "12." );
|
|
||||||
BOOST_CHECK_EQUAL( string(ten-two), "8." );
|
|
||||||
BOOST_CHECK_EQUAL( string(ten*two), "20." );
|
|
||||||
BOOST_CHECK_EQUAL( string(ten/two), "5." );
|
|
||||||
BOOST_CHECK_EQUAL( string(ten/two/two/two*two*two*two), "10." );
|
|
||||||
BOOST_CHECK_EQUAL( string(ten/two/two/two*two*two*two), string(ten) );
|
|
||||||
BOOST_CHECK_EQUAL( string(twenty/ten), string(two) );
|
|
||||||
BOOST_CHECK_EQUAL( string(pi), "3.1415926535" );
|
|
||||||
BOOST_CHECK_EQUAL( string(pi*10), "31.415926535" );
|
|
||||||
BOOST_CHECK_EQUAL( string(pi*20), "62.83185307" );
|
|
||||||
BOOST_CHECK_EQUAL( string(real128("62.83185307")/twenty), string(pi) );
|
|
||||||
BOOST_CHECK_EQUAL( string(pi*1), "3.1415926535" );
|
|
||||||
BOOST_CHECK_EQUAL( string(pi*0), "0." );
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(real128("12345.6789").to_uint64(), 12345u);
|
|
||||||
BOOST_CHECK_EQUAL((real128("12345.6789")*10000).to_uint64(), 123456789u);
|
|
||||||
BOOST_CHECK_EQUAL(string(real128("12345.6789")), string("12345.6789"));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL( real128(uint64_t(-1)).to_uint64(), uint64_t(-1) );
|
|
||||||
|
|
||||||
wdump( (ten)(two)(twenty) );
|
|
||||||
wdump((real128("12345.6789")) );
|
|
||||||
wdump( (ten/3*3) );
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
|
||||||
126
tests/reflection_tests.cpp
Normal file
126
tests/reflection_tests.cpp
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <fc/exception/exception.hpp>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
struct reflect_test_base {
|
||||||
|
int x = 1;
|
||||||
|
char y = 'a';
|
||||||
|
};
|
||||||
|
struct reflect_test_derived : reflect_test_base {
|
||||||
|
double z = 3.14;
|
||||||
|
};
|
||||||
|
struct reflect_layer_1 { reflect_test_base b; int32_t n; };
|
||||||
|
struct reflect_layer_2 { reflect_layer_1 l1; reflect_test_derived d; };
|
||||||
|
struct reflect_layer_3 { reflect_layer_2 l2; int32_t i; };
|
||||||
|
|
||||||
|
FC_REFLECT( reflect_test_base, (x)(y) );
|
||||||
|
FC_REFLECT_DERIVED( reflect_test_derived, (reflect_test_base), (z) );
|
||||||
|
FC_REFLECT( reflect_layer_1, (b)(n) );
|
||||||
|
FC_REFLECT( reflect_layer_2, (l1)(d) );
|
||||||
|
FC_REFLECT( reflect_layer_3, (l2)(i) );
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE( fc_reflection )
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( reflection_static_tests )
|
||||||
|
{
|
||||||
|
// These are all compile-time tests, nothing actually happens here at runtime
|
||||||
|
using base_reflection = fc::reflector<reflect_test_base>;
|
||||||
|
using derived_reflection = fc::reflector<reflect_test_derived>;
|
||||||
|
static_assert(fc::typelist::length<base_reflection::members>() == 2, "");
|
||||||
|
static_assert(fc::typelist::length<derived_reflection::members>() == 3, "");
|
||||||
|
static_assert(fc::typelist::at<derived_reflection::members, 0>::is_derived, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::at<derived_reflection::members, 0>::field_container,
|
||||||
|
reflect_test_base>::value, "");
|
||||||
|
static_assert(fc::typelist::at<derived_reflection::members, 1>::is_derived, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::at<derived_reflection::members, 1>::field_container,
|
||||||
|
reflect_test_base>::value, "");
|
||||||
|
static_assert(fc::typelist::at<derived_reflection::members, 2>::is_derived == false, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 0, 1>,
|
||||||
|
fc::typelist::list<int>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 0, 2>,
|
||||||
|
fc::typelist::list<int, bool>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 0, 3>,
|
||||||
|
fc::typelist::list<int, bool, char>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 1, 3>,
|
||||||
|
fc::typelist::list<bool, char>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 2, 3>,
|
||||||
|
fc::typelist::list<char>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 1, 2>,
|
||||||
|
fc::typelist::list<bool>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 1>,
|
||||||
|
fc::typelist::list<bool, char>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::make_sequence<0>, fc::typelist::list<>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::make_sequence<1>,
|
||||||
|
fc::typelist::list<std::integral_constant<size_t, 0>>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::make_sequence<2>,
|
||||||
|
fc::typelist::list<std::integral_constant<size_t, 0>,
|
||||||
|
std::integral_constant<size_t, 1>>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::make_sequence<3>,
|
||||||
|
fc::typelist::list<std::integral_constant<size_t, 0>,
|
||||||
|
std::integral_constant<size_t, 1>,
|
||||||
|
std::integral_constant<size_t, 2>>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::zip<fc::typelist::list<>, fc::typelist::list<>>,
|
||||||
|
fc::typelist::list<>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::zip<fc::typelist::list<bool>, fc::typelist::list<char>>,
|
||||||
|
fc::typelist::list<fc::typelist::list<bool, char>>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::zip<fc::typelist::list<int, bool>, fc::typelist::list<char, double>>,
|
||||||
|
fc::typelist::list<fc::typelist::list<int, char>,
|
||||||
|
fc::typelist::list<bool, double>>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::index<fc::typelist::list<>>, fc::typelist::list<>>::value, "");
|
||||||
|
static_assert(std::is_same<fc::typelist::index<fc::typelist::list<int, bool, char, double>>,
|
||||||
|
fc::typelist::list<fc::typelist::list<std::integral_constant<size_t, 0>, int>,
|
||||||
|
fc::typelist::list<std::integral_constant<size_t, 1>, bool>,
|
||||||
|
fc::typelist::list<std::integral_constant<size_t, 2>, char>,
|
||||||
|
fc::typelist::list<std::integral_constant<size_t, 3>, double>>
|
||||||
|
>::value, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( typelist_dispatch_test )
|
||||||
|
{
|
||||||
|
using list = fc::typelist::list<float, bool, char>;
|
||||||
|
auto get_name = [](auto t) -> std::string { return fc::get_typename<typename decltype(t)::type>::name(); };
|
||||||
|
BOOST_CHECK_EQUAL(fc::typelist::runtime::dispatch(list(), 0ul, get_name), "float");
|
||||||
|
BOOST_CHECK_EQUAL(fc::typelist::runtime::dispatch(list(), 1ul, get_name), "bool");
|
||||||
|
BOOST_CHECK_EQUAL(fc::typelist::runtime::dispatch(list(), 2ul, get_name), "char");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper template to use fc::typelist::at without a comma, for macro friendliness
|
||||||
|
template<typename T> struct index_from { template<std::size_t idx> using at = fc::typelist::at<T, idx>; };
|
||||||
|
BOOST_AUTO_TEST_CASE( reflection_get_test )
|
||||||
|
{ try {
|
||||||
|
reflect_test_derived derived;
|
||||||
|
reflect_test_base& base = derived;
|
||||||
|
|
||||||
|
using base_reflector = fc::reflector<reflect_test_base>;
|
||||||
|
using derived_reflector = fc::reflector<reflect_test_derived>;
|
||||||
|
|
||||||
|
BOOST_CHECK(index_from<base_reflector::members>::at<0>::get(base) == 1);
|
||||||
|
BOOST_CHECK(index_from<base_reflector::members>::at<1>::get(base) == 'a');
|
||||||
|
|
||||||
|
fc::typelist::at<base_reflector::members, 0>::get(base) = 5;
|
||||||
|
fc::typelist::at<base_reflector::members, 1>::get(base) = 'q';
|
||||||
|
|
||||||
|
BOOST_CHECK(index_from<base_reflector::members>::at<0>::get(base) == 5);
|
||||||
|
BOOST_CHECK(index_from<base_reflector::members>::at<1>::get(base) == 'q');
|
||||||
|
|
||||||
|
BOOST_CHECK(index_from<derived_reflector::members>::at<0>::get(derived) == 5);
|
||||||
|
BOOST_CHECK(index_from<derived_reflector::members>::at<1>::get(derived) == 'q');
|
||||||
|
BOOST_CHECK(index_from<derived_reflector::members>::at<2>::get(derived) == 3.14);
|
||||||
|
|
||||||
|
fc::typelist::at<derived_reflector::members, 1>::get(derived) = 'X';
|
||||||
|
|
||||||
|
BOOST_CHECK(index_from<base_reflector::members>::at<1>::get(base) == 'X');
|
||||||
|
|
||||||
|
reflect_layer_3 l3;
|
||||||
|
BOOST_CHECK(index_from<index_from<index_from<index_from<fc::reflector<reflect_layer_3>::members>::at<0>
|
||||||
|
::reflector::members>::at<0>::reflector::members>::at<0>::reflector::members>::at<1>::get(l3.l2.l1.b)
|
||||||
|
== 'a');
|
||||||
|
BOOST_CHECK(index_from<index_from<index_from<fc::reflector<reflect_layer_3>::members>::at<0>::reflector::members>
|
||||||
|
::at<1>::reflector::members>::at<1>::get(l3.l2.d) == 'a');
|
||||||
|
BOOST_CHECK(index_from<index_from<index_from<fc::reflector<reflect_layer_3>::members>::at<0>::reflector::members>
|
||||||
|
::at<1>::reflector::members>::at<2>::get(l3.l2.d) == 3.14);
|
||||||
|
} FC_CAPTURE_LOG_AND_RETHROW( (0) ) }
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
@ -35,7 +35,6 @@ namespace fc { namespace test {
|
||||||
inline bool operator < ( const item& a, const item& b )
|
inline bool operator < ( const item& a, const item& b )
|
||||||
{ return ( std::tie( a.level, a.w ) < std::tie( b.level, b.w ) ); }
|
{ return ( std::tie( a.level, a.w ) < std::tie( b.level, b.w ) ); }
|
||||||
|
|
||||||
|
|
||||||
} } // namespace fc::test
|
} } // namespace fc::test
|
||||||
|
|
||||||
FC_REFLECT( fc::test::item_wrapper, (v) );
|
FC_REFLECT( fc::test::item_wrapper, (v) );
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue