Initial checkin of FC code.
This commit is contained in:
commit
9041b9bff4
83 changed files with 11294 additions and 0 deletions
504
CMakeCache.txt
Normal file
504
CMakeCache.txt
Normal file
|
|
@ -0,0 +1,504 @@
|
|||
# This is the CMakeCache file.
|
||||
# For build in directory: /Users/dlarimer/Downloads/fc
|
||||
# It was generated by CMake: /opt/local/bin/cmake
|
||||
# You can edit this file to change values found and used by cmake.
|
||||
# If you do not want to change any of the values, simply exit the editor.
|
||||
# If you do want to change a value, simply edit, save, and exit the editor.
|
||||
# The syntax for the file is as follows:
|
||||
# KEY:TYPE=VALUE
|
||||
# KEY is the name of a variable in the cache.
|
||||
# TYPE is a hint to GUI's for the type of VALUE, DO NOT EDIT TYPE!.
|
||||
# VALUE is the current value for the KEY.
|
||||
|
||||
########################
|
||||
# EXTERNAL cache entries
|
||||
########################
|
||||
|
||||
//The Boost CHRONO library
|
||||
Boost_CHRONO_LIBRARY:FILEPATH=/usr/local/lib/libboost_chrono.a
|
||||
|
||||
//Boost chrono library (debug)
|
||||
Boost_CHRONO_LIBRARY_DEBUG:FILEPATH=/usr/local/lib/libboost_chrono.a
|
||||
|
||||
//Boost chrono library (release)
|
||||
Boost_CHRONO_LIBRARY_RELEASE:FILEPATH=/usr/local/lib/libboost_chrono.a
|
||||
|
||||
//The Boost CONTEXT library
|
||||
Boost_CONTEXT_LIBRARY:FILEPATH=/usr/local/lib/libboost_context.a
|
||||
|
||||
//Boost context library (debug)
|
||||
Boost_CONTEXT_LIBRARY_DEBUG:FILEPATH=/usr/local/lib/libboost_context.a
|
||||
|
||||
//Boost context library (release)
|
||||
Boost_CONTEXT_LIBRARY_RELEASE:FILEPATH=/usr/local/lib/libboost_context.a
|
||||
|
||||
//The Boost DATE_TIME library
|
||||
Boost_DATE_TIME_LIBRARY:FILEPATH=/usr/local/lib/libboost_date_time.a
|
||||
|
||||
//Boost date_time library (debug)
|
||||
Boost_DATE_TIME_LIBRARY_DEBUG:FILEPATH=/usr/local/lib/libboost_date_time.a
|
||||
|
||||
//Boost date_time library (release)
|
||||
Boost_DATE_TIME_LIBRARY_RELEASE:FILEPATH=/usr/local/lib/libboost_date_time.a
|
||||
|
||||
//The directory containing a CMake configuration file for Boost.
|
||||
Boost_DIR:PATH=Boost_DIR-NOTFOUND
|
||||
|
||||
//The Boost FILESYSTEM library
|
||||
Boost_FILESYSTEM_LIBRARY:FILEPATH=/usr/local/lib/libboost_filesystem.a
|
||||
|
||||
//Boost filesystem library (debug)
|
||||
Boost_FILESYSTEM_LIBRARY_DEBUG:FILEPATH=/usr/local/lib/libboost_filesystem.a
|
||||
|
||||
//Boost filesystem library (release)
|
||||
Boost_FILESYSTEM_LIBRARY_RELEASE:FILEPATH=/usr/local/lib/libboost_filesystem.a
|
||||
|
||||
//Path to a file.
|
||||
Boost_INCLUDE_DIR:PATH=/usr/local/include
|
||||
|
||||
//Boost library directory
|
||||
Boost_LIBRARY_DIRS:FILEPATH=/usr/local/lib
|
||||
|
||||
//The Boost PROGRAM_OPTIONS library
|
||||
Boost_PROGRAM_OPTIONS_LIBRARY:FILEPATH=/usr/local/lib/libboost_program_options.a
|
||||
|
||||
//Boost program_options library (debug)
|
||||
Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG:FILEPATH=/usr/local/lib/libboost_program_options.a
|
||||
|
||||
//Boost program_options library (release)
|
||||
Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE:FILEPATH=/usr/local/lib/libboost_program_options.a
|
||||
|
||||
//The Boost SERIALIZATION library
|
||||
Boost_SERIALIZATION_LIBRARY:FILEPATH=/usr/local/lib/libboost_serialization.a
|
||||
|
||||
//Boost serialization library (debug)
|
||||
Boost_SERIALIZATION_LIBRARY_DEBUG:FILEPATH=/usr/local/lib/libboost_serialization.a
|
||||
|
||||
//Boost serialization library (release)
|
||||
Boost_SERIALIZATION_LIBRARY_RELEASE:FILEPATH=/usr/local/lib/libboost_serialization.a
|
||||
|
||||
//The Boost SIGNALS library
|
||||
Boost_SIGNALS_LIBRARY:FILEPATH=/usr/local/lib/libboost_signals.a
|
||||
|
||||
//Boost signals library (debug)
|
||||
Boost_SIGNALS_LIBRARY_DEBUG:FILEPATH=/usr/local/lib/libboost_signals.a
|
||||
|
||||
//Boost signals library (release)
|
||||
Boost_SIGNALS_LIBRARY_RELEASE:FILEPATH=/usr/local/lib/libboost_signals.a
|
||||
|
||||
//The Boost SYSTEM library
|
||||
Boost_SYSTEM_LIBRARY:FILEPATH=/usr/local/lib/libboost_system.a
|
||||
|
||||
//Boost system library (debug)
|
||||
Boost_SYSTEM_LIBRARY_DEBUG:FILEPATH=/usr/local/lib/libboost_system.a
|
||||
|
||||
//Boost system library (release)
|
||||
Boost_SYSTEM_LIBRARY_RELEASE:FILEPATH=/usr/local/lib/libboost_system.a
|
||||
|
||||
//The Boost THREAD library
|
||||
Boost_THREAD_LIBRARY:FILEPATH=/usr/local/lib/libboost_thread.a
|
||||
|
||||
//Boost thread library (debug)
|
||||
Boost_THREAD_LIBRARY_DEBUG:FILEPATH=/usr/local/lib/libboost_thread.a
|
||||
|
||||
//Boost thread library (release)
|
||||
Boost_THREAD_LIBRARY_RELEASE:FILEPATH=/usr/local/lib/libboost_thread.a
|
||||
|
||||
//The Boost UNIT_TEST_FRAMEWORK library
|
||||
Boost_UNIT_TEST_FRAMEWORK_LIBRARY:FILEPATH=/usr/local/lib/libboost_unit_test_framework.a
|
||||
|
||||
//Boost unit_test_framework library (debug)
|
||||
Boost_UNIT_TEST_FRAMEWORK_LIBRARY_DEBUG:FILEPATH=/usr/local/lib/libboost_unit_test_framework.a
|
||||
|
||||
//Boost unit_test_framework library (release)
|
||||
Boost_UNIT_TEST_FRAMEWORK_LIBRARY_RELEASE:FILEPATH=/usr/local/lib/libboost_unit_test_framework.a
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_AR:FILEPATH=/opt/local/bin/ar
|
||||
|
||||
//Choose the type of build, options are: None(CMAKE_CXX_FLAGS or
|
||||
// CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.
|
||||
CMAKE_BUILD_TYPE:STRING=
|
||||
|
||||
//Enable/Disable color output during build.
|
||||
CMAKE_COLOR_MAKEFILE:BOOL=ON
|
||||
|
||||
//CXX compiler.
|
||||
CMAKE_CXX_COMPILER:FILEPATH=/opt/local/bin/c++
|
||||
|
||||
//Flags used by the compiler during all build types.
|
||||
CMAKE_CXX_FLAGS:STRING=
|
||||
|
||||
//Flags used by the compiler during debug builds.
|
||||
CMAKE_CXX_FLAGS_DEBUG:STRING=-g
|
||||
|
||||
//Flags used by the compiler during release minsize builds.
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
|
||||
|
||||
//Flags used by the compiler during release builds (/MD /Ob1 /Oi
|
||||
// /Ot /Oy /Gs will produce slightly less optimized but smaller
|
||||
// files).
|
||||
CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
|
||||
|
||||
//Flags used by the compiler during Release with Debug Info builds.
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g
|
||||
|
||||
//C compiler.
|
||||
CMAKE_C_COMPILER:FILEPATH=/opt/local/bin/gcc
|
||||
|
||||
//Flags used by the compiler during all build types.
|
||||
CMAKE_C_FLAGS:STRING=
|
||||
|
||||
//Flags used by the compiler during debug builds.
|
||||
CMAKE_C_FLAGS_DEBUG:STRING=-g
|
||||
|
||||
//Flags used by the compiler during release minsize builds.
|
||||
CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
|
||||
|
||||
//Flags used by the compiler during release builds (/MD /Ob1 /Oi
|
||||
// /Ot /Oy /Gs will produce slightly less optimized but smaller
|
||||
// files).
|
||||
CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
|
||||
|
||||
//Flags used by the compiler during Release with Debug Info builds.
|
||||
CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g
|
||||
|
||||
//Flags used by the linker.
|
||||
CMAKE_EXE_LINKER_FLAGS:STRING=' '
|
||||
|
||||
//Flags used by the linker during debug builds.
|
||||
CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=
|
||||
|
||||
//Flags used by the linker during release minsize builds.
|
||||
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||
|
||||
//Flags used by the linker during release builds.
|
||||
CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=
|
||||
|
||||
//Flags used by the linker during Release with Debug Info builds.
|
||||
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||
|
||||
//Enable/Disable output of compile commands during generation.
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=OFF
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_INSTALL_NAME_TOOL:FILEPATH=/opt/local/bin/install_name_tool
|
||||
|
||||
//Install path prefix, prepended onto install directories.
|
||||
CMAKE_INSTALL_PREFIX:PATH=/usr/local
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_LINKER:FILEPATH=/opt/local/bin/ld
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/make
|
||||
|
||||
//Flags used by the linker during the creation of modules.
|
||||
CMAKE_MODULE_LINKER_FLAGS:STRING=' '
|
||||
|
||||
//Flags used by the linker during debug builds.
|
||||
CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=
|
||||
|
||||
//Flags used by the linker during release minsize builds.
|
||||
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||
|
||||
//Flags used by the linker during release builds.
|
||||
CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=
|
||||
|
||||
//Flags used by the linker during Release with Debug Info builds.
|
||||
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_NM:FILEPATH=/opt/local/bin/nm
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_OBJCOPY:FILEPATH=CMAKE_OBJCOPY-NOTFOUND
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_OBJDUMP:FILEPATH=CMAKE_OBJDUMP-NOTFOUND
|
||||
|
||||
//Build architectures for OSX
|
||||
CMAKE_OSX_ARCHITECTURES:STRING=
|
||||
|
||||
//Minimum OS X version to target for deployment (at runtime); newer
|
||||
// APIs weak linked. Set to empty string for default value.
|
||||
CMAKE_OSX_DEPLOYMENT_TARGET:STRING=
|
||||
|
||||
//The product will be built against the headers and libraries located
|
||||
// inside the indicated SDK.
|
||||
CMAKE_OSX_SYSROOT:PATH=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk
|
||||
|
||||
//Value Computed by CMake
|
||||
CMAKE_PROJECT_NAME:STATIC=fc
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_RANLIB:FILEPATH=/opt/local/bin/ranlib
|
||||
|
||||
//Flags used by the linker during the creation of dll's.
|
||||
CMAKE_SHARED_LINKER_FLAGS:STRING=' '
|
||||
|
||||
//Flags used by the linker during debug builds.
|
||||
CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=
|
||||
|
||||
//Flags used by the linker during release minsize builds.
|
||||
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=
|
||||
|
||||
//Flags used by the linker during release builds.
|
||||
CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=
|
||||
|
||||
//Flags used by the linker during Release with Debug Info builds.
|
||||
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=
|
||||
|
||||
//If set, runtime paths are not added when installing shared libraries,
|
||||
// but are added when building.
|
||||
CMAKE_SKIP_INSTALL_RPATH:BOOL=NO
|
||||
|
||||
//If set, runtime paths are not added when using shared libraries.
|
||||
CMAKE_SKIP_RPATH:BOOL=NO
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_STRIP:FILEPATH=/opt/local/bin/strip
|
||||
|
||||
//If true, cmake will use relative paths in makefiles and projects.
|
||||
CMAKE_USE_RELATIVE_PATHS:BOOL=OFF
|
||||
|
||||
//If this value is on, makefiles will be generated without the
|
||||
// .SILENT directive, and all commands will be echoed to the console
|
||||
// during the make. This is useful for debugging only. With Visual
|
||||
// Studio IDE projects all commands are done without /nologo.
|
||||
CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE
|
||||
|
||||
//Path to a program.
|
||||
CMAKE_XCODE_SELECT:FILEPATH=/usr/bin/xcode-select
|
||||
|
||||
//OFF
|
||||
UNITY_BUILD:BOOL=OFF
|
||||
|
||||
//Value Computed by CMake
|
||||
fc_BINARY_DIR:STATIC=/Users/dlarimer/Downloads/fc
|
||||
|
||||
//Dependencies for target
|
||||
fc_LIB_DEPENDS:STATIC=
|
||||
|
||||
//Value Computed by CMake
|
||||
fc_SOURCE_DIR:STATIC=/Users/dlarimer/Downloads/fc
|
||||
|
||||
|
||||
########################
|
||||
# INTERNAL cache entries
|
||||
########################
|
||||
|
||||
//Whether the Boost CHRONO library found
|
||||
Boost_CHRONO_FOUND:INTERNAL=ON
|
||||
//ADVANCED property for variable: Boost_CHRONO_LIBRARY
|
||||
Boost_CHRONO_LIBRARY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_CHRONO_LIBRARY_DEBUG
|
||||
Boost_CHRONO_LIBRARY_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_CHRONO_LIBRARY_RELEASE
|
||||
Boost_CHRONO_LIBRARY_RELEASE-ADVANCED:INTERNAL=1
|
||||
//Whether the Boost CONTEXT library found
|
||||
Boost_CONTEXT_FOUND:INTERNAL=ON
|
||||
//ADVANCED property for variable: Boost_CONTEXT_LIBRARY
|
||||
Boost_CONTEXT_LIBRARY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_CONTEXT_LIBRARY_DEBUG
|
||||
Boost_CONTEXT_LIBRARY_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_CONTEXT_LIBRARY_RELEASE
|
||||
Boost_CONTEXT_LIBRARY_RELEASE-ADVANCED:INTERNAL=1
|
||||
//Whether the Boost DATE_TIME library found
|
||||
Boost_DATE_TIME_FOUND:INTERNAL=ON
|
||||
//ADVANCED property for variable: Boost_DATE_TIME_LIBRARY
|
||||
Boost_DATE_TIME_LIBRARY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_DATE_TIME_LIBRARY_DEBUG
|
||||
Boost_DATE_TIME_LIBRARY_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_DATE_TIME_LIBRARY_RELEASE
|
||||
Boost_DATE_TIME_LIBRARY_RELEASE-ADVANCED:INTERNAL=1
|
||||
//Whether the Boost FILESYSTEM library found
|
||||
Boost_FILESYSTEM_FOUND:INTERNAL=ON
|
||||
//ADVANCED property for variable: Boost_FILESYSTEM_LIBRARY
|
||||
Boost_FILESYSTEM_LIBRARY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_FILESYSTEM_LIBRARY_DEBUG
|
||||
Boost_FILESYSTEM_LIBRARY_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_FILESYSTEM_LIBRARY_RELEASE
|
||||
Boost_FILESYSTEM_LIBRARY_RELEASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_INCLUDE_DIR
|
||||
Boost_INCLUDE_DIR-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_LIBRARY_DIRS
|
||||
Boost_LIBRARY_DIRS-ADVANCED:INTERNAL=1
|
||||
//The library version string for boost libraries
|
||||
Boost_LIB_VERSION:INTERNAL=1_51
|
||||
//Whether the Boost PROGRAM_OPTIONS library found
|
||||
Boost_PROGRAM_OPTIONS_FOUND:INTERNAL=ON
|
||||
//ADVANCED property for variable: Boost_PROGRAM_OPTIONS_LIBRARY
|
||||
Boost_PROGRAM_OPTIONS_LIBRARY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG
|
||||
Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE
|
||||
Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE-ADVANCED:INTERNAL=1
|
||||
//Whether the Boost SERIALIZATION library found
|
||||
Boost_SERIALIZATION_FOUND:INTERNAL=ON
|
||||
//ADVANCED property for variable: Boost_SERIALIZATION_LIBRARY
|
||||
Boost_SERIALIZATION_LIBRARY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_SERIALIZATION_LIBRARY_DEBUG
|
||||
Boost_SERIALIZATION_LIBRARY_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_SERIALIZATION_LIBRARY_RELEASE
|
||||
Boost_SERIALIZATION_LIBRARY_RELEASE-ADVANCED:INTERNAL=1
|
||||
//Whether the Boost SIGNALS library found
|
||||
Boost_SIGNALS_FOUND:INTERNAL=ON
|
||||
//ADVANCED property for variable: Boost_SIGNALS_LIBRARY
|
||||
Boost_SIGNALS_LIBRARY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_SIGNALS_LIBRARY_DEBUG
|
||||
Boost_SIGNALS_LIBRARY_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_SIGNALS_LIBRARY_RELEASE
|
||||
Boost_SIGNALS_LIBRARY_RELEASE-ADVANCED:INTERNAL=1
|
||||
//Whether the Boost SYSTEM library found
|
||||
Boost_SYSTEM_FOUND:INTERNAL=ON
|
||||
//ADVANCED property for variable: Boost_SYSTEM_LIBRARY
|
||||
Boost_SYSTEM_LIBRARY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_SYSTEM_LIBRARY_DEBUG
|
||||
Boost_SYSTEM_LIBRARY_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_SYSTEM_LIBRARY_RELEASE
|
||||
Boost_SYSTEM_LIBRARY_RELEASE-ADVANCED:INTERNAL=1
|
||||
//Whether the Boost THREAD library found
|
||||
Boost_THREAD_FOUND:INTERNAL=ON
|
||||
//ADVANCED property for variable: Boost_THREAD_LIBRARY
|
||||
Boost_THREAD_LIBRARY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_THREAD_LIBRARY_DEBUG
|
||||
Boost_THREAD_LIBRARY_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_THREAD_LIBRARY_RELEASE
|
||||
Boost_THREAD_LIBRARY_RELEASE-ADVANCED:INTERNAL=1
|
||||
//Whether the Boost UNIT_TEST_FRAMEWORK library found
|
||||
Boost_UNIT_TEST_FRAMEWORK_FOUND:INTERNAL=ON
|
||||
//ADVANCED property for variable: Boost_UNIT_TEST_FRAMEWORK_LIBRARY
|
||||
Boost_UNIT_TEST_FRAMEWORK_LIBRARY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_UNIT_TEST_FRAMEWORK_LIBRARY_DEBUG
|
||||
Boost_UNIT_TEST_FRAMEWORK_LIBRARY_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: Boost_UNIT_TEST_FRAMEWORK_LIBRARY_RELEASE
|
||||
Boost_UNIT_TEST_FRAMEWORK_LIBRARY_RELEASE-ADVANCED:INTERNAL=1
|
||||
//The version number for boost libraries
|
||||
Boost_VERSION:INTERNAL=105100
|
||||
//ADVANCED property for variable: CMAKE_AR
|
||||
CMAKE_AR-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_BUILD_TOOL
|
||||
CMAKE_BUILD_TOOL-ADVANCED:INTERNAL=1
|
||||
//What is the target build tool cmake is generating for.
|
||||
CMAKE_BUILD_TOOL:INTERNAL=/usr/bin/make
|
||||
//This is the directory where this CMakeCache.txt was created
|
||||
CMAKE_CACHEFILE_DIR:INTERNAL=/Users/dlarimer/Downloads/fc
|
||||
//Major version of cmake used to create the current loaded cache
|
||||
CMAKE_CACHE_MAJOR_VERSION:INTERNAL=2
|
||||
//Minor version of cmake used to create the current loaded cache
|
||||
CMAKE_CACHE_MINOR_VERSION:INTERNAL=8
|
||||
//Patch version of cmake used to create the current loaded cache
|
||||
CMAKE_CACHE_PATCH_VERSION:INTERNAL=8
|
||||
//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE
|
||||
CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1
|
||||
//Path to CMake executable.
|
||||
CMAKE_COMMAND:INTERNAL=/opt/local/bin/cmake
|
||||
//Path to cpack program executable.
|
||||
CMAKE_CPACK_COMMAND:INTERNAL=/opt/local/bin/cpack
|
||||
//Path to ctest program executable.
|
||||
CMAKE_CTEST_COMMAND:INTERNAL=/opt/local/bin/ctest
|
||||
//ADVANCED property for variable: CMAKE_CXX_COMPILER
|
||||
CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1
|
||||
CMAKE_CXX_COMPILER_WORKS:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_FLAGS
|
||||
CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG
|
||||
CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_C_COMPILER
|
||||
CMAKE_C_COMPILER-ADVANCED:INTERNAL=1
|
||||
CMAKE_C_COMPILER_WORKS:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_C_FLAGS
|
||||
CMAKE_C_FLAGS-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG
|
||||
CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL
|
||||
CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||
//Result of TRY_COMPILE
|
||||
CMAKE_DETERMINE_CXX_ABI_COMPILED:INTERNAL=TRUE
|
||||
//Result of TRY_COMPILE
|
||||
CMAKE_DETERMINE_C_ABI_COMPILED:INTERNAL=TRUE
|
||||
//Path to cache edit program executable.
|
||||
CMAKE_EDIT_COMMAND:INTERNAL=/opt/local/bin/ccmake
|
||||
//Executable file format
|
||||
CMAKE_EXECUTABLE_FORMAT:INTERNAL=Unknown
|
||||
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS
|
||||
CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG
|
||||
CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL
|
||||
CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE
|
||||
CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1
|
||||
//Name of generator.
|
||||
CMAKE_GENERATOR:INTERNAL=Unix Makefiles
|
||||
//Start directory with the top level CMakeLists.txt file for this
|
||||
// project
|
||||
CMAKE_HOME_DIRECTORY:INTERNAL=/Users/dlarimer/Downloads/fc
|
||||
//ADVANCED property for variable: CMAKE_INSTALL_NAME_TOOL
|
||||
CMAKE_INSTALL_NAME_TOOL-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_LINKER
|
||||
CMAKE_LINKER-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_MAKE_PROGRAM
|
||||
CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS
|
||||
CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG
|
||||
CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL
|
||||
CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE
|
||||
CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_NM
|
||||
CMAKE_NM-ADVANCED:INTERNAL=1
|
||||
//number of local generators
|
||||
CMAKE_NUMBER_OF_LOCAL_GENERATORS:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_OBJCOPY
|
||||
CMAKE_OBJCOPY-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_OBJDUMP
|
||||
CMAKE_OBJDUMP-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_RANLIB
|
||||
CMAKE_RANLIB-ADVANCED:INTERNAL=1
|
||||
//Path to CMake installation.
|
||||
CMAKE_ROOT:INTERNAL=/opt/local/share/cmake-2.8
|
||||
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS
|
||||
CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG
|
||||
CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL
|
||||
CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE
|
||||
CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH
|
||||
CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_SKIP_RPATH
|
||||
CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_STRIP
|
||||
CMAKE_STRIP-ADVANCED:INTERNAL=1
|
||||
//uname command
|
||||
CMAKE_UNAME:INTERNAL=/usr/bin/uname
|
||||
//ADVANCED property for variable: CMAKE_USE_RELATIVE_PATHS
|
||||
CMAKE_USE_RELATIVE_PATHS-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE
|
||||
CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1
|
||||
//ADVANCED property for variable: CMAKE_XCODE_SELECT
|
||||
CMAKE_XCODE_SELECT-ADVANCED:INTERNAL=1
|
||||
|
||||
72
CMakeLists.txt
Normal file
72
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
PROJECT( fc )
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED( VERSION 2.8.0 )
|
||||
|
||||
SET( CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeModules;${CMAKE_MODULE_PATH}" )
|
||||
|
||||
INCLUDE( VersionMacros )
|
||||
INCLUDE( SetupTargetMacros )
|
||||
|
||||
SET( DEFAULT_HEADER_INSTALL_DIR include/\${target} )
|
||||
SET( DEFAULT_LIBRARY_INSTALL_DIR lib/ )
|
||||
SET( DEFAULT_EXECUTABLE_INSTALL_DIR bin/ )
|
||||
SET( CMAKE_DEBUG_POSTFIX _debug )
|
||||
#SET( BUILD_SHARED_LIBS NO )
|
||||
|
||||
SET(Boost_USE_STATIC_LIBS ON)
|
||||
FIND_PACKAGE(Boost 1.50 COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework context )
|
||||
|
||||
|
||||
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR} )
|
||||
LINK_DIRECTORIES( ${Boost_LIBRARY_DIRS} )
|
||||
|
||||
IF( WIN32 )
|
||||
ADD_DEFINITIONS( -DBOOST_CONTEXT_NO_LIB )
|
||||
ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
|
||||
ADD_DEFINITIONS( -D_WIN32_WINNT=0x0501 )
|
||||
ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
|
||||
ELSE(WIN32)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall")
|
||||
ENDIF(WIN32)
|
||||
|
||||
if( UNIX )
|
||||
if( NOT APPLE )
|
||||
set(rt_library rt )
|
||||
set(pthread_library pthread)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option( UNITY_BUILD OFF )
|
||||
|
||||
include_directories( ~/projects/mace/libs/atomic/include )
|
||||
include_directories( ~/projects/mace/libs/context/include )
|
||||
include_directories( ${Boost_INCLUDE_DIR} )
|
||||
include_directories( include )
|
||||
|
||||
set( sources
|
||||
src/json_rpc_connection.cpp
|
||||
src/spin_lock.cpp
|
||||
src/spin_yield_lock.cpp
|
||||
src/task.cpp
|
||||
src/future.cpp
|
||||
src/shared_ptr.cpp
|
||||
src/string.cpp
|
||||
src/json.cpp
|
||||
src/log.cpp
|
||||
src/time.cpp
|
||||
src/stream.cpp
|
||||
src/exception.cpp
|
||||
src/thread.cpp
|
||||
src/value.cpp
|
||||
src/value_cast.cpp
|
||||
)
|
||||
setup_library( fc SOURCES ${sources} )
|
||||
|
||||
add_executable( test_vec tests/vector_test.cpp )
|
||||
target_link_libraries( test_vec fc ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} )
|
||||
|
||||
|
||||
add_executable( unit_tests tests/unit.cpp )
|
||||
target_link_libraries( unit_tests fc ${Boost_CHRONO_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} )
|
||||
|
||||
25
README.md
Normal file
25
README.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Fast Compiliing C++ Library
|
||||
-----------------------------------------
|
||||
|
||||
In my prior attempts at developing MACE what I discovered is that compile times
|
||||
would explode to unreasonable levels that hinder the rate of development more
|
||||
than what can be saved by reduced typing. So I began a quest to get C++ to compile
|
||||
as quickly as Java or C# and the result is this library.
|
||||
|
||||
One of the major drawbacks to templates is that they place everything in header and
|
||||
must be compiled with every run and generate a lot of object code. With Link Time Optimization,
|
||||
the benefit of inline methods mostly disapears, leaving only static vs dynamic polymorphism.
|
||||
|
||||
For the vast majority of applications, a virtual method call is not the bottleneck and the
|
||||
increased compile times costs more than is otherwise justified; therefore, the Fast Compiling C++
|
||||
library opts for virtual interfaces to handle reflection instead of template interfaces. One could
|
||||
argue that both types of reflection could be useful.
|
||||
|
||||
Another source of slowness was the standard template library itself. Most standard template library
|
||||
classes cannot be forward declared and import thousands of lines of code into every compilation unit.
|
||||
|
||||
Another source of slowness is the need to include headers simply because the 'size' of the object must
|
||||
be known. A new utility class allows you to 'forward declare' the size required for certain types which
|
||||
allows you to remove their inclusion from the header file.
|
||||
|
||||
|
||||
217
include/boost/atomic.hpp
Normal file
217
include/boost/atomic.hpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
#ifndef BOOST_ATOMIC_HPP
|
||||
#define BOOST_ATOMIC_HPP
|
||||
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/platform.hpp>
|
||||
#include <boost/atomic/detail/base.hpp>
|
||||
//#include <boost/atomic/detail/integral-casts.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
template<typename T>
|
||||
class atomic : public detail::atomic::internal_atomic<T> {
|
||||
public:
|
||||
typedef detail::atomic::internal_atomic<T> super;
|
||||
|
||||
atomic() {}
|
||||
explicit atomic(T v) : super(v) {}
|
||||
private:
|
||||
atomic(const atomic &);
|
||||
void operator=(const atomic &);
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
class atomic<bool> : private detail::atomic::internal_atomic<bool> {
|
||||
public:
|
||||
typedef detail::atomic::internal_atomic<bool> super;
|
||||
|
||||
atomic() {}
|
||||
explicit atomic(bool v) : super(v) {}
|
||||
|
||||
using super::load;
|
||||
using super::store;
|
||||
using super::compare_exchange_strong;
|
||||
using super::compare_exchange_weak;
|
||||
using super::exchange;
|
||||
using super::is_lock_free;
|
||||
|
||||
operator bool(void) const volatile {return load();}
|
||||
bool operator=(bool v) volatile {store(v); return v;}
|
||||
private:
|
||||
atomic(const atomic &);
|
||||
void operator=(const atomic &);
|
||||
};
|
||||
|
||||
template<>
|
||||
class atomic<void *> : private detail::atomic::internal_atomic<void *, sizeof(void *), int> {
|
||||
public:
|
||||
typedef detail::atomic::internal_atomic<void *, sizeof(void *), int> super;
|
||||
|
||||
atomic() {}
|
||||
explicit atomic(void * p) : super(p) {}
|
||||
using super::load;
|
||||
using super::store;
|
||||
using super::compare_exchange_strong;
|
||||
using super::compare_exchange_weak;
|
||||
using super::exchange;
|
||||
using super::is_lock_free;
|
||||
|
||||
operator void *(void) const volatile {return load();}
|
||||
void * operator=(void * v) volatile {store(v); return v;}
|
||||
|
||||
private:
|
||||
atomic(const atomic &);
|
||||
void * operator=(const atomic &);
|
||||
};
|
||||
|
||||
/* FIXME: pointer arithmetic still missing */
|
||||
|
||||
template<typename T>
|
||||
class atomic<T *> : private detail::atomic::internal_atomic<intptr_t> {
|
||||
public:
|
||||
typedef detail::atomic::internal_atomic<intptr_t> super;
|
||||
|
||||
atomic() {}
|
||||
explicit atomic(T * p) : super((intptr_t)p) {}
|
||||
|
||||
T *load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
return (T*)super::load(order);
|
||||
}
|
||||
void store(T *v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
super::store((intptr_t)v, order);
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T * &expected,
|
||||
T * desired,
|
||||
memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, order, detail::atomic::calculate_failure_order(order));
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T * &expected,
|
||||
T *desired,
|
||||
memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return compare_exchange_weak(expected, desired, order, detail::atomic::calculate_failure_order(order));
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T * &expected,
|
||||
T *desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
intptr_t expected_=(intptr_t)expected;
|
||||
intptr_t desired_=(intptr_t)desired;
|
||||
bool success=super::compare_exchange_weak(expected_, desired_, success_order, failure_order);
|
||||
expected=(T*)expected_;
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T * &expected,
|
||||
T *desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
intptr_t expected_=(intptr_t)expected, desired_=(intptr_t)desired;
|
||||
bool success=super::compare_exchange_strong(expected_, desired_, success_order, failure_order);
|
||||
expected=(T*)expected_;
|
||||
return success;
|
||||
}
|
||||
T *exchange(T * replacement, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return (T*)super::exchange((intptr_t)replacement, order);
|
||||
}
|
||||
using super::is_lock_free;
|
||||
|
||||
operator T *(void) const volatile {return load();}
|
||||
T * operator=(T * v) volatile {store(v); return v;}
|
||||
|
||||
T * fetch_add(ptrdiff_t diff, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return (T*)super::fetch_add(diff*sizeof(T), order);
|
||||
}
|
||||
T * fetch_sub(ptrdiff_t diff, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return (T*)super::fetch_sub(diff*sizeof(T), order);
|
||||
}
|
||||
|
||||
T *operator++(void) volatile {return fetch_add(1)+1;}
|
||||
T *operator++(int) volatile {return fetch_add(1);}
|
||||
T *operator--(void) volatile {return fetch_sub(1)-1;}
|
||||
T *operator--(int) volatile {return fetch_sub(1);}
|
||||
private:
|
||||
atomic(const atomic &);
|
||||
T * operator=(const atomic &);
|
||||
};
|
||||
|
||||
class atomic_flag : private atomic<int> {
|
||||
public:
|
||||
typedef atomic<int> super;
|
||||
using super::is_lock_free;
|
||||
|
||||
atomic_flag(bool initial_state) : super(initial_state?1:0) {}
|
||||
atomic_flag() {}
|
||||
|
||||
bool test_and_set(memory_order order=memory_order_seq_cst)
|
||||
{
|
||||
return super::exchange(1, order) ? true : false;
|
||||
}
|
||||
void clear(memory_order order=memory_order_seq_cst)
|
||||
{
|
||||
super::store(0, order);
|
||||
}
|
||||
};
|
||||
|
||||
typedef atomic<char> atomic_char;
|
||||
typedef atomic<unsigned char> atomic_uchar;
|
||||
typedef atomic<signed char> atomic_schar;
|
||||
typedef atomic<boost::uint8_t> atomic_uint8_t;
|
||||
typedef atomic<boost::int8_t> atomic_int8_t;
|
||||
typedef atomic<unsigned short> atomic_ushort;
|
||||
typedef atomic<short> atomic_short;
|
||||
typedef atomic<boost::uint16_t> atomic_uint16_t;
|
||||
typedef atomic<boost::int16_t> atomic_int16_t;
|
||||
typedef atomic<unsigned int> atomic_uint;
|
||||
typedef atomic<int> atomic_int;
|
||||
typedef atomic<boost::uint32_t> atomic_uint32_t;
|
||||
typedef atomic<boost::int32_t> atomic_int32_t;
|
||||
typedef atomic<unsigned long> atomic_ulong;
|
||||
typedef atomic<long> atomic_long;
|
||||
typedef atomic<boost::uint64_t> atomic_uint64_t;
|
||||
typedef atomic<boost::int64_t> atomic_int64_t;
|
||||
#ifdef BOOST_HAS_LONG_LONG
|
||||
typedef atomic<boost::ulong_long_type> atomic_ullong;
|
||||
typedef atomic<boost::long_long_type> atomic_llong;
|
||||
#endif
|
||||
#ifdef BOOST_ATOMIC_HAVE_GNU_128BIT_INTEGERS
|
||||
typedef atomic<__uint128_t> atomic_uint128_t;
|
||||
typedef atomic<__int128_t> atomic_int128_t;
|
||||
#endif
|
||||
#if BOOST_MSVC >= 1500 && (defined(_M_IA64) || defined(_M_AMD64)) && defined(BOOST_ATOMIC_HAVE_SSE2)
|
||||
typedef atomic<__m128i> atomic_uint128_t;
|
||||
typedef atomic<__m128i> atomic_int128_t;
|
||||
#endif
|
||||
typedef atomic<void*> atomic_address;
|
||||
typedef atomic<bool> atomic_bool;
|
||||
|
||||
static inline void atomic_thread_fence(memory_order order)
|
||||
{
|
||||
detail::atomic::platform_atomic_thread_fence<memory_order>(order);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
186
include/boost/atomic/detail/base.hpp
Normal file
186
include/boost/atomic/detail/base.hpp
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_BASE_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_BASE_HPP
|
||||
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/atomic/detail/fallback.hpp>
|
||||
#include <boost/atomic/detail/builder.hpp>
|
||||
#include <boost/atomic/detail/valid_integral_types.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace atomic {
|
||||
|
||||
static inline memory_order calculate_failure_order(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_acq_rel: return memory_order_acquire;
|
||||
case memory_order_release: return memory_order_relaxed;
|
||||
default: return order;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, unsigned short Size=sizeof(T)>
|
||||
class platform_atomic : public fallback_atomic<T> {
|
||||
public:
|
||||
typedef fallback_atomic<T> super;
|
||||
|
||||
explicit platform_atomic(T v) : super(v) {}
|
||||
platform_atomic() {}
|
||||
protected:
|
||||
typedef typename super::integral_type integral_type;
|
||||
};
|
||||
|
||||
template<typename T, unsigned short Size=sizeof(T)>
|
||||
class platform_atomic_integral : public build_atomic_from_exchange<fallback_atomic<T> > {
|
||||
public:
|
||||
typedef build_atomic_from_exchange<fallback_atomic<T> > super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral() {}
|
||||
protected:
|
||||
typedef typename super::integral_type integral_type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
static inline void platform_atomic_thread_fence(T order)
|
||||
{
|
||||
/* FIXME: this does not provide
|
||||
sequential consistency, need one global
|
||||
variable for that... */
|
||||
platform_atomic<int> a;
|
||||
a.exchange(0, order);
|
||||
}
|
||||
|
||||
template<typename T, unsigned short Size=sizeof(T), typename Int=typename is_integral_type<T>::test>
|
||||
class internal_atomic;
|
||||
|
||||
template<typename T, unsigned short Size>
|
||||
class internal_atomic<T, Size, void> : private detail::atomic::platform_atomic<T> {
|
||||
public:
|
||||
typedef detail::atomic::platform_atomic<T> super;
|
||||
|
||||
internal_atomic() {}
|
||||
explicit internal_atomic(T v) : super(v) {}
|
||||
|
||||
operator T(void) const volatile {return load();}
|
||||
T operator=(T v) volatile {store(v); return v;}
|
||||
|
||||
using super::is_lock_free;
|
||||
using super::load;
|
||||
using super::store;
|
||||
using super::exchange;
|
||||
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return super::compare_exchange_strong(expected, desired, order, calculate_failure_order(order));
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return super::compare_exchange_strong(expected, desired, order, calculate_failure_order(order));
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return super::compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return super::compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
private:
|
||||
internal_atomic(const internal_atomic &);
|
||||
void operator=(const internal_atomic &);
|
||||
};
|
||||
|
||||
template<typename T, unsigned short Size>
|
||||
class internal_atomic<T, Size, int> : private detail::atomic::platform_atomic_integral<T> {
|
||||
public:
|
||||
typedef detail::atomic::platform_atomic_integral<T> super;
|
||||
typedef typename super::integral_type integral_type;
|
||||
|
||||
internal_atomic() {}
|
||||
explicit internal_atomic(T v) : super(v) {}
|
||||
|
||||
using super::is_lock_free;
|
||||
using super::load;
|
||||
using super::store;
|
||||
using super::exchange;
|
||||
using super::fetch_add;
|
||||
using super::fetch_sub;
|
||||
using super::fetch_and;
|
||||
using super::fetch_or;
|
||||
using super::fetch_xor;
|
||||
|
||||
operator integral_type(void) const volatile {return load();}
|
||||
integral_type operator=(integral_type v) volatile {store(v); return v;}
|
||||
|
||||
integral_type operator&=(integral_type c) volatile {return fetch_and(c)&c;}
|
||||
integral_type operator|=(integral_type c) volatile {return fetch_or(c)|c;}
|
||||
integral_type operator^=(integral_type c) volatile {return fetch_xor(c)^c;}
|
||||
|
||||
integral_type operator+=(integral_type c) volatile {return fetch_add(c)+c;}
|
||||
integral_type operator-=(integral_type c) volatile {return fetch_sub(c)-c;}
|
||||
|
||||
integral_type operator++(void) volatile {return fetch_add(1)+1;}
|
||||
integral_type operator++(int) volatile {return fetch_add(1);}
|
||||
integral_type operator--(void) volatile {return fetch_sub(1)-1;}
|
||||
integral_type operator--(int) volatile {return fetch_sub(1);}
|
||||
|
||||
bool compare_exchange_strong(
|
||||
integral_type &expected,
|
||||
integral_type desired,
|
||||
memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return super::compare_exchange_strong(expected, desired, order, calculate_failure_order(order));
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
integral_type &expected,
|
||||
integral_type desired,
|
||||
memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return super::compare_exchange_strong(expected, desired, order, calculate_failure_order(order));
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
integral_type &expected,
|
||||
integral_type desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return super::compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
integral_type &expected,
|
||||
integral_type desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return super::compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
private:
|
||||
internal_atomic(const internal_atomic &);
|
||||
void operator=(const internal_atomic &);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
412
include/boost/atomic/detail/builder.hpp
Normal file
412
include/boost/atomic/detail/builder.hpp
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_BUILDER_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_BUILDER_HPP
|
||||
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/detail/endian.hpp>
|
||||
#include <boost/atomic/detail/valid_integral_types.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace atomic {
|
||||
|
||||
/*
|
||||
given a Base that implements:
|
||||
|
||||
- load(memory_order order)
|
||||
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
||||
|
||||
generates exchange and compare_exchange_strong
|
||||
*/
|
||||
template<typename Base>
|
||||
class build_exchange : public Base {
|
||||
public:
|
||||
typedef typename Base::integral_type integral_type;
|
||||
|
||||
using Base::load;
|
||||
using Base::compare_exchange_weak;
|
||||
|
||||
bool compare_exchange_strong(
|
||||
integral_type &expected,
|
||||
integral_type desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
integral_type expected_save=expected;
|
||||
while(true) {
|
||||
if (compare_exchange_weak(expected, desired, success_order, failure_order)) return true;
|
||||
if (expected_save!=expected) return false;
|
||||
expected=expected_save;
|
||||
}
|
||||
}
|
||||
|
||||
integral_type exchange(integral_type replacement, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
integral_type o=load(memory_order_relaxed);
|
||||
do {} while(!compare_exchange_weak(o, replacement, order, memory_order_relaxed));
|
||||
return o;
|
||||
}
|
||||
|
||||
build_exchange() {}
|
||||
explicit build_exchange(integral_type i) : Base(i) {}
|
||||
};
|
||||
|
||||
/*
|
||||
given a Base that implements:
|
||||
|
||||
- fetch_add_var(integral_type c, memory_order order)
|
||||
- fetch_inc(memory_order order)
|
||||
- fetch_dec(memory_order order)
|
||||
|
||||
creates a fetch_add method that delegates to fetch_inc/fetch_dec if operand
|
||||
is constant +1/-1, and uses fetch_add_var otherwise
|
||||
|
||||
the intention is to allow optimizing the incredibly common case of +1/-1
|
||||
*/
|
||||
template<typename Base>
|
||||
class build_const_fetch_add : public Base {
|
||||
public:
|
||||
typedef typename Base::integral_type integral_type;
|
||||
|
||||
integral_type fetch_add(
|
||||
integral_type c,
|
||||
memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
if (__builtin_constant_p(c)) {
|
||||
switch(c) {
|
||||
case -1: return fetch_dec(order);
|
||||
case 1: return fetch_inc(order);
|
||||
}
|
||||
}
|
||||
return fetch_add_var(c, order);
|
||||
}
|
||||
|
||||
build_const_fetch_add() {}
|
||||
explicit build_const_fetch_add(integral_type i) : Base(i) {}
|
||||
protected:
|
||||
using Base::fetch_add_var;
|
||||
using Base::fetch_inc;
|
||||
using Base::fetch_dec;
|
||||
};
|
||||
|
||||
/*
|
||||
given a Base that implements:
|
||||
|
||||
- load(memory_order order)
|
||||
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
||||
|
||||
generates a -- not very efficient, but correct -- fetch_add operation
|
||||
*/
|
||||
template<typename Base>
|
||||
class build_fetch_add : public Base {
|
||||
public:
|
||||
typedef typename Base::integral_type integral_type;
|
||||
|
||||
using Base::compare_exchange_weak;
|
||||
|
||||
integral_type fetch_add(
|
||||
integral_type c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
integral_type o=Base::load(memory_order_relaxed), n;
|
||||
do {n=o+c;} while(!compare_exchange_weak(o, n, order, memory_order_relaxed));
|
||||
return o;
|
||||
}
|
||||
|
||||
build_fetch_add() {}
|
||||
explicit build_fetch_add(integral_type i) : Base(i) {}
|
||||
};
|
||||
|
||||
/*
|
||||
given a Base that implements:
|
||||
|
||||
- fetch_add(integral_type c, memory_order order)
|
||||
|
||||
generates fetch_sub and post/pre- increment/decrement operators
|
||||
*/
|
||||
template<typename Base>
|
||||
class build_arithmeticops : public Base {
|
||||
public:
|
||||
typedef typename Base::integral_type integral_type;
|
||||
|
||||
using Base::fetch_add;
|
||||
|
||||
integral_type fetch_sub(
|
||||
integral_type c,
|
||||
memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
#endif
|
||||
return fetch_add(-c, order);
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
build_arithmeticops() {}
|
||||
explicit build_arithmeticops(integral_type i) : Base(i) {}
|
||||
};
|
||||
|
||||
/*
|
||||
given a Base that implements:
|
||||
|
||||
- load(memory_order order)
|
||||
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
||||
|
||||
generates -- not very efficient, but correct -- fetch_and, fetch_or and fetch_xor operators
|
||||
*/
|
||||
template<typename Base>
|
||||
class build_logicops : public Base {
|
||||
public:
|
||||
typedef typename Base::integral_type integral_type;
|
||||
|
||||
using Base::compare_exchange_weak;
|
||||
using Base::load;
|
||||
|
||||
integral_type fetch_and(integral_type c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
integral_type o=load(memory_order_relaxed), n;
|
||||
do {n=o&c;} while(!compare_exchange_weak(o, n, order, memory_order_relaxed));
|
||||
return o;
|
||||
}
|
||||
integral_type fetch_or(integral_type c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
integral_type o=load(memory_order_relaxed), n;
|
||||
do {n=o|c;} while(!compare_exchange_weak(o, n, order, memory_order_relaxed));
|
||||
return o;
|
||||
}
|
||||
integral_type fetch_xor(integral_type c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
integral_type o=load(memory_order_relaxed), n;
|
||||
do {n=o^c;} while(!compare_exchange_weak(o, n, order, memory_order_relaxed));
|
||||
return o;
|
||||
}
|
||||
|
||||
build_logicops() {}
|
||||
build_logicops(integral_type i) : Base(i) {}
|
||||
};
|
||||
|
||||
/*
|
||||
given a Base that implements:
|
||||
|
||||
- load(memory_order order)
|
||||
- store(integral_type i, memory_order order)
|
||||
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
||||
|
||||
generates the full set of atomic operations for integral types
|
||||
*/
|
||||
template<typename Base>
|
||||
class build_atomic_from_minimal : public build_logicops< build_arithmeticops< build_fetch_add< build_exchange<Base> > > > {
|
||||
public:
|
||||
typedef build_logicops< build_arithmeticops< build_fetch_add< build_exchange<Base> > > > super;
|
||||
typedef typename super::integral_type integral_type;
|
||||
|
||||
build_atomic_from_minimal(void) {}
|
||||
build_atomic_from_minimal(typename super::integral_type i) : super(i) {}
|
||||
};
|
||||
|
||||
/*
|
||||
given a Base that implements:
|
||||
|
||||
- load(memory_order order)
|
||||
- store(integral_type i, memory_order order)
|
||||
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
||||
- compare_exchange_strong(integral_type &expected, integral_type desired, memory_order order)
|
||||
- exchange(integral_type replacement, memory_order order)
|
||||
- fetch_add_var(integral_type c, memory_order order)
|
||||
- fetch_inc(memory_order order)
|
||||
- fetch_dec(memory_order order)
|
||||
|
||||
generates the full set of atomic operations for integral types
|
||||
*/
|
||||
template<typename Base>
|
||||
class build_atomic_from_typical : public build_logicops< build_arithmeticops< build_const_fetch_add<Base> > > {
|
||||
public:
|
||||
typedef build_logicops< build_arithmeticops< build_const_fetch_add<Base> > > super;
|
||||
typedef typename super::integral_type integral_type;
|
||||
|
||||
build_atomic_from_typical(void) {}
|
||||
build_atomic_from_typical(typename super::integral_type i) : super(i) {}
|
||||
};
|
||||
|
||||
/*
|
||||
given a Base that implements:
|
||||
|
||||
- load(memory_order order)
|
||||
- store(integral_type i, memory_order order)
|
||||
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
||||
- compare_exchange_strong(integral_type &expected, integral_type desired, memory_order order)
|
||||
- exchange(integral_type replacement, memory_order order)
|
||||
- fetch_add(integral_type c, memory_order order)
|
||||
|
||||
generates the full set of atomic operations for integral types
|
||||
*/
|
||||
template<typename Base>
|
||||
class build_atomic_from_add : public build_logicops< build_arithmeticops<Base> > {
|
||||
public:
|
||||
typedef build_logicops< build_arithmeticops<Base> > super;
|
||||
typedef typename super::integral_type integral_type;
|
||||
|
||||
build_atomic_from_add(void) {}
|
||||
build_atomic_from_add(typename super::integral_type i) : super(i) {}
|
||||
};
|
||||
|
||||
/*
|
||||
given a Base that implements:
|
||||
|
||||
- load(memory_order order)
|
||||
- store(integral_type i, memory_order order)
|
||||
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
||||
- compare_exchange_strong(integral_type &expected, integral_type desired, memory_order order)
|
||||
- exchange(integral_type replacement, memory_order order)
|
||||
|
||||
generates the full set of atomic operations for integral types
|
||||
*/
|
||||
template<typename Base>
|
||||
class build_atomic_from_exchange : public build_logicops< build_arithmeticops< build_fetch_add<Base> > > {
|
||||
public:
|
||||
typedef build_logicops< build_arithmeticops< build_fetch_add<Base> > > super;
|
||||
typedef typename super::integral_type integral_type;
|
||||
|
||||
build_atomic_from_exchange(void) {}
|
||||
build_atomic_from_exchange(typename super::integral_type i) : super(i) {}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
given a Base that implements:
|
||||
|
||||
- compare_exchange_weak()
|
||||
|
||||
generates load, store and compare_exchange_weak for a smaller
|
||||
data type (e.g. an atomic "byte" embedded into a temporary
|
||||
and properly aligned atomic "int").
|
||||
*/
|
||||
template<typename Base, typename Type>
|
||||
class build_base_from_larger_type {
|
||||
public:
|
||||
typedef Type integral_type;
|
||||
|
||||
build_base_from_larger_type() {}
|
||||
build_base_from_larger_type(integral_type t) {store(t, memory_order_relaxed);}
|
||||
|
||||
integral_type load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
larger_integral_type v=get_base().load(order);
|
||||
return extract(v);
|
||||
}
|
||||
bool compare_exchange_weak(integral_type &expected,
|
||||
integral_type desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
larger_integral_type expected_;
|
||||
larger_integral_type desired_;
|
||||
|
||||
expected_=get_base().load(memory_order_relaxed);
|
||||
expected_=insert(expected_, expected);
|
||||
desired_=insert(expected_, desired);
|
||||
bool success=get_base().compare_exchange_weak(expected_, desired_, success_order, failure_order);
|
||||
expected=extract(expected_);
|
||||
return success;
|
||||
}
|
||||
void store(integral_type v,
|
||||
memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
larger_integral_type expected, desired;
|
||||
expected=get_base().load(memory_order_relaxed);
|
||||
do {
|
||||
desired=insert(expected, v);
|
||||
} while(!get_base().compare_exchange_weak(expected, desired, order, memory_order_relaxed));
|
||||
}
|
||||
|
||||
bool is_lock_free(void)
|
||||
{
|
||||
return get_base().is_lock_free();
|
||||
}
|
||||
private:
|
||||
typedef typename Base::integral_type larger_integral_type;
|
||||
|
||||
const Base &get_base(void) const volatile
|
||||
{
|
||||
intptr_t address=(intptr_t)this;
|
||||
address&=~(sizeof(larger_integral_type)-1);
|
||||
return *reinterpret_cast<const Base *>(address);
|
||||
}
|
||||
Base &get_base(void) volatile
|
||||
{
|
||||
intptr_t address=(intptr_t)this;
|
||||
address&=~(sizeof(larger_integral_type)-1);
|
||||
return *reinterpret_cast<Base *>(address);
|
||||
}
|
||||
unsigned int get_offset(void) const volatile
|
||||
{
|
||||
intptr_t address=(intptr_t)this;
|
||||
address&=(sizeof(larger_integral_type)-1);
|
||||
return address;
|
||||
}
|
||||
|
||||
unsigned int get_shift(void) const volatile
|
||||
{
|
||||
#if defined(BOOST_LITTLE_ENDIAN)
|
||||
return get_offset()*8;
|
||||
#elif defined(BOOST_BIG_ENDIAN)
|
||||
return (sizeof(larger_integral_type)-sizeof(integral_type)-get_offset())*8;
|
||||
#else
|
||||
#error "Unknown endian"
|
||||
#endif
|
||||
}
|
||||
|
||||
integral_type extract(larger_integral_type v) const volatile
|
||||
{
|
||||
return v>>get_shift();
|
||||
}
|
||||
|
||||
larger_integral_type insert(larger_integral_type target, integral_type source) const volatile
|
||||
{
|
||||
larger_integral_type tmp=source;
|
||||
larger_integral_type mask=(larger_integral_type)-1;
|
||||
|
||||
mask=~(mask<<(8*sizeof(integral_type)));
|
||||
|
||||
mask=mask<<get_shift();
|
||||
tmp=tmp<<get_shift();
|
||||
|
||||
tmp=(tmp & mask) | (target & ~mask);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
integral_type i;
|
||||
};
|
||||
|
||||
/*
|
||||
given a Base that implements:
|
||||
|
||||
- compare_exchange_weak()
|
||||
|
||||
generates the full set of atomic ops for a smaller
|
||||
data type (e.g. an atomic "byte" embedded into a temporary
|
||||
and properly aligned atomic "int").
|
||||
*/
|
||||
template<typename Base, typename Type>
|
||||
class build_atomic_from_larger_type : public build_atomic_from_minimal< build_base_from_larger_type<Base, Type> > {
|
||||
public:
|
||||
typedef build_atomic_from_minimal< build_base_from_larger_type<Base, Type> > super;
|
||||
//typedef typename super::integral_type integral_type;
|
||||
typedef Type integral_type;
|
||||
|
||||
build_atomic_from_larger_type() {}
|
||||
build_atomic_from_larger_type(integral_type v) : super(v) {}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
76
include/boost/atomic/detail/fallback.hpp
Normal file
76
include/boost/atomic/detail/fallback.hpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_FALLBACK_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_FALLBACK_HPP
|
||||
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <string.h>
|
||||
#include <boost/smart_ptr/detail/spinlock_pool.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace atomic {
|
||||
|
||||
template<typename T>
|
||||
class fallback_atomic {
|
||||
public:
|
||||
fallback_atomic(void) {}
|
||||
explicit fallback_atomic(const T &t) {memcpy(&i, &t, sizeof(T));}
|
||||
|
||||
void store(const T &t, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
detail::spinlock_pool<0>::scoped_lock guard(const_cast<T*>(&i));
|
||||
memcpy((void*)&i, &t, sizeof(T));
|
||||
}
|
||||
T load(memory_order /*order*/=memory_order_seq_cst) volatile const
|
||||
{
|
||||
detail::spinlock_pool<0>::scoped_lock guard(const_cast<T*>(&i));
|
||||
T tmp;
|
||||
memcpy(&tmp, (T*)&i, sizeof(T));
|
||||
return tmp;
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order /*success_order*/,
|
||||
memory_order /*failure_order*/) volatile
|
||||
{
|
||||
detail::spinlock_pool<0>::scoped_lock guard(const_cast<T*>(&i));
|
||||
if (memcmp((void*)&i, &expected, sizeof(T))==0) {
|
||||
memcpy((void*)&i, &desired, sizeof(T));
|
||||
return true;
|
||||
} else {
|
||||
memcpy(&expected, (void*)&i, sizeof(T));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T replacement, memory_order /*order*/=memory_order_seq_cst) volatile
|
||||
{
|
||||
detail::spinlock_pool<0>::scoped_lock guard(const_cast<T*>(&i));
|
||||
T tmp;
|
||||
memcpy(&tmp, (void*)&i, sizeof(T));
|
||||
memcpy((void*)&i, &replacement, sizeof(T));
|
||||
return tmp;
|
||||
}
|
||||
bool is_lock_free(void) const volatile {return false;}
|
||||
protected:
|
||||
T i;
|
||||
typedef T integral_type;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
354
include/boost/atomic/detail/gcc-alpha.hpp
Normal file
354
include/boost/atomic/detail/gcc-alpha.hpp
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_GCC_ALPHA_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_GCC_ALPHA_HPP
|
||||
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/atomic/detail/base.hpp>
|
||||
#include <boost/atomic/detail/builder.hpp>
|
||||
|
||||
/*
|
||||
Refer to http://h71000.www7.hp.com/doc/82final/5601/5601pro_004.html
|
||||
(HP OpenVMS systems documentation) and the alpha reference manual.
|
||||
*/
|
||||
|
||||
/*
|
||||
NB: The most natural thing would be to write the increment/decrement
|
||||
operators along the following lines:
|
||||
|
||||
__asm__ __volatile__(
|
||||
"1: ldl_l %0,%1 \n"
|
||||
"addl %0,1,%0 \n"
|
||||
"stl_c %0,%1 \n"
|
||||
"beq %0,1b\n"
|
||||
: "=&b" (tmp)
|
||||
: "m" (value)
|
||||
: "cc"
|
||||
);
|
||||
|
||||
However according to the comments on the HP website and matching
|
||||
comments in the Linux kernel sources this defies branch prediction,
|
||||
as the cpu assumes that backward branches are always taken; so
|
||||
instead copy the trick from the Linux kernel, introduce a forward
|
||||
branch and back again.
|
||||
|
||||
I have, however, had a hard time measuring the difference between
|
||||
the two versions in microbenchmarks -- I am leaving it in nevertheless
|
||||
as it apparently does not hurt either.
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace atomic {
|
||||
|
||||
static inline void fence_before(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_consume:
|
||||
case memory_order_release:
|
||||
case memory_order_acq_rel:
|
||||
case memory_order_seq_cst:
|
||||
__asm__ __volatile__ ("mb" ::: "memory");
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void fence_after(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_acquire:
|
||||
case memory_order_acq_rel:
|
||||
case memory_order_seq_cst:
|
||||
__asm__ __volatile__ ("mb" ::: "memory");
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void platform_atomic_thread_fence(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_acquire:
|
||||
case memory_order_consume:
|
||||
case memory_order_release:
|
||||
case memory_order_acq_rel:
|
||||
case memory_order_seq_cst:
|
||||
__asm__ __volatile__ ("mb" ::: "memory");
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class atomic_alpha_32 {
|
||||
public:
|
||||
typedef T integral_type;
|
||||
explicit atomic_alpha_32(T v) : i(v) {}
|
||||
atomic_alpha_32() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=*reinterpret_cast<volatile const int *>(&i);
|
||||
fence_after(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
*reinterpret_cast<volatile int *>(&i)=(int)v;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
fence_before(success_order);
|
||||
int current, success;
|
||||
__asm__ __volatile__(
|
||||
"1: ldl_l %2, %4\n"
|
||||
"cmpeq %2, %0, %3\n"
|
||||
"mov %2, %0\n"
|
||||
"beq %3, 3f\n"
|
||||
"stl_c %1, %4\n"
|
||||
"2:\n"
|
||||
|
||||
".subsection 2\n"
|
||||
"3: mov %3, %1\n"
|
||||
"br 2b\n"
|
||||
".previous\n"
|
||||
|
||||
: "+&r" (expected), "+&r" (desired), "=&r"(current), "=&r"(success)
|
||||
: "m" (i)
|
||||
:
|
||||
);
|
||||
if (desired) fence_after(success_order);
|
||||
else fence_after(failure_order);
|
||||
return desired;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
protected:
|
||||
inline T fetch_add_var(T c, memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, modified;
|
||||
__asm__ __volatile__(
|
||||
"1: ldl_l %0, %2\n"
|
||||
"addl %0, %3, %1\n"
|
||||
"stl_c %1, %2\n"
|
||||
"beq %1, 2f\n"
|
||||
|
||||
".subsection 2\n"
|
||||
"2: br 1b\n"
|
||||
".previous\n"
|
||||
|
||||
: "=&r" (original), "=&r" (modified)
|
||||
: "m" (i), "r" (c)
|
||||
:
|
||||
);
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
inline T fetch_inc(memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
int original, modified;
|
||||
__asm__ __volatile__(
|
||||
"1: ldl_l %0, %2\n"
|
||||
"addl %0, 1, %1\n"
|
||||
"stl_c %1, %2\n"
|
||||
"beq %1, 2f\n"
|
||||
|
||||
".subsection 2\n"
|
||||
"2: br 1b\n"
|
||||
".previous\n"
|
||||
|
||||
: "=&r" (original), "=&r" (modified)
|
||||
: "m" (i)
|
||||
:
|
||||
);
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
inline T fetch_dec(memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
int original, modified;
|
||||
__asm__ __volatile__(
|
||||
"1: ldl_l %0, %2\n"
|
||||
"subl %0, 1, %1\n"
|
||||
"stl_c %1, %2\n"
|
||||
"beq %1, 2f\n"
|
||||
|
||||
".subsection 2\n"
|
||||
"2: br 1b\n"
|
||||
".previous\n"
|
||||
|
||||
: "=&r" (original), "=&r" (modified)
|
||||
: "m" (i)
|
||||
:
|
||||
);
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
private:
|
||||
T i;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class atomic_alpha_64 {
|
||||
public:
|
||||
typedef T integral_type;
|
||||
explicit atomic_alpha_64(T v) : i(v) {}
|
||||
atomic_alpha_64() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=*reinterpret_cast<volatile const T *>(&i);
|
||||
fence_after(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
*reinterpret_cast<volatile T *>(&i)=v;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
fence_before(success_order);
|
||||
int current, success;
|
||||
__asm__ __volatile__(
|
||||
"1: ldq_l %2, %4\n"
|
||||
"cmpeq %2, %0, %3\n"
|
||||
"mov %2, %0\n"
|
||||
"beq %3, 3f\n"
|
||||
"stq_c %1, %4\n"
|
||||
"2:\n"
|
||||
|
||||
".subsection 2\n"
|
||||
"3: mov %3, %1\n"
|
||||
"br 2b\n"
|
||||
".previous\n"
|
||||
|
||||
: "+&r" (expected), "+&r" (desired), "=&r"(current), "=&r"(success)
|
||||
: "m" (i)
|
||||
:
|
||||
);
|
||||
if (desired) fence_after(success_order);
|
||||
else fence_after(failure_order);
|
||||
return desired;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
protected:
|
||||
inline T fetch_add_var(T c, memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, modified;
|
||||
__asm__ __volatile__(
|
||||
"1: ldq_l %0, %2\n"
|
||||
"addq %0, %3, %1\n"
|
||||
"stq_c %1, %2\n"
|
||||
"beq %1, 2f\n"
|
||||
|
||||
".subsection 2\n"
|
||||
"2: br 1b\n"
|
||||
".previous\n"
|
||||
|
||||
: "=&r" (original), "=&r" (modified)
|
||||
: "m" (i), "r" (c)
|
||||
:
|
||||
);
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
inline T fetch_inc(memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, modified;
|
||||
__asm__ __volatile__(
|
||||
"1: ldq_l %0, %2\n"
|
||||
"addq %0, 1, %1\n"
|
||||
"stq_c %1, %2\n"
|
||||
"beq %1, 2f\n"
|
||||
|
||||
".subsection 2\n"
|
||||
"2: br 1b\n"
|
||||
".previous\n"
|
||||
|
||||
: "=&r" (original), "=&r" (modified)
|
||||
: "m" (i)
|
||||
:
|
||||
);
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
inline T fetch_dec(memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, modified;
|
||||
__asm__ __volatile__(
|
||||
"1: ldq_l %0, %2\n"
|
||||
"subq %0, 1, %1\n"
|
||||
"stq_c %1, %2\n"
|
||||
"beq %1, 2f\n"
|
||||
|
||||
".subsection 2\n"
|
||||
"2: br 1b\n"
|
||||
".previous\n"
|
||||
|
||||
: "=&r" (original), "=&r" (modified)
|
||||
: "m" (i)
|
||||
:
|
||||
);
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
private:
|
||||
T i;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 4> : public build_atomic_from_typical<build_exchange<atomic_alpha_32<T> > > {
|
||||
public:
|
||||
typedef build_atomic_from_typical<build_exchange<atomic_alpha_32<T> > > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 8> : public build_atomic_from_typical<build_exchange<atomic_alpha_64<T> > > {
|
||||
public:
|
||||
typedef build_atomic_from_typical<build_exchange<atomic_alpha_64<T> > > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 1>: public build_atomic_from_larger_type<atomic_alpha_32<uint32_t>, T> {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_alpha_32<uint32_t>, T> super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 2>: public build_atomic_from_larger_type<atomic_alpha_32<uint32_t>, T> {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_alpha_32<uint32_t>, T> super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
299
include/boost/atomic/detail/gcc-armv6+.hpp
Normal file
299
include/boost/atomic/detail/gcc-armv6+.hpp
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_GCC_ARMV6P_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_GCC_ARMV6P_HPP
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
// Copyright (c) 2009 Phil Endecott
|
||||
// ARM Code by Phil Endecott, based on other architectures.
|
||||
|
||||
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/detail/base.hpp>
|
||||
#include <boost/atomic/detail/builder.hpp>
|
||||
|
||||
// From the ARM Architecture Reference Manual for architecture v6:
|
||||
//
|
||||
// LDREX{<cond>} <Rd>, [<Rn>]
|
||||
// <Rd> Specifies the destination register for the memory word addressed by <Rd>
|
||||
// <Rn> Specifies the register containing the address.
|
||||
//
|
||||
// STREX{<cond>} <Rd>, <Rm>, [<Rn>]
|
||||
// <Rd> Specifies the destination register for the returned status value.
|
||||
// 0 if the operation updates memory
|
||||
// 1 if the operation fails to update memory
|
||||
// <Rm> Specifies the register containing the word to be stored to memory.
|
||||
// <Rn> Specifies the register containing the address.
|
||||
// Rd must not be the same register is Rm or Rn.
|
||||
//
|
||||
// ARM v7 is like ARM v6 plus:
|
||||
// There are half-word and byte versions of the LDREX and STREX instructions,
|
||||
// LDREXH, LDREXB, STREXH and STREXB.
|
||||
// There are also double-word versions, LDREXD and STREXD.
|
||||
// (Actually it looks like these are available from version 6k onwards.)
|
||||
// FIXME these are not yet used; should be mostly a matter of copy-and-paste.
|
||||
// I think you can supply an immediate offset to the address.
|
||||
//
|
||||
// A memory barrier is effected using a "co-processor 15" instruction,
|
||||
// though a separate assembler mnemonic is available for it in v7.
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace atomic {
|
||||
|
||||
|
||||
// "Thumb 1" is a subset of the ARM instruction set that uses a 16-bit encoding. It
|
||||
// doesn't include all instructions and in particular it doesn't include the co-processor
|
||||
// instruction used for the memory barrier or the load-locked/store-conditional
|
||||
// instructions. So, if we're compiling in "Thumb 1" mode, we need to wrap all of our
|
||||
// asm blocks with code to temporarily change to ARM mode.
|
||||
//
|
||||
// You can only change between ARM and Thumb modes when branching using the bx instruction.
|
||||
// bx takes an address specified in a register. The least significant bit of the address
|
||||
// indicates the mode, so 1 is added to indicate that the destination code is Thumb.
|
||||
// A temporary register is needed for the address and is passed as an argument to these
|
||||
// macros. It must be one of the "low" registers accessible to Thumb code, specified
|
||||
// usng the "l" attribute in the asm statement.
|
||||
//
|
||||
// Architecture v7 introduces "Thumb 2", which does include (almost?) all of the ARM
|
||||
// instruction set. So in v7 we don't need to change to ARM mode; we can write "universal
|
||||
// assembler" which will assemble to Thumb 2 or ARM code as appropriate. The only thing
|
||||
// we need to do to make this "universal" assembler mode work is to insert "IT" instructions
|
||||
// to annotate the conditional instructions. These are ignored in other modes (e.g. v6),
|
||||
// so they can always be present.
|
||||
|
||||
#if defined(__thumb__) && !defined(__ARM_ARCH_7A__)
|
||||
// FIXME also other v7 variants.
|
||||
#define BOOST_ATOMIC_ARM_ASM_START(TMPREG) "adr " #TMPREG ", 1f\n" "bx " #TMPREG "\n" ".arm\n" ".align 4\n" "1: "
|
||||
#define BOOST_ATOMIC_ARM_ASM_END(TMPREG) "adr " #TMPREG ", 1f + 1\n" "bx " #TMPREG "\n" ".thumb\n" ".align 2\n" "1: "
|
||||
|
||||
#else
|
||||
// The tmpreg is wasted in this case, which is non-optimal.
|
||||
#define BOOST_ATOMIC_ARM_ASM_START(TMPREG)
|
||||
#define BOOST_ATOMIC_ARM_ASM_END(TMPREG)
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__ARM_ARCH_7A__)
|
||||
// FIXME ditto.
|
||||
#define BOOST_ATOMIC_ARM_DMB "dmb\n"
|
||||
#else
|
||||
#define BOOST_ATOMIC_ARM_DMB "mcr\tp15, 0, r0, c7, c10, 5\n"
|
||||
#endif
|
||||
|
||||
// There is also a "Data Synchronisation Barrier" DSB; this exists in v6 as another co-processor
|
||||
// instruction like the above.
|
||||
|
||||
|
||||
static inline void fence_before(memory_order order)
|
||||
{
|
||||
// FIXME I don't understand enough about barriers to know what this should do.
|
||||
switch(order) {
|
||||
case memory_order_release:
|
||||
case memory_order_acq_rel:
|
||||
case memory_order_seq_cst:
|
||||
int brtmp;
|
||||
__asm__ __volatile__ (
|
||||
BOOST_ATOMIC_ARM_ASM_START(%0)
|
||||
BOOST_ATOMIC_ARM_DMB
|
||||
BOOST_ATOMIC_ARM_ASM_END(%0)
|
||||
: "=&l" (brtmp) :: "memory"
|
||||
);
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void fence_after(memory_order order)
|
||||
{
|
||||
// FIXME I don't understand enough about barriers to know what this should do.
|
||||
switch(order) {
|
||||
case memory_order_acquire:
|
||||
case memory_order_acq_rel:
|
||||
case memory_order_seq_cst:
|
||||
int brtmp;
|
||||
__asm__ __volatile__ (
|
||||
BOOST_ATOMIC_ARM_ASM_START(%0)
|
||||
BOOST_ATOMIC_ARM_DMB
|
||||
BOOST_ATOMIC_ARM_ASM_END(%0)
|
||||
: "=&l" (brtmp) :: "memory"
|
||||
);
|
||||
case memory_order_consume:
|
||||
__asm__ __volatile__ ("" ::: "memory");
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
#undef BOOST_ATOMIC_ARM_DMB
|
||||
|
||||
|
||||
template<typename T>
|
||||
class atomic_arm_4 {
|
||||
public:
|
||||
typedef T integral_type;
|
||||
explicit atomic_arm_4(T v) : i(v) {}
|
||||
atomic_arm_4() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=const_cast<volatile const T &>(i);
|
||||
fence_after(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
const_cast<volatile T &>(i)=v;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
fence_before(success_order);
|
||||
int success;
|
||||
int tmp;
|
||||
__asm__ __volatile__(
|
||||
BOOST_ATOMIC_ARM_ASM_START(%2)
|
||||
"mov %1, #0\n" // success = 0
|
||||
"ldrex %0, [%3]\n" // expected' = *(&i)
|
||||
"teq %0, %4\n" // flags = expected'==expected
|
||||
"ittt eq\n"
|
||||
"strexeq %2, %5, [%3]\n" // if (flags.equal) *(&i) = desired, tmp = !OK
|
||||
"teqeq %2, #0\n" // if (flags.equal) flags = tmp==0
|
||||
"moveq %1, #1\n" // if (flags.equal) success = 1
|
||||
BOOST_ATOMIC_ARM_ASM_END(%2)
|
||||
: "=&r" (expected), // %0
|
||||
"=&r" (success), // %1
|
||||
"=&l" (tmp) // %2
|
||||
: "r" (&i), // %3
|
||||
"r" (expected), // %4
|
||||
"r" ((int)desired) // %5
|
||||
: "cc"
|
||||
);
|
||||
if (success) fence_after(success_order);
|
||||
else fence_after(failure_order);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
protected:
|
||||
inline T fetch_add_var(T c, memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, tmp;
|
||||
int tmp2;
|
||||
__asm__ __volatile__(
|
||||
BOOST_ATOMIC_ARM_ASM_START(%2)
|
||||
"1: ldrex %0, [%3]\n" // original = *(&i)
|
||||
"add %1, %0, %4\n" // tmp = original + c
|
||||
"strex %2, %1, [%3]\n" // *(&i) = tmp; tmp2 = !OK
|
||||
"teq %2, #0\n" // flags = tmp2==0
|
||||
"it ne\n"
|
||||
"bne 1b\n" // if (!flags.equal) goto 1
|
||||
BOOST_ATOMIC_ARM_ASM_END(%2)
|
||||
: "=&r" (original), // %0
|
||||
"=&r" (tmp), // %1
|
||||
"=&l" (tmp2) // %2
|
||||
: "r" (&i), // %3
|
||||
"r" (c) // %4
|
||||
: "cc"
|
||||
);
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
inline T fetch_inc(memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, tmp;
|
||||
int tmp2;
|
||||
__asm__ __volatile__(
|
||||
BOOST_ATOMIC_ARM_ASM_START(%2)
|
||||
"1: ldrex %0, [%3]\n" // original = *(&i)
|
||||
"add %1, %0, #1\n" // tmp = original + 1
|
||||
"strex %2, %1, [%3]\n" // *(&i) = tmp; tmp2 = !OK
|
||||
"teq %2, #0\n" // flags = tmp2==0
|
||||
"it ne\n"
|
||||
"bne 1b\n" // if (!flags.equal) goto 1
|
||||
BOOST_ATOMIC_ARM_ASM_END(%2)
|
||||
: "=&r" (original), // %0
|
||||
"=&r" (tmp), // %1
|
||||
"=&l" (tmp2) // %2
|
||||
: "r" (&i) // %3
|
||||
: "cc"
|
||||
);
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
inline T fetch_dec(memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, tmp;
|
||||
int tmp2;
|
||||
__asm__ __volatile__(
|
||||
BOOST_ATOMIC_ARM_ASM_START(%2)
|
||||
"1: ldrex %0, [%3]\n" // original = *(&i)
|
||||
"sub %1, %0, #1\n" // tmp = original - 1
|
||||
"strex %2, %1, [%3]\n" // *(&i) = tmp; tmp2 = !OK
|
||||
"teq %2, #0\n" // flags = tmp2==0
|
||||
"it ne\n"
|
||||
"bne 1b\n" // if (!flags.equal) goto 1
|
||||
BOOST_ATOMIC_ARM_ASM_END(%2)
|
||||
: "=&r" (original), // %0
|
||||
"=&r" (tmp), // %1
|
||||
"=&l" (tmp2) // %2
|
||||
: "r" (&i) // %3
|
||||
: "cc"
|
||||
);
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
private:
|
||||
T i;
|
||||
};
|
||||
|
||||
|
||||
// #ifdef _ARM_ARCH_7
|
||||
// FIXME TODO can add native byte and halfword version here
|
||||
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 4> : public build_atomic_from_typical<build_exchange<atomic_arm_4<T> > > {
|
||||
public:
|
||||
typedef build_atomic_from_typical<build_exchange<atomic_arm_4<T> > > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 1>: public build_atomic_from_larger_type<atomic_arm_4<uint32_t>, T> {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_arm_4<uint32_t>, T> super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 2>: public build_atomic_from_larger_type<atomic_arm_4<uint32_t>, T> {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_arm_4<uint32_t>, T> super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef build_exchange<atomic_arm_4<void *> > platform_atomic_address;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef BOOST_ATOMIC_ARM_ASM_START
|
||||
#undef BOOST_ATOMIC_ARM_ASM_END
|
||||
|
||||
|
||||
#endif
|
||||
351
include/boost/atomic/detail/gcc-ppc.hpp
Normal file
351
include/boost/atomic/detail/gcc-ppc.hpp
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_GCC_PPC_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_GCC_PPC_HPP
|
||||
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/atomic/detail/base.hpp>
|
||||
#include <boost/atomic/detail/builder.hpp>
|
||||
|
||||
/*
|
||||
Refer to: Motorola: "Programming Environments Manual for 32-Bit
|
||||
Implementations of the PowerPC Architecture", Appendix E:
|
||||
"Synchronization Programming Examples" for an explanation of what is
|
||||
going on here (can be found on the web at various places by the
|
||||
name "MPCFPE32B.pdf", Google is your friend...)
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace atomic {
|
||||
|
||||
static inline void fence_before(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_release:
|
||||
case memory_order_acq_rel:
|
||||
#if defined(__powerpc64__)
|
||||
__asm__ __volatile__ ("lwsync" ::: "memory");
|
||||
break;
|
||||
#endif
|
||||
case memory_order_seq_cst:
|
||||
__asm__ __volatile__ ("sync" ::: "memory");
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note on the barrier instructions used by fence_after and
|
||||
atomic_thread_fence: the "isync" instruction normally does
|
||||
not wait for memory-accessing operations to complete, the
|
||||
"trick" is to introduce a conditional branch that formally
|
||||
depends on the memory-accessing instruction -- isync waits
|
||||
until the branch can be resolved and thus implicitly until
|
||||
the memory access completes.
|
||||
|
||||
This means that the load(memory_order_relaxed) instruction
|
||||
includes this branch, even though no barrier would be required
|
||||
here, but as a consequence atomic_thread_fence(memory_order_acquire)
|
||||
would have to be implemented using "sync" instead of "isync".
|
||||
The following simple cost-analysis provides the rationale
|
||||
for this decision:
|
||||
|
||||
- isync: about ~12 cycles
|
||||
- sync: about ~50 cycles
|
||||
- "spurious" branch after load: 1-2 cycles
|
||||
- making the right decision: priceless
|
||||
|
||||
*/
|
||||
|
||||
static inline void fence_after(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_acquire:
|
||||
case memory_order_acq_rel:
|
||||
case memory_order_seq_cst:
|
||||
__asm__ __volatile__ ("isync");
|
||||
case memory_order_consume:
|
||||
__asm__ __volatile__ ("" ::: "memory");
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void platform_atomic_thread_fence(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_acquire:
|
||||
__asm__ __volatile__ ("isync" ::: "memory");
|
||||
break;
|
||||
case memory_order_release:
|
||||
case memory_order_acq_rel:
|
||||
#if defined(__powerpc64__)
|
||||
__asm__ __volatile__ ("lwsync" ::: "memory");
|
||||
break;
|
||||
#endif
|
||||
case memory_order_seq_cst:
|
||||
__asm__ __volatile__ ("sync" ::: "memory");
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* note: the __asm__ constraint "b" instructs gcc to use any register
|
||||
except r0; this is required because r0 is not allowed in
|
||||
some places. Since I am sometimes unsure if it is allowed
|
||||
or not just play it safe and avoid r0 entirely -- ppc isn't
|
||||
exactly register-starved, so this really should not matter :) */
|
||||
|
||||
template<typename T>
|
||||
class atomic_ppc_32 {
|
||||
public:
|
||||
typedef T integral_type;
|
||||
explicit atomic_ppc_32(T v) : i(v) {}
|
||||
atomic_ppc_32() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=*reinterpret_cast<volatile const T *>(&i);
|
||||
__asm__ __volatile__ (
|
||||
"cmpw %0, %0\n"
|
||||
"bne- 1f\n"
|
||||
"1f:\n"
|
||||
: "+b"(v));
|
||||
fence_after(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
*reinterpret_cast<volatile T *>(&i)=v;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
fence_before(success_order);
|
||||
int success;
|
||||
__asm__ __volatile__(
|
||||
"lwarx %0,0,%2\n"
|
||||
"cmpw %0, %3\n"
|
||||
"bne- 2f\n"
|
||||
"stwcx. %4,0,%2\n"
|
||||
"bne- 2f\n"
|
||||
"addi %1,0,1\n"
|
||||
"1:"
|
||||
|
||||
".subsection 2\n"
|
||||
"2: addi %1,0,0\n"
|
||||
"b 1b\n"
|
||||
".previous\n"
|
||||
: "=&b" (expected), "=&b" (success)
|
||||
: "b" (&i), "b" (expected), "b" ((int)desired)
|
||||
);
|
||||
if (success) fence_after(success_order);
|
||||
else fence_after(failure_order);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
protected:
|
||||
inline T fetch_add_var(T c, memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, tmp;
|
||||
__asm__ __volatile__(
|
||||
"1: lwarx %0,0,%2\n"
|
||||
"add %1,%0,%3\n"
|
||||
"stwcx. %1,0,%2\n"
|
||||
"bne- 1b\n"
|
||||
: "=&b" (original), "=&b" (tmp)
|
||||
: "b" (&i), "b" (c)
|
||||
: "cc");
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
inline T fetch_inc(memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, tmp;
|
||||
__asm__ __volatile__(
|
||||
"1: lwarx %0,0,%2\n"
|
||||
"addi %1,%0,1\n"
|
||||
"stwcx. %1,0,%2\n"
|
||||
"bne- 1b\n"
|
||||
: "=&b" (original), "=&b" (tmp)
|
||||
: "b" (&i)
|
||||
: "cc");
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
inline T fetch_dec(memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, tmp;
|
||||
__asm__ __volatile__(
|
||||
"1: lwarx %0,0,%2\n"
|
||||
"addi %1,%0,-1\n"
|
||||
"stwcx. %1,0,%2\n"
|
||||
"bne- 1b\n"
|
||||
: "=&b" (original), "=&b" (tmp)
|
||||
: "b" (&i)
|
||||
: "cc");
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
private:
|
||||
T i;
|
||||
};
|
||||
|
||||
#if defined(__powerpc64__)
|
||||
|
||||
#warning Untested code -- please inform me if it works
|
||||
|
||||
template<typename T>
|
||||
class atomic_ppc_64 {
|
||||
public:
|
||||
typedef T integral_type;
|
||||
explicit atomic_ppc_64(T v) : i(v) {}
|
||||
atomic_ppc_64() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=*reinterpret_cast<volatile const T *>(&i);
|
||||
__asm__ __volatile__ (
|
||||
"cmpw %0, %0\n"
|
||||
"bne- 1f\n"
|
||||
"1f:\n"
|
||||
: "+b"(v));
|
||||
fence_after(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
*reinterpret_cast<volatile T *>(&i)=v;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
fence_before(success_order);
|
||||
int success;
|
||||
__asm__ __volatile__(
|
||||
"ldarx %0,0,%2\n"
|
||||
"cmpw %0, %3\n"
|
||||
"bne- 2f\n"
|
||||
"stdcx. %4,0,%2\n"
|
||||
"bne- 2f\n"
|
||||
"addi %1,0,1\n"
|
||||
"1:"
|
||||
|
||||
".subsection 2\n"
|
||||
"2: addi %1,0,0\n"
|
||||
"b 1b\n"
|
||||
".previous\n"
|
||||
: "=&b" (expected), "=&b" (success)
|
||||
: "b" (&i), "b" (expected), "b" ((int)desired)
|
||||
);
|
||||
if (success) fence_after(success_order);
|
||||
else fence_after(failure_order);
|
||||
fence_after(order);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
protected:
|
||||
inline T fetch_add_var(T c, memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, tmp;
|
||||
__asm__ __volatile__(
|
||||
"1: ldarx %0,0,%2\n"
|
||||
"add %1,%0,%3\n"
|
||||
"stdcx. %1,0,%2\n"
|
||||
"bne- 1b\n"
|
||||
: "=&b" (original), "=&b" (tmp)
|
||||
: "b" (&i), "b" (c)
|
||||
: "cc");
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
inline T fetch_inc(memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, tmp;
|
||||
__asm__ __volatile__(
|
||||
"1: ldarx %0,0,%2\n"
|
||||
"addi %1,%0,1\n"
|
||||
"stdcx. %1,0,%2\n"
|
||||
"bne- 1b\n"
|
||||
: "=&b" (original), "=&b" (tmp)
|
||||
: "b" (&i)
|
||||
: "cc");
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
inline T fetch_dec(memory_order order) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
T original, tmp;
|
||||
__asm__ __volatile__(
|
||||
"1: ldarx %0,0,%2\n"
|
||||
"addi %1,%0,-1\n"
|
||||
"stdcx. %1,0,%2\n"
|
||||
"bne- 1b\n"
|
||||
: "=&b" (original), "=&b" (tmp)
|
||||
: "b" (&i)
|
||||
: "cc");
|
||||
fence_after(order);
|
||||
return original;
|
||||
}
|
||||
private:
|
||||
T i;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 4> : public build_atomic_from_typical<build_exchange<atomic_ppc_32<T> > > {
|
||||
public:
|
||||
typedef build_atomic_from_typical<build_exchange<atomic_ppc_32<T> > > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 1>: public build_atomic_from_larger_type<atomic_ppc_32<uint32_t>, T> {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_ppc_32<uint32_t>, T> super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 2>: public build_atomic_from_larger_type<atomic_ppc_32<uint32_t>, T> {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_ppc_32<uint32_t>, T> super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
#if defined(__powerpc64__)
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 8> : public build_atomic_from_typical<build_exchange<atomic_ppc_64<T> > > {
|
||||
public:
|
||||
typedef build_atomic_from_typical<build_exchange<atomic_ppc_64<T> > > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
546
include/boost/atomic/detail/gcc-x86.hpp
Normal file
546
include/boost/atomic/detail/gcc-x86.hpp
Normal file
|
|
@ -0,0 +1,546 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_GCC_X86_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_GCC_X86_HPP
|
||||
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/atomic/detail/base.hpp>
|
||||
#include <boost/atomic/detail/builder.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace atomic {
|
||||
|
||||
static inline void fence_before(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_consume:
|
||||
case memory_order_release:
|
||||
case memory_order_acq_rel:
|
||||
case memory_order_seq_cst:
|
||||
__asm__ __volatile__ ("" ::: "memory");
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void fence_after(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_acquire:
|
||||
case memory_order_acq_rel:
|
||||
case memory_order_seq_cst:
|
||||
__asm__ __volatile__ ("" ::: "memory");
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void full_fence(void)
|
||||
{
|
||||
#if (defined(__amd64__) || defined(__x86_64__))
|
||||
__asm__ __volatile__("mfence" ::: "memory");
|
||||
#else
|
||||
/* could use mfence iff i686, but it does not appear to matter much */
|
||||
__asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void fence_after_load(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_seq_cst:
|
||||
full_fence();
|
||||
case memory_order_acquire:
|
||||
case memory_order_acq_rel:
|
||||
__asm__ __volatile__ ("" ::: "memory");
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void platform_atomic_thread_fence(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_seq_cst:
|
||||
full_fence();
|
||||
case memory_order_acquire:
|
||||
case memory_order_consume:
|
||||
case memory_order_acq_rel:
|
||||
case memory_order_release:
|
||||
__asm__ __volatile__ ("" ::: "memory");
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class atomic_x86_8 {
|
||||
public:
|
||||
explicit atomic_x86_8(T v) : i(v) {}
|
||||
atomic_x86_8() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=*reinterpret_cast<volatile const T *>(&i);
|
||||
fence_after_load(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
if (order!=memory_order_seq_cst) {
|
||||
fence_before(order);
|
||||
*reinterpret_cast<volatile T *>(&i)=v;
|
||||
} else {
|
||||
exchange(v);
|
||||
}
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
fence_before(success_order);
|
||||
T prev=expected;
|
||||
__asm__ __volatile__("lock; cmpxchgb %1, %2\n" : "=a" (prev) : "q" (desired), "m" (i), "a" (expected) : "memory");
|
||||
bool success=(prev==expected);
|
||||
if (success) fence_after(success_order);
|
||||
else fence_after(failure_order);
|
||||
expected=prev;
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T r, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
__asm__ __volatile__("xchgb %0, %1\n" : "=q" (r) : "m"(i), "0" (r) : "memory");
|
||||
return r;
|
||||
}
|
||||
T fetch_add(T c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
__asm__ __volatile__("lock; xaddb %0, %1" : "+q" (c), "+m" (i) :: "memory");
|
||||
return c;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
protected:
|
||||
typedef T integral_type;
|
||||
private:
|
||||
T i;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 1> : public build_atomic_from_add<atomic_x86_8<T> > {
|
||||
public:
|
||||
typedef build_atomic_from_add<atomic_x86_8<T> > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class atomic_x86_16 {
|
||||
public:
|
||||
explicit atomic_x86_16(T v) : i(v) {}
|
||||
atomic_x86_16() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=*reinterpret_cast<volatile const T *>(&i);
|
||||
fence_after_load(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
if (order!=memory_order_seq_cst) {
|
||||
fence_before(order);
|
||||
*reinterpret_cast<volatile T *>(&i)=v;
|
||||
} else {
|
||||
exchange(v);
|
||||
}
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
fence_before(success_order);
|
||||
T prev=expected;
|
||||
__asm__ __volatile__("lock; cmpxchgw %1, %2\n" : "=a" (prev) : "q" (desired), "m" (i), "a" (expected) : "memory");
|
||||
bool success=(prev==expected);
|
||||
if (success) fence_after(success_order);
|
||||
else fence_after(failure_order);
|
||||
expected=prev;
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T r, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
__asm__ __volatile__("xchgw %0, %1\n" : "=r" (r) : "m"(i), "0" (r) : "memory");
|
||||
return r;
|
||||
}
|
||||
T fetch_add(T c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
__asm__ __volatile__("lock; xaddw %0, %1" : "+r" (c), "+m" (i) :: "memory");
|
||||
return c;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
protected:
|
||||
typedef T integral_type;
|
||||
private:
|
||||
T i;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 2> : public build_atomic_from_add<atomic_x86_16<T> > {
|
||||
public:
|
||||
typedef build_atomic_from_add<atomic_x86_16<T> > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class atomic_x86_32 {
|
||||
public:
|
||||
explicit atomic_x86_32(T v) : i(v) {}
|
||||
atomic_x86_32() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=*reinterpret_cast<volatile const T *>(&i);
|
||||
fence_after_load(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
if (order!=memory_order_seq_cst) {
|
||||
fence_before(order);
|
||||
*reinterpret_cast<volatile T *>(&i)=v;
|
||||
} else {
|
||||
exchange(v);
|
||||
}
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
fence_before(success_order);
|
||||
T prev=expected;
|
||||
__asm__ __volatile__("lock; cmpxchgl %1, %2\n" : "=a" (prev) : "q" (desired), "m" (i), "a" (expected) : "memory");
|
||||
bool success=(prev==expected);
|
||||
if (success) fence_after(success_order);
|
||||
else fence_after(failure_order);
|
||||
expected=prev;
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T r, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
__asm__ __volatile__("xchgl %0, %1\n" : "=r" (r) : "m"(i), "0" (r) : "memory");
|
||||
return r;
|
||||
}
|
||||
T fetch_add(T c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
__asm__ __volatile__("lock; xaddl %0, %1" : "+r" (c), "+m" (i) :: "memory");
|
||||
return c;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
protected:
|
||||
typedef T integral_type;
|
||||
private:
|
||||
T i;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 4> : public build_atomic_from_add<atomic_x86_32<T> > {
|
||||
public:
|
||||
typedef build_atomic_from_add<atomic_x86_32<T> > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
#if (defined(__amd64__) || defined(__x86_64__))
|
||||
template<typename T>
|
||||
class atomic_x86_64 {
|
||||
public:
|
||||
explicit atomic_x86_64(T v) : i(v) {}
|
||||
atomic_x86_64() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=*reinterpret_cast<volatile const T *>(&i);
|
||||
fence_after_load(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
if (order!=memory_order_seq_cst) {
|
||||
fence_before(order);
|
||||
*reinterpret_cast<volatile T *>(&i)=v;
|
||||
} else {
|
||||
exchange(v);
|
||||
}
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
fence_before(success_order);
|
||||
T prev=expected;
|
||||
__asm__ __volatile__("lock; cmpxchgq %1, %2\n" : "=a" (prev) : "q" (desired), "m" (i), "a" (expected) : "memory");
|
||||
bool success=(prev==expected);
|
||||
if (success) fence_after(success_order);
|
||||
else fence_after(failure_order);
|
||||
expected=prev;
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T r, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
__asm__ __volatile__("xchgq %0, %1\n" : "=r" (r) : "m"(i), "0" (r) : "memory");
|
||||
return r;
|
||||
}
|
||||
T fetch_add(T c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
__asm__ __volatile__("lock; xaddq %0, %1" : "+r" (c), "+m" (i) :: "memory");
|
||||
return c;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
protected:
|
||||
typedef T integral_type;
|
||||
private:
|
||||
T i;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
#elif defined(__i686__)
|
||||
|
||||
template<typename T>
|
||||
class atomic_x86_64 {
|
||||
private:
|
||||
typedef atomic_x86_64 this_type;
|
||||
public:
|
||||
explicit atomic_x86_64(T v) : i(v) {}
|
||||
atomic_x86_64() {}
|
||||
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
long scratch;
|
||||
fence_before(success_order);
|
||||
T prev=expected;
|
||||
/* Make sure ebx is saved and restored properly in case
|
||||
this object is compiled as "position independent". Since
|
||||
programmers on x86 tend to forget specifying -DPIC or
|
||||
similar, always assume PIC.
|
||||
|
||||
To make this work uniformly even in the non-PIC case,
|
||||
setup register constraints such that ebx can not be
|
||||
used by accident e.g. as base address for the variable
|
||||
to be modified. Accessing "scratch" should always be okay,
|
||||
as it can only be placed on the stack (and therefore
|
||||
accessed through ebp or esp only).
|
||||
|
||||
In theory, could push/pop ebx onto/off the stack, but movs
|
||||
to a prepared stack slot turn out to be faster. */
|
||||
__asm__ __volatile__(
|
||||
"movl %%ebx, %1\n"
|
||||
"movl %2, %%ebx\n"
|
||||
"lock; cmpxchg8b 0(%4)\n"
|
||||
"movl %1, %%ebx\n"
|
||||
: "=A" (prev), "=m" (scratch)
|
||||
: "D" ((long)desired), "c" ((long)(desired>>32)), "S" (&i), "0" (prev)
|
||||
: "memory");
|
||||
bool success=(prev==expected);
|
||||
if (success) fence_after(success_order);
|
||||
else fence_after(failure_order);
|
||||
expected=prev;
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T r, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
T prev=i;
|
||||
do {} while(!compare_exchange_strong(prev, r, order, memory_order_relaxed));
|
||||
return prev;
|
||||
}
|
||||
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
/* this is a bit problematic -- there is no other
|
||||
way to atomically load a 64 bit value, but of course
|
||||
compare_exchange requires write access to the memory
|
||||
area */
|
||||
T expected=i;
|
||||
do { } while(!const_cast<this_type *>(this)->compare_exchange_strong(expected, expected, order, memory_order_relaxed));
|
||||
return expected;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
exchange(v, order);
|
||||
}
|
||||
T fetch_add(T c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
T expected=i, desired;;
|
||||
do {
|
||||
desired=expected+c;
|
||||
} while(!compare_exchange_strong(expected, desired, order, memory_order_relaxed));
|
||||
return expected;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
protected:
|
||||
typedef T integral_type;
|
||||
private:
|
||||
T i;
|
||||
} __attribute__((aligned(8))) ;
|
||||
|
||||
#endif
|
||||
|
||||
#if (defined(__amd64__) || defined(__x86_64__)) || defined(__i686__)
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 8> : public build_atomic_from_add<atomic_x86_64<T> >{
|
||||
public:
|
||||
typedef build_atomic_from_add<atomic_x86_64<T> > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
// TODO: only use the sync intrinsics as a fallback, prefer inline asm as it
|
||||
// allows us to do relaxed memory ordering.
|
||||
#if (defined(__amd64__) || defined(__x86_64__)) && \
|
||||
defined(BOOST_ATOMIC_HAVE_SSE2) && \
|
||||
defined(BOOST_ATOMIC_HAVE_GNU_SYNC_16) && \
|
||||
defined(BOOST_ATOMIC_HAVE_GNU_ALIGNED_16)
|
||||
template<typename T>
|
||||
class atomic_x86_128 {
|
||||
public:
|
||||
explicit atomic_x86_128(T v) : i(v) {}
|
||||
atomic_x86_128() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v;
|
||||
__asm__ __volatile__ (
|
||||
"movdqa %1, %%xmm0 ;\n"
|
||||
"movdqa %%xmm0, %0 ;\n"
|
||||
: "=m" (v)
|
||||
: "m" (i)
|
||||
: "xmm0", "memory"
|
||||
);
|
||||
fence_after_load(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
// Atomically stores 128bit value by SSE instruction movdqa
|
||||
__asm__ __volatile__ (
|
||||
"movdqa %1, %%xmm0 ;\n"
|
||||
"movdqa %%xmm0, %0 ;\n"
|
||||
: "=m" (i)
|
||||
: "m" (v)
|
||||
: "xmm0", "memory"
|
||||
);
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
T prev = __sync_val_compare_and_swap_16
|
||||
(reinterpret_cast<volatile T*>(&i), expected, desired);
|
||||
bool success=(prev==expected);
|
||||
if (success) fence_after(success_order);
|
||||
else fence_after(failure_order);
|
||||
expected=prev;
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T r, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
while (!__sync_bool_compare_and_swap_16
|
||||
(reinterpret_cast<volatile T*>(&i), i, r))
|
||||
{};
|
||||
|
||||
return r;
|
||||
}
|
||||
T fetch_add(T c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
T expected=i, desired;
|
||||
do {
|
||||
desired=expected+c;
|
||||
} while(!compare_exchange_strong(expected, desired, order, memory_order_relaxed));
|
||||
return expected;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
protected:
|
||||
typedef T integral_type;
|
||||
private:
|
||||
T i;
|
||||
} __attribute__((aligned(16)));
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 16> : public build_atomic_from_add<atomic_x86_128<T> >{
|
||||
public:
|
||||
typedef build_atomic_from_add<atomic_x86_128<T> > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
192
include/boost/atomic/detail/generic-cas.hpp
Normal file
192
include/boost/atomic/detail/generic-cas.hpp
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_GENERIC_CAS_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_GENERIC_CAS_HPP
|
||||
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/detail/base.hpp>
|
||||
#include <boost/atomic/detail/builder.hpp>
|
||||
|
||||
/* fallback implementation for various compilation targets;
|
||||
this is *not* efficient, particularly because all operations
|
||||
are fully fenced (full memory barriers before and after
|
||||
each operation) */
|
||||
|
||||
#if defined(__GNUC__)
|
||||
namespace boost { namespace detail { namespace atomic {
|
||||
static inline int32_t
|
||||
fenced_compare_exchange_strong_32(volatile int32_t *ptr, int32_t expected, int32_t desired)
|
||||
{
|
||||
return __sync_val_compare_and_swap_4(ptr, expected, desired);
|
||||
}
|
||||
#define BOOST_ATOMIC_HAVE_CAS32 1
|
||||
|
||||
#if (defined(__amd64__) || defined(__x86_64__)) || defined(__i686__)
|
||||
static inline int64_t
|
||||
fenced_compare_exchange_strong_64(int64_t *ptr, int64_t expected, int64_t desired)
|
||||
{
|
||||
return __sync_val_compare_and_swap_8(ptr, expected, desired);
|
||||
}
|
||||
#define BOOST_ATOMIC_HAVE_CAS64 1
|
||||
#endif
|
||||
}}}
|
||||
|
||||
#elif defined(__ICL) || defined(_MSC_VER)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <Windows.h>
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace detail { namespace atomic {
|
||||
static inline int32_t
|
||||
fenced_compare_exchange_strong(int32_t *ptr, int32_t expected, int32_t desired)
|
||||
{
|
||||
return _InterlockedCompareExchange(reinterpret_cast<volatile long*>(ptr), desired, expected);
|
||||
}
|
||||
#define BOOST_ATOMIC_HAVE_CAS32 1
|
||||
#if defined(_WIN64)
|
||||
static inline int64_t
|
||||
fenced_compare_exchange_strong(int64_t *ptr, int64_t expected, int64_t desired)
|
||||
{
|
||||
return _InterlockedCompareExchange64(ptr, desired, expected);
|
||||
}
|
||||
#define BOOST_ATOMIC_HAVE_CAS64 1
|
||||
#endif
|
||||
}}}
|
||||
|
||||
#elif (defined(__ICC) || defined(__ECC))
|
||||
namespace boost { namespace detail { namespace atomic {
|
||||
static inline int32_t
|
||||
fenced_compare_exchange_strong_32(int32_t *ptr, int32_t expected, int32_t desired)
|
||||
{
|
||||
return _InterlockedCompareExchange((void*)ptr, desired, expected);
|
||||
}
|
||||
#define BOOST_ATOMIC_HAVE_CAS32 1
|
||||
#if defined(__x86_64)
|
||||
static inline int64_t
|
||||
fenced_compare_exchange_strong(int64_t *ptr, int64_t expected, int64_t desired)
|
||||
{
|
||||
return cas64<int>(ptr, expected, desired);
|
||||
}
|
||||
#define BOOST_ATOMIC_HAVE_CAS64 1
|
||||
#elif defined(__ECC) //IA-64 version
|
||||
static inline int64_t
|
||||
fenced_compare_exchange_strong(int64_t *ptr, int64_t expected, int64_t desired)
|
||||
{
|
||||
return _InterlockedCompareExchange64((void*)ptr, desired, expected);
|
||||
}
|
||||
#define BOOST_ATOMIC_HAVE_CAS64 1
|
||||
#endif
|
||||
}}}
|
||||
|
||||
#elif (defined(__SUNPRO_CC) && defined(__sparc))
|
||||
#include <sys/atomic.h>
|
||||
namespace boost { namespace detail { namespace atomic {
|
||||
static inline int32_t
|
||||
fenced_compare_exchange_strong_32(int32_t *ptr, int32_t expected, int32_t desired)
|
||||
{
|
||||
return atomic_cas_32((volatile unsigned int*)ptr, expected, desired);
|
||||
}
|
||||
#define BOOST_ATOMIC_HAVE_CAS32 1
|
||||
|
||||
/* FIXME: check for 64 bit mode */
|
||||
static inline int64_t
|
||||
fenced_compare_exchange_strong_64(int64_t *ptr, int64_t expected, int64_t desired)
|
||||
{
|
||||
return atomic_cas_64((volatile unsigned long long*)ptr, expected, desired);
|
||||
}
|
||||
#define BOOST_ATOMIC_HAVE_CAS64 1
|
||||
}}}
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost { namespace detail { namespace atomic {
|
||||
|
||||
#ifdef BOOST_ATOMIC_HAVE_CAS32
|
||||
template<typename T>
|
||||
class atomic_generic_cas32 {
|
||||
private:
|
||||
typedef atomic_generic_cas32 this_type;
|
||||
public:
|
||||
explicit atomic_generic_cas32(T v) : i((int32_t)v) {}
|
||||
atomic_generic_cas32() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T expected=(T)i;
|
||||
do { } while(!const_cast<this_type *>(this)->compare_exchange_weak(expected, expected, order, memory_order_relaxed));
|
||||
return expected;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
exchange(v);
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
T found;
|
||||
found=(T)fenced_compare_exchange_strong_32(&i, (int32_t)expected, (int32_t)desired);
|
||||
bool success=(found==expected);
|
||||
expected=found;
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T r, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
T expected=(T)i;
|
||||
do { } while(!compare_exchange_weak(expected, r, order, memory_order_relaxed));
|
||||
return expected;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
typedef T integral_type;
|
||||
private:
|
||||
mutable int32_t i;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 4> : public build_atomic_from_exchange<atomic_generic_cas32<T> > {
|
||||
public:
|
||||
typedef build_atomic_from_exchange<atomic_generic_cas32<T> > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 1>: public build_atomic_from_larger_type<atomic_generic_cas32<int32_t>, T> {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_generic_cas32<int32_t>, T> super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 2>: public build_atomic_from_larger_type<atomic_generic_cas32<int32_t>, T> {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_generic_cas32<int32_t>, T> super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
} } }
|
||||
|
||||
#endif
|
||||
465
include/boost/atomic/detail/integral-casts.hpp
Normal file
465
include/boost/atomic/detail/integral-casts.hpp
Normal file
|
|
@ -0,0 +1,465 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_INTEGRAL_CASTS_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_INTEGRAL_CASTS_HPP
|
||||
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <string.h>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost { namespace detail { namespace atomic {
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic<T, 1> : private platform_atomic_integral<boost::uint8_t> {
|
||||
public:
|
||||
typedef platform_atomic_integral<boost::uint8_t> super;
|
||||
#if defined(BOOST_ATOMIC_ENFORCE_PODNESS)
|
||||
typedef union { T e; boost::uint8_t i;} conv;
|
||||
#endif
|
||||
|
||||
platform_atomic() {}
|
||||
explicit platform_atomic(T t) : super(to_integral(t))
|
||||
{
|
||||
}
|
||||
|
||||
void store(T t, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
super::store(to_integral(t), order);
|
||||
}
|
||||
T load(memory_order order=memory_order_seq_cst) volatile const
|
||||
{
|
||||
return from_integral(super::load(order));
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
boost::uint8_t _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_strong(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
boost::uint8_t _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_weak(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
|
||||
T exchange(T replacement, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return from_integral(super::exchange(to_integral(replacement), order));
|
||||
}
|
||||
|
||||
operator T(void) const volatile {return load();}
|
||||
T operator=(T v) volatile {store(v); return v;}
|
||||
|
||||
using super::is_lock_free;
|
||||
protected:
|
||||
static inline boost::uint8_t to_integral(T &t)
|
||||
{
|
||||
boost::uint8_t tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
static inline T from_integral(boost::uint8_t t)
|
||||
{
|
||||
T tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic<T, 2> : private platform_atomic_integral<boost::uint16_t> {
|
||||
public:
|
||||
typedef platform_atomic_integral<boost::uint16_t> super;
|
||||
#if defined(BOOST_ATOMIC_ENFORCE_PODNESS)
|
||||
typedef union { T e; boost::uint16_t i;} conv;
|
||||
#endif
|
||||
|
||||
platform_atomic() {}
|
||||
explicit platform_atomic(T t) : super(to_integral(t))
|
||||
{
|
||||
}
|
||||
|
||||
void store(T t, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
super::store(to_integral(t), order);
|
||||
}
|
||||
T load(memory_order order=memory_order_seq_cst) volatile const
|
||||
{
|
||||
return from_integral(super::load(order));
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
boost::uint16_t _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_strong(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
boost::uint16_t _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_weak(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
|
||||
T exchange(T replacement, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return from_integral(super::exchange(to_integral(replacement), order));
|
||||
}
|
||||
|
||||
operator T(void) const volatile {return load();}
|
||||
T operator=(T v) volatile {store(v); return v;}
|
||||
|
||||
using super::is_lock_free;
|
||||
protected:
|
||||
static inline boost::uint16_t to_integral(T &t)
|
||||
{
|
||||
boost::uint16_t tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
static inline T from_integral(boost::uint16_t t)
|
||||
{
|
||||
T tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic<T, 4> : private platform_atomic_integral<boost::uint32_t> {
|
||||
public:
|
||||
typedef platform_atomic_integral<boost::uint32_t> super;
|
||||
#if defined(BOOST_ATOMIC_ENFORCE_PODNESS)
|
||||
typedef union { T e; boost::uint32_t i;} conv;
|
||||
#endif
|
||||
|
||||
platform_atomic() {}
|
||||
explicit platform_atomic(T t) : super(to_integral(t))
|
||||
{
|
||||
}
|
||||
|
||||
void store(T t, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
super::store(to_integral(t), order);
|
||||
}
|
||||
T load(memory_order order=memory_order_seq_cst) volatile const
|
||||
{
|
||||
return from_integral(super::load(order));
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
boost::uint32_t _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_strong(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
boost::uint32_t _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_weak(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
|
||||
T exchange(T replacement, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return from_integral(super::exchange(to_integral(replacement), order));
|
||||
}
|
||||
|
||||
operator T(void) const volatile {return load();}
|
||||
T operator=(T v) volatile {store(v); return v;}
|
||||
|
||||
using super::is_lock_free;
|
||||
protected:
|
||||
static inline boost::uint32_t to_integral(T &t)
|
||||
{
|
||||
boost::uint32_t tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
static inline T from_integral(boost::uint32_t t)
|
||||
{
|
||||
T tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic<T, 8> : private platform_atomic_integral<boost::uint64_t> {
|
||||
public:
|
||||
typedef platform_atomic_integral<boost::uint64_t> super;
|
||||
#if defined(BOOST_ATOMIC_ENFORCE_PODNESS)
|
||||
typedef union { T e; boost::uint64_t i;} conv;
|
||||
#endif
|
||||
|
||||
platform_atomic() {}
|
||||
explicit platform_atomic(T t) : super(to_integral(t))
|
||||
{
|
||||
}
|
||||
|
||||
void store(T t, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
super::store(to_integral(t), order);
|
||||
}
|
||||
T load(memory_order order=memory_order_seq_cst) volatile const
|
||||
{
|
||||
return from_integral(super::load(order));
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
boost::uint64_t _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_strong(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
boost::uint64_t _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_weak(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
|
||||
T exchange(T replacement, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return from_integral(super::exchange(to_integral(replacement), order));
|
||||
}
|
||||
|
||||
operator T(void) const volatile {return load();}
|
||||
T operator=(T v) volatile {store(v); return v;}
|
||||
|
||||
using super::is_lock_free;
|
||||
protected:
|
||||
static inline boost::uint64_t to_integral(T &t)
|
||||
{
|
||||
boost::uint64_t tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
static inline T from_integral(boost::uint64_t t)
|
||||
{
|
||||
T tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
#if (defined(__amd64__) || defined(__x86_64__)) && \
|
||||
defined(BOOST_ATOMIC_HAVE_SSE2) && \
|
||||
defined(BOOST_ATOMIC_HAVE_GNU_SYNC_16) && \
|
||||
defined(BOOST_ATOMIC_HAVE_GNU_ALIGNED_16) && \
|
||||
defined(BOOST_ATOMIC_HAVE_GNU_128BIT_INTEGERS)
|
||||
|
||||
#define BOOST_ATOMIC_HAVE_128BIT_SUPPORT
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic<T, 16> : private platform_atomic_integral<__uint128_t> {
|
||||
public:
|
||||
typedef platform_atomic_integral<__uint128_t> super;
|
||||
#if defined(BOOST_ATOMIC_ENFORCE_PODNESS)
|
||||
typedef union { T e; __uint128_t i;} conv;
|
||||
#endif
|
||||
|
||||
platform_atomic() {}
|
||||
explicit platform_atomic(T t) : super(to_integral(t))
|
||||
{
|
||||
}
|
||||
|
||||
void store(T t, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
super::store(to_integral(t), order);
|
||||
}
|
||||
T load(memory_order order=memory_order_seq_cst) volatile const
|
||||
{
|
||||
return from_integral(super::load(order));
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
__uint128_t _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_strong(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
__uint128_t _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_weak(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
|
||||
T exchange(T replacement, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return from_integral(super::exchange(to_integral(replacement), order));
|
||||
}
|
||||
|
||||
operator T(void) const volatile {return load();}
|
||||
T operator=(T v) volatile {store(v); return v;}
|
||||
|
||||
using super::is_lock_free;
|
||||
protected:
|
||||
static inline __uint128_t to_integral(T &t)
|
||||
{
|
||||
__uint128_t tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
static inline T from_integral(__uint128_t t)
|
||||
{
|
||||
T tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOOST_MSVC >= 1500 && (defined(_M_IA64) || defined(_M_AMD64)) && defined(BOOST_ATOMIC_HAVE_SSE2)
|
||||
|
||||
#define BOOST_ATOMIC_HAVE_128BIT_SUPPORT
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic<T, 16> : private platform_atomic_integral<__m128i> {
|
||||
public:
|
||||
typedef platform_atomic_integral<__m128i> super;
|
||||
#if defined(BOOST_ATOMIC_ENFORCE_PODNESS)
|
||||
typedef union { T e; __m128i i;} conv;
|
||||
#endif
|
||||
|
||||
platform_atomic() {}
|
||||
explicit platform_atomic(T t) : super(to_integral(t))
|
||||
{
|
||||
}
|
||||
|
||||
void store(T t, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
super::store(to_integral(t), order);
|
||||
}
|
||||
T load(memory_order order=memory_order_seq_cst) volatile const
|
||||
{
|
||||
return from_integral(super::load(order));
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
__m128i _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_strong(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
__m128i _expected, _desired;
|
||||
_expected=to_integral(expected);
|
||||
_desired=to_integral(desired);
|
||||
bool success=super::compare_exchange_weak(_expected, _desired, success_order, failure_order);
|
||||
expected=from_integral(_expected);
|
||||
return success;
|
||||
}
|
||||
|
||||
T exchange(T replacement, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return from_integral(super::exchange(to_integral(replacement), order));
|
||||
}
|
||||
|
||||
operator T(void) const volatile {return load();}
|
||||
T operator=(T v) volatile {store(v); return v;}
|
||||
|
||||
using super::is_lock_free;
|
||||
protected:
|
||||
static inline __m128i to_integral(T &t)
|
||||
{
|
||||
__m128i tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
static inline T from_integral(__m128i t)
|
||||
{
|
||||
T tmp;
|
||||
memcpy(&tmp, &t, sizeof(t));
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} } }
|
||||
|
||||
#endif
|
||||
365
include/boost/atomic/detail/interlocked.hpp
Normal file
365
include/boost/atomic/detail/interlocked.hpp
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_INTERLOCKED_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_INTERLOCKED_HPP
|
||||
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
|
||||
#include <boost/atomic/detail/base.hpp>
|
||||
#include <boost/atomic/detail/builder.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace atomic {
|
||||
|
||||
static inline void full_fence(void)
|
||||
{
|
||||
long tmp;
|
||||
BOOST_INTERLOCKED_EXCHANGE(&tmp, 0);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void platform_atomic_thread_fence(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_seq_cst:
|
||||
full_fence();
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void fence_after_load(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
case memory_order_seq_cst:
|
||||
full_fence();
|
||||
case memory_order_acquire:
|
||||
case memory_order_acq_rel:
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
class atomic_interlocked_32 {
|
||||
public:
|
||||
explicit atomic_interlocked_32(T v) : i(v) {}
|
||||
atomic_interlocked_32() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=*reinterpret_cast<volatile const T *>(&i);
|
||||
fence_after_load(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
if (order!=memory_order_seq_cst) {
|
||||
*reinterpret_cast<volatile T *>(&i)=v;
|
||||
} else {
|
||||
exchange(v);
|
||||
}
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
T prev=expected;
|
||||
expected=(T)BOOST_INTERLOCKED_COMPARE_EXCHANGE((long *)(&i), (long)desired, (long)expected);
|
||||
bool success=(prev==expected);
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T r, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return (T)BOOST_INTERLOCKED_EXCHANGE((long *)&i, (long)r);
|
||||
}
|
||||
T fetch_add(T c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return (T)BOOST_INTERLOCKED_EXCHANGE_ADD((long *)&i, c);
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
|
||||
typedef T integral_type;
|
||||
private:
|
||||
T i;
|
||||
};
|
||||
|
||||
# if defined(_M_IA64) || defined(_M_AMD64)
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
|
||||
# include <windows.h>
|
||||
|
||||
# define BOOST_INTERLOCKED_EXCHANGE_ADD64 InterlockedExchangeAdd64
|
||||
# define BOOST_INTERLOCKED_EXCHANGE64 InterlockedExchange64
|
||||
# define BOOST_INTERLOCKED_COMPARE_EXCHANGE64 InterlockedCompareExchange64
|
||||
|
||||
#else
|
||||
|
||||
extern "C" boost::int64_t __cdecl _InterlockedExchangeAdd64(boost::int64_t volatile *, boost::int64_t);
|
||||
extern "C" boost::int64_t __cdecl _InterlockedExchange64(boost::int64_t volatile *, boost::int64_t);
|
||||
extern "C" boost::int64_t __cdecl _InterlockedCompareExchange64(boost::int64_t volatile *, boost::int64_t, boost::int64_t);
|
||||
|
||||
# pragma intrinsic( _InterlockedExchangeAdd64 )
|
||||
# pragma intrinsic( _InterlockedExchange64 )
|
||||
# pragma intrinsic( _InterlockedCompareExchange64 )
|
||||
|
||||
# define BOOST_INTERLOCKED_EXCHANGE_ADD64 _InterlockedExchangeAdd64
|
||||
# define BOOST_INTERLOCKED_EXCHANGE64 _InterlockedExchange64
|
||||
# define BOOST_INTERLOCKED_COMPARE_EXCHANGE64 _InterlockedCompareExchange64
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
class __declspec(align(64)) atomic_interlocked_64 {
|
||||
public:
|
||||
explicit atomic_interlocked_64(T v) : i(v) {}
|
||||
atomic_interlocked_64() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=*reinterpret_cast<volatile const T *>(&i);
|
||||
fence_after_load(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
if (order!=memory_order_seq_cst) {
|
||||
*reinterpret_cast<volatile T *>(&i)=v;
|
||||
} else {
|
||||
exchange(v);
|
||||
}
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
T prev=expected;
|
||||
expected=(T)BOOST_INTERLOCKED_COMPARE_EXCHANGE64((boost::int64_t *)(&i), (boost::int64_t)desired, (boost::int64_t)expected);
|
||||
bool success=(prev==expected);
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T r, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return (T)BOOST_INTERLOCKED_EXCHANGE64((boost::int64_t *)&i, (boost::int64_t)r);
|
||||
}
|
||||
T fetch_add(T c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
return (T)BOOST_INTERLOCKED_EXCHANGE_ADD64((boost::int64_t *)&i, c);
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
|
||||
typedef T integral_type;
|
||||
private:
|
||||
T i;
|
||||
};
|
||||
|
||||
// _InterlockedCompareExchange128 is available only starting with VS2008
|
||||
#if BOOST_MSVC >= 1500 && defined(BOOST_ATOMIC_HAVE_SSE2)
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
|
||||
# include <windows.h>
|
||||
# include <emmintrin.h>
|
||||
|
||||
# define BOOST_INTERLOCKED_COMPARE_EXCHANGE128 InterlockedCompareExchange128
|
||||
|
||||
# pragma intrinsic( _mm_load_si128 )
|
||||
# pragma intrinsic( _mm_store_si128 )
|
||||
|
||||
#else
|
||||
|
||||
# include <emmintrin.h>
|
||||
|
||||
extern "C" unsigned char __cdecl _InterlockedCompareExchange128(
|
||||
boost::int64_t volatile *Destination,
|
||||
boost::int64_t ExchangeHigh, boost::int64_t ExchangeLow,
|
||||
boost::int64_t *Comparand)
|
||||
extern "C" __m128i _mm_load_si128(__m128i const*_P);
|
||||
extern "C" void _mm_store_si128(__m128i *_P, __m128i _B);
|
||||
|
||||
# pragma intrinsic( _InterlockedCompareExchange128 )
|
||||
# pragma intrinsic( _mm_load_si128 )
|
||||
# pragma intrinsic( _mm_store_si128 )
|
||||
|
||||
# define BOOST_INTERLOCKED_COMPARE_EXCHANGE128 _InterlockedCompareExchange128
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
class __declspec(align(128)) atomic_interlocked_128 {
|
||||
public:
|
||||
explicit atomic_interlocked_128(T v) : i(v) {}
|
||||
atomic_interlocked_128() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v;
|
||||
if (order!=memory_order_seq_cst) {
|
||||
v = _mm_load_si128(*(__m128i*)(&i));
|
||||
}
|
||||
else {
|
||||
v = *reinterpret_cast<volatile const T *>(&i);
|
||||
}
|
||||
fence_after_load(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
if (order!=memory_order_seq_cst) {
|
||||
*reinterpret_cast<volatile T *>(&i)=v;
|
||||
}
|
||||
else {
|
||||
_mm_store_si128(*(__m128i*)(&i), v);
|
||||
}
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
boost::int64_t* desired_raw = &desired;
|
||||
T prev = i;
|
||||
bool success = BOOST_INTERLOCKED_COMPARE_EXCHANGE128(
|
||||
(boost::int64_t volatile *)(&i),
|
||||
desired_raw[1], desired_raw[0], (boost::int64_t*)&expected);
|
||||
if (!success)
|
||||
expected = prev;
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T r, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
boost::int64_t* desired_raw = &r;
|
||||
T prev = i;
|
||||
|
||||
while (!BOOST_INTERLOCKED_COMPARE_EXCHANGE128(
|
||||
(boost::int64_t volatile*)&i, desired_raw[1], desired_raw[0],
|
||||
(boost::int64_t*)&i))
|
||||
{}
|
||||
|
||||
return prev;
|
||||
}
|
||||
T fetch_add(T c, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
T expected = i;
|
||||
__m128i desired;
|
||||
|
||||
do {
|
||||
desired = _mm_add_epi32(*(__m128i*)(&expected), *(__m128i*)(&c));
|
||||
} while (!compare_exchange_strong(expected, *(T*)(&desired), order, memory_order_relaxed));
|
||||
|
||||
return expected;
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
|
||||
typedef T integral_type;
|
||||
private:
|
||||
T i;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 4> : public build_atomic_from_add<atomic_interlocked_32<T> > {
|
||||
public:
|
||||
typedef build_atomic_from_add<atomic_interlocked_32<T> > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 1>: public build_atomic_from_larger_type<atomic_interlocked_32<uint32_t>, T> {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_interlocked_32<uint32_t>, T> super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 2>: public build_atomic_from_larger_type<atomic_interlocked_32<uint32_t>, T> {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_interlocked_32<uint32_t>, T> super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
# if defined(_M_IA64) || defined(_M_AMD64)
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 8>
|
||||
: public build_atomic_from_add<atomic_interlocked_64<uint64_t> >
|
||||
{
|
||||
public:
|
||||
typedef build_atomic_from_add<atomic_interlocked_64<uint64_t> > super;
|
||||
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
template<>
|
||||
class platform_atomic_integral<void*, 8>
|
||||
: public build_atomic_from_add<atomic_interlocked_64<void*> >
|
||||
{
|
||||
public:
|
||||
typedef build_atomic_from_add<atomic_interlocked_64<void*> > super;
|
||||
|
||||
explicit platform_atomic_integral(void* v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
#if BOOST_MSVC >= 1500 && defined(BOOST_ATOMIC_HAVE_SSE2)
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 16>
|
||||
: public build_atomic_from_add<atomic_interlocked_128<T> >
|
||||
{
|
||||
public:
|
||||
typedef build_atomic_from_add<atomic_interlocked_128<T> > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
171
include/boost/atomic/detail/linux-arm.hpp
Normal file
171
include/boost/atomic/detail/linux-arm.hpp
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_LINUX_ARM_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_LINUX_ARM_HPP
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
// Copyright (c) 2009 Phil Endecott
|
||||
// ARM Code by Phil Endecott, based on other architectures.
|
||||
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/detail/base.hpp>
|
||||
#include <boost/atomic/detail/builder.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace atomic {
|
||||
|
||||
|
||||
// Different ARM processors have different atomic instructions. In particular,
|
||||
// architecture versions before v6 (which are still in widespread use, e.g. the
|
||||
// Intel/Marvell XScale chips like the one in the NSLU2) have only atomic swap.
|
||||
// On Linux the kernel provides some support that lets us abstract away from
|
||||
// these differences: it provides emulated CAS and barrier functions at special
|
||||
// addresses that are garaunteed not to be interrupted by the kernel. Using
|
||||
// this facility is slightly slower than inline assembler would be, but much
|
||||
// faster than a system call.
|
||||
//
|
||||
// For documentation, see arch/arm/kernel/entry-armv.S in the kernel source
|
||||
// (search for "User Helpers").
|
||||
|
||||
|
||||
typedef void (kernel_dmb_t)(void);
|
||||
#define BOOST_ATOMIC_KERNEL_DMB (*(kernel_dmb_t *)0xffff0fa0)
|
||||
|
||||
static inline void fence_before(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
// FIXME I really don't know which of these cases should call
|
||||
// kernel_dmb() and which shouldn't...
|
||||
case memory_order_consume:
|
||||
case memory_order_release:
|
||||
case memory_order_acq_rel:
|
||||
case memory_order_seq_cst:
|
||||
BOOST_ATOMIC_KERNEL_DMB();
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void fence_after(memory_order order)
|
||||
{
|
||||
switch(order) {
|
||||
// FIXME I really don't know which of these cases should call
|
||||
// kernel_dmb() and which shouldn't...
|
||||
case memory_order_acquire:
|
||||
case memory_order_acq_rel:
|
||||
case memory_order_seq_cst:
|
||||
BOOST_ATOMIC_KERNEL_DMB();
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
#undef BOOST_ATOMIC_KERNEL_DMB
|
||||
|
||||
|
||||
template<typename T>
|
||||
class atomic_linux_arm_4 {
|
||||
|
||||
// typedef int (kernel_cmpxchg_t)(T oldval, T newval, T *ptr);
|
||||
typedef int (kernel_cmpxchg_t)(T oldval, T newval, volatile T *ptr);
|
||||
# define BOOST_ATOMIC_KERNEL_CMPXCHG (*(kernel_cmpxchg_t *)0xffff0fc0)
|
||||
// Returns 0 if *ptr was changed.
|
||||
|
||||
public:
|
||||
explicit atomic_linux_arm_4(T v) : i(v) {}
|
||||
atomic_linux_arm_4() {}
|
||||
T load(memory_order order=memory_order_seq_cst) const volatile
|
||||
{
|
||||
T v=const_cast<volatile const T &>(i);
|
||||
fence_after(order);
|
||||
return v;
|
||||
}
|
||||
void store(T v, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
fence_before(order);
|
||||
const_cast<volatile T &>(i)=v;
|
||||
}
|
||||
bool compare_exchange_strong(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
// Aparently we can consider kernel_cmpxchg to be strong if it is retried
|
||||
// by the kernel after being interrupted, which I think it is.
|
||||
// Also it seems that when an ll/sc implementation is used the kernel
|
||||
// loops until the store succeeds.
|
||||
bool success = BOOST_ATOMIC_KERNEL_CMPXCHG(expected,desired,&i)==0;
|
||||
if (!success) expected = load(memory_order_relaxed);
|
||||
return success;
|
||||
}
|
||||
bool compare_exchange_weak(
|
||||
T &expected,
|
||||
T desired,
|
||||
memory_order success_order,
|
||||
memory_order failure_order) volatile
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, success_order, failure_order);
|
||||
}
|
||||
T exchange(T replacement, memory_order order=memory_order_seq_cst) volatile
|
||||
{
|
||||
// Copied from build_exchange.
|
||||
T o=load(memory_order_relaxed);
|
||||
do {} while(!compare_exchange_weak(o, replacement, order, order));
|
||||
return o;
|
||||
// Note that ARM has an atomic swap instruction that we could use here:
|
||||
// T oldval;
|
||||
// asm volatile ("swp\t%0, %1, [%2]" : "=&r"(oldval) : "r" (replacement), "r" (&i) : "memory");
|
||||
// return oldval;
|
||||
// This instruction is deprecated in architecture >= 6. I'm unsure how inefficient
|
||||
// its implementation is on those newer architectures.
|
||||
// I don't think this would gain
|
||||
// much since exchange() is not used often.
|
||||
}
|
||||
|
||||
bool is_lock_free(void) const volatile {return true;}
|
||||
typedef T integral_type;
|
||||
protected:
|
||||
private:
|
||||
T i;
|
||||
|
||||
# undef BOOST_ATOMIC_KERNEL_CMPXCHG
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 4> : public build_atomic_from_exchange<atomic_linux_arm_4<T> > {
|
||||
public:
|
||||
typedef build_atomic_from_exchange<atomic_linux_arm_4<T> > super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 1> : public build_atomic_from_larger_type<atomic_linux_arm_4<uint32_t>, T > {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_linux_arm_4<uint32_t>, T> super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class platform_atomic_integral<T, 2> : public build_atomic_from_larger_type<atomic_linux_arm_4<uint32_t>, T > {
|
||||
public:
|
||||
typedef build_atomic_from_larger_type<atomic_linux_arm_4<uint32_t>, T> super;
|
||||
explicit platform_atomic_integral(T v) : super(v) {}
|
||||
platform_atomic_integral(void) {}
|
||||
};
|
||||
|
||||
|
||||
typedef atomic_linux_arm_4<void *> platform_atomic_address;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
45
include/boost/atomic/detail/valid_integral_types.hpp
Normal file
45
include/boost/atomic/detail/valid_integral_types.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef BOOST_DETAIL_ATOMIC_VALID_INTEGRAL_TYPES_HPP
|
||||
#define BOOST_DETAIL_ATOMIC_VALID_INTEGRAL_TYPES_HPP
|
||||
|
||||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace atomic {
|
||||
|
||||
template<typename T> struct is_integral_type {typedef void test;};
|
||||
|
||||
template<> struct is_integral_type<char> {typedef int test;};
|
||||
|
||||
template<> struct is_integral_type<unsigned char> {typedef int test;};
|
||||
template<> struct is_integral_type<signed char> {typedef int test;};
|
||||
template<> struct is_integral_type<unsigned short> {typedef int test;};
|
||||
template<> struct is_integral_type<signed short> {typedef int test;};
|
||||
template<> struct is_integral_type<unsigned int> {typedef int test;};
|
||||
template<> struct is_integral_type<signed int> {typedef int test;};
|
||||
template<> struct is_integral_type<unsigned long> {typedef int test;};
|
||||
template<> struct is_integral_type<long> {typedef int test;};
|
||||
#ifdef BOOST_HAS_LONG_LONG
|
||||
template<> struct is_integral_type<boost::ulong_long_type> {typedef int test;};
|
||||
template<> struct is_integral_type<boost::long_long_type> {typedef int test;};
|
||||
#endif
|
||||
#ifdef BOOST_ATOMIC_HAVE_GNU_128BIT_INTEGERS
|
||||
template<> struct is_integral_type<__uint128_t> {typedef int test;};
|
||||
template<> struct is_integral_type<__int128_t> {typedef int test;};
|
||||
#endif
|
||||
#if BOOST_MSVC >= 1500 && (defined(_M_IA64) || defined(_M_AMD64)) && defined(BOOST_ATOMIC_HAVE_SSE2)
|
||||
#include <emmintrin.h>
|
||||
template<> struct is_integral_type<__m128i> {typedef int test;};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
42
include/boost/atomic/platform.hpp
Normal file
42
include/boost/atomic/platform.hpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2009 Helge Bahmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
|
||||
|
||||
#include <boost/atomic/detail/gcc-x86.hpp>
|
||||
|
||||
#elif defined(__GNUC__) && defined(__alpha__)
|
||||
|
||||
#include <boost/atomic/detail/gcc-alpha.hpp>
|
||||
|
||||
#elif defined(__GNUC__) && (defined(__POWERPC__) || defined(__PPC__))
|
||||
|
||||
#include <boost/atomic/detail/gcc-ppc.hpp>
|
||||
|
||||
// This list of ARM architecture versions comes from Apple's arm/arch.h header.
|
||||
// I don't know how complete it is.
|
||||
#elif defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|
||||
|| defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \
|
||||
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_7A__))
|
||||
|
||||
#include <boost/atomic/detail/gcc-armv6+.hpp>
|
||||
|
||||
#elif defined(__linux__) && defined(__arm__)
|
||||
|
||||
#include <boost/atomic/detail/linux-arm.hpp>
|
||||
|
||||
#elif defined(BOOST_USE_WINDOWS_H) || defined(_WIN32_CE) || defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
|
||||
|
||||
#include <boost/atomic/detail/interlocked.hpp>
|
||||
|
||||
#else
|
||||
|
||||
#warning "Using slow fallback atomic implementation"
|
||||
#include <boost/atomic/detail/generic-cas.hpp>
|
||||
|
||||
#endif
|
||||
92
include/fc/abstract_types.hpp
Normal file
92
include/fc/abstract_types.hpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
#ifndef _FC_ABSTRACT_TYPES_HPP_
|
||||
#define _FC_ABSTRACT_TYPES_HPP_
|
||||
#include <fc/utility.hpp>
|
||||
#include <fc/log.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
struct abstract_type {
|
||||
virtual ~abstract_type(){}
|
||||
virtual size_t size_of()const = 0;
|
||||
/*
|
||||
* @brief Inplace destructor (does not free memory) ((T*)dst)->~T();
|
||||
*/
|
||||
virtual void destructor( void* dst )const = 0;
|
||||
|
||||
/** @brief 'delete T' */
|
||||
virtual void destroy( void* dst )const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct type : virtual abstract_type {
|
||||
virtual size_t size_of()const { return sizeof(T); }
|
||||
virtual void destructor( void* dst )const { ((T*)dst)->~T(); }
|
||||
virtual void destroy( void* dst )const { delete ((T*)dst); }
|
||||
};
|
||||
|
||||
struct abstract_moveable_type : virtual abstract_type {
|
||||
virtual void move_construct( void* dst, void* src )const = 0;
|
||||
virtual void move( void* dst, void* src )const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct moveable_type : virtual type<T>, virtual abstract_moveable_type {
|
||||
static abstract_moveable_type& instance() { static moveable_type<T> inst; return inst; }
|
||||
virtual void destruct( void* dst )const { ((T*)dst)->~T(); }
|
||||
virtual void move_construct( void* dst, void* src )const { slog( "move construct" ); new ((char*)dst) T( fc::move(*((T*)src)) ); }
|
||||
virtual void move( void* dst, void* src )const { *((T*)dst) = fc::move(*((T*)src)); }
|
||||
};
|
||||
|
||||
struct abstract_value_type : virtual abstract_moveable_type {
|
||||
virtual void construct( void* dst )const = 0;
|
||||
virtual void copy_construct( void* dst, const void* src )const = 0;
|
||||
virtual void assign( void* dst, const void* src )const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructable, moveable, copyable, assignable.
|
||||
*/
|
||||
template<typename T>
|
||||
struct value_type : virtual moveable_type<T>, virtual abstract_value_type {
|
||||
static abstract_value_type& instance() { static value_type<T> inst; return inst; }
|
||||
|
||||
virtual void construct( void* dst )const { new ((char*)dst) T(); }
|
||||
virtual void copy_construct( void* dst, const void* src )const { new ((char*)dst) T( *((const T*)src) ); }
|
||||
virtual void assign( void* dst, const void* src )const { *((T*)dst) = *((const T*)src); }
|
||||
};
|
||||
|
||||
struct abstract_less_than_comparable_type {
|
||||
virtual bool less_than( const void* left, const void* right )const = 0;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct less_than_comparable_type : abstract_less_than_comparable_type {
|
||||
virtual bool less_than( const void* left, const void* right )const {
|
||||
return *((const T*)left) < *((const T*)right);
|
||||
}
|
||||
};
|
||||
|
||||
struct abstract_equal_comparable_type {
|
||||
virtual bool equal( const void* left, const void* right )const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct equal_comparable_type : abstract_equal_comparable_type {
|
||||
virtual bool equal( const void* left, const void* right )const {
|
||||
return *((const T*)left) == *((const T*)right);
|
||||
}
|
||||
};
|
||||
|
||||
struct abstract_callable_type {
|
||||
virtual void call( const void* self )const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct callable_type : virtual abstract_callable_type, virtual value_type<T> {
|
||||
virtual void call( const void* self )const { (*((const T*)self))(); }
|
||||
};
|
||||
|
||||
} // namespace fc
|
||||
|
||||
#endif
|
||||
14
include/fc/aligned.hpp
Normal file
14
include/fc/aligned.hpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef _FC_ALIGNED_HPP_
|
||||
#define _FC_ALIGNED_HPP_
|
||||
namespace fc {
|
||||
|
||||
template<unsigned int S, typename T=double>
|
||||
struct aligned {
|
||||
union {
|
||||
T _align;
|
||||
char _data[S];
|
||||
} _store;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // _FC_ALIGNED_HPP_
|
||||
13
include/fc/any.hpp
Normal file
13
include/fc/any.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef _FC_ANY_HPP_
|
||||
#define _FC_ANY_HPP_
|
||||
|
||||
namespace fc { namespace reflect {
|
||||
|
||||
// provides value semantics
|
||||
struct any {
|
||||
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
#endif // _FC_ANY_HPP_
|
||||
561
include/fc/console_defines.h
Normal file
561
include/fc/console_defines.h
Normal file
|
|
@ -0,0 +1,561 @@
|
|||
#ifndef _MACE_CMT_CONSOLE_DEFINES_H_
|
||||
#define _MACE_CMT_CONSOLE_DEFINES_H_
|
||||
|
||||
/// @cond INTERNAL_DEV
|
||||
/**
|
||||
@file console_defines.h
|
||||
This header contains definitions for console styles and colors.
|
||||
@ingroup tconsole
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
@defgroup console_styles Console Styles
|
||||
@brief Defines styles that can be used within text printed to the Console.
|
||||
|
||||
Note that styles will not show up when printing to files (in fact, you will
|
||||
get a lot of garbage characters if you do this). Also, not all consoles
|
||||
support styled text.
|
||||
@{
|
||||
*/
|
||||
#if COLOR_CONSOLE
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
/**
|
||||
@def CONSOLE_DEFAULT
|
||||
@brief Sets all styles and colors to the console defaults.
|
||||
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_DEFAULT "\033[0m"
|
||||
/**
|
||||
@def CONSOLE_BOLD
|
||||
@brief Print bold console text (or brighten foreground color if present).
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BOLD "\033[1m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_HALF_BRIGHT
|
||||
@brief Print half-bright console text.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_HALF_BRIGHT "\033[2m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_ITALIC
|
||||
@brief Print italic console text.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*) Typically not supported.
|
||||
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_ITALIC "\033[3m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_UNDERLINE
|
||||
@brief Print underlined console text.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_UNDERLINE "\033[4m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_BLINK
|
||||
@brief Print blinking console text.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BLINK "\033[5m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_RAPID_BLINK
|
||||
@brief Print rapidly blinking console text. Typically not supported.
|
||||
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_RAPID_BLINK "\033[6m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_REVERSED
|
||||
@brief Print console text with foreground and background colors reversed.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_REVERSED "\033[7m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_CONCEALED
|
||||
@brief Print concealed console text.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_CONCEALED "\033[8m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_STRIKETHROUGH
|
||||
@brief Print strikethrough console text. Typically not supported.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_STRIKETHROUGH "\033[9m"
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/**
|
||||
@defgroup console_colors Console Colors
|
||||
@brief Defines colors that can be used within text printed to the Console.
|
||||
|
||||
@ingroup tconsole
|
||||
Note that colors will not show up when printing to files (in fact, you will
|
||||
get a lot of garbage characters if you do this). Also, not all consoles
|
||||
support colored text.
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
@def CONSOLE_BLACK
|
||||
@brief Print text with black foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BLACK "\033[30m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_RED
|
||||
@brief Print text with red foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_RED "\033[31m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_GREEN
|
||||
@brief Print text with green foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_GREEN "\033[32m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_BROWN
|
||||
@brief Print text with brown foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BROWN "\033[33m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_BLUE
|
||||
@brief Print text with blue foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BLUE "\033[34m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_MAGENTA
|
||||
@brief Print text with magenta foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_MAGENTA "\033[35m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_CYAN
|
||||
@brief Print text with cyan foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_CYAN "\033[36m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_WHITE
|
||||
@brief Print text with white foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_WHITE "\033[37m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_BLACK_BG
|
||||
@brief Print text with black background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BLACK_BG "\033[40m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_RED_BG
|
||||
@brief Print text with red background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_RED_BG "\033[41m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_GREEN_BG
|
||||
@brief Print text with green background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_GREEN_BG "\033[42m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_BROWN_BG
|
||||
@brief Print text with brown background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BROWN_BG "\033[43m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_BLUE_BG
|
||||
@brief Print text with blue background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BLUE_BG "\033[44m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_MAGENTA_BG
|
||||
@brief Print text with magenta background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_MAGENTA_BG "\033[45m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_CYAN_BG
|
||||
@brief Print text with cyan background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_CYAN_BG "\033[46m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_WHITE_BG
|
||||
@brief Print text with white background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_WHITE_BG "\033[47m"
|
||||
|
||||
|
||||
|
||||
#else // WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
//#include <stdlib.h>
|
||||
#include <conio.h>
|
||||
|
||||
/**
|
||||
@def CONSOLE_DEFAULT
|
||||
@brief Sets all styles and colors to the console defaults.
|
||||
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_DEFAULT (FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN)
|
||||
/**
|
||||
@def CONSOLE_BOLD
|
||||
@brief Print bold console text (or brighten foreground color if present).
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BOLD FOREGROUND_INTENSITY
|
||||
|
||||
/**
|
||||
@def CONSOLE_HALF_BRIGHT
|
||||
@brief Print half-bright console text.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_HALF_BRIGHT
|
||||
|
||||
/**
|
||||
@def CONSOLE_ITALIC
|
||||
@brief Print italic console text.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*) Typically not supported.
|
||||
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_ITALIC
|
||||
|
||||
/**
|
||||
@def CONSOLE_UNDERLINE
|
||||
@brief Print underlined console text.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_UNDERLINE COMMON_LVB_UNDERSCORE
|
||||
|
||||
/**
|
||||
@def CONSOLE_BLINK
|
||||
@brief Print blinking console text.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BLINK
|
||||
|
||||
/**
|
||||
@def CONSOLE_RAPID_BLINK
|
||||
@brief Print rapidly blinking console text. Typically not supported.
|
||||
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_RAPID_BLINK
|
||||
|
||||
/**
|
||||
@def CONSOLE_REVERSED
|
||||
@brief Print console text with foreground and background colors reversed.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_REVERSED CONSOLE_LVB_REVERSE_VIDEO
|
||||
|
||||
/**
|
||||
@def CONSOLE_CONCEALED
|
||||
@brief Print concealed console text.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_CONCEALED
|
||||
|
||||
/**
|
||||
@def CONSOLE_STRIKETHROUGH
|
||||
@brief Print strikethrough console text. Typically not supported.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_STRIKETHROUGH
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/**
|
||||
@defgroup console_colors Console Colors
|
||||
@brief Defines colors that can be used within text printed to the Console.
|
||||
|
||||
@ingroup tconsole
|
||||
Note that colors will not show up when printing to files (in fact, you will
|
||||
get a lot of garbage characters if you do this). Also, not all consoles
|
||||
support colored text.
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
@def CONSOLE_BLACK
|
||||
@brief Print text with black foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BLACK 0
|
||||
|
||||
/**
|
||||
@def CONSOLE_RED
|
||||
@brief Print text with red foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_RED FOREGROUND_RED
|
||||
|
||||
/**
|
||||
@def CONSOLE_GREEN
|
||||
@brief Print text with green foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_GREEN FOREGROUND_GREEN
|
||||
|
||||
/**
|
||||
@def CONSOLE_BROWN
|
||||
@brief Print text with brown foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BROWN (FOREGROUND_RED | FOREGROUND_GREEN)
|
||||
|
||||
/**
|
||||
@def CONSOLE_BLUE
|
||||
@brief Print text with blue foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BLUE FOREGROUND_BLUE
|
||||
|
||||
/**
|
||||
@def CONSOLE_MAGENTA
|
||||
@brief Print text with magenta foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_MAGENTA (CONSOLE_RED | CONSOLE_BLUE)
|
||||
|
||||
/**
|
||||
@def CONSOLE_CYAN
|
||||
@brief Print text with cyan foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_CYAN (CONSOLE_BLUE | CONSOLE_GREEN)
|
||||
|
||||
/**
|
||||
@def CONSOLE_WHITE
|
||||
@brief Print text with white foreground.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_WHITE (CONSOLE_RED | CONSOLE_BLUE | CONSOLE_GREEN)
|
||||
|
||||
/**
|
||||
@def CONSOLE_BLACK_BG
|
||||
@brief Print text with black background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BLACK_BG 0
|
||||
|
||||
/**
|
||||
@def CONSOLE_RED_BG
|
||||
@brief Print text with red background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_RED_BG (BACKGROUND_RED)
|
||||
|
||||
/**
|
||||
@def CONSOLE_GREEN_BG
|
||||
@brief Print text with green background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_GREEN_BG (BACKGROUND_GREEN)
|
||||
|
||||
/**
|
||||
@def CONSOLE_BROWN_BG
|
||||
@brief Print text with brown background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BROWN_BG (BACKGROUND_RED | BACKGROUND_GREEN)
|
||||
|
||||
/**
|
||||
@def CONSOLE_BLUE_BG
|
||||
@brief Print text with blue background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_BLUE_BG (BACKGROUND_BLUE)
|
||||
|
||||
/**
|
||||
@def CONSOLE_MAGENTA_BG
|
||||
@brief Print text with magenta background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_MAGENTA_BG "\033[45m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_CYAN_BG
|
||||
@brief Print text with cyan background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_CYAN_BG "\033[46m"
|
||||
|
||||
/**
|
||||
@def CONSOLE_WHITE_BG
|
||||
@brief Print text with white background.
|
||||
|
||||
@ingroup tconsole
|
||||
(const char*)
|
||||
*/
|
||||
#define CONSOLE_WHITE_BG "\033[47m"
|
||||
#endif
|
||||
|
||||
|
||||
/// @}
|
||||
#else // On Window's no color output WIN32
|
||||
#define CONSOLE_DEFAULT ""
|
||||
#define CONSOLE_BOLD ""
|
||||
#define CONSOLE_HALF_BRIGHT ""
|
||||
#define CONSOLE_ITALIC ""
|
||||
#define CONSOLE_UNDERLINE ""
|
||||
#define CONSOLE_BLINK ""
|
||||
#define CONSOLE_RAPID_BLINK ""
|
||||
#define CONSOLE_REVERSED ""
|
||||
#define CONSOLE_CONCEALED ""
|
||||
#define CONSOLE_STRIKETHROUGH ""
|
||||
#define CONSOLE_BLACK ""
|
||||
#define CONSOLE_RED ""
|
||||
#define CONSOLE_GREEN ""
|
||||
#define CONSOLE_BROWN ""
|
||||
#define CONSOLE_BLUE ""
|
||||
#define CONSOLE_MAGENTA ""
|
||||
#define CONSOLE_CYAN ""
|
||||
#define CONSOLE_WHITE ""
|
||||
#define CONSOLE_BLACK_BG ""
|
||||
#define CONSOLE_RED_BG ""
|
||||
#define CONSOLE_GREEN_BG ""
|
||||
#define CONSOLE_BROWN_BG ""
|
||||
#define CONSOLE_BLUE_BG ""
|
||||
#define CONSOLE_MAGENTA_BG ""
|
||||
#define CONSOLE_CYAN_BG ""
|
||||
#define CONSOLE_WHITE_BG ""
|
||||
|
||||
/// @}
|
||||
/// @endcond INTERNAL_DEV
|
||||
#endif // NOT DEFINED WIN32
|
||||
#endif // _BOOST_CMT_CONSOLE_DEFINES_H_
|
||||
17
include/fc/error.hpp
Normal file
17
include/fc/error.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef _FC_ERROR_HPP_
|
||||
#define _FC_ERROR_HPP_
|
||||
|
||||
namespace fc {
|
||||
struct future_wait_timeout: public std::exception{};
|
||||
struct task_canceled: public std::exception{};
|
||||
struct thread_quit: public std::exception{};
|
||||
struct wait_any_error: public std::exception{};
|
||||
struct bad_cast: public std::exception{
|
||||
const char* what()const throw(){ return "bad cast"; }
|
||||
};
|
||||
struct range_error: public std::exception{
|
||||
const char* what()const throw(){ return "range error"; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _FC_ERROR_HPP_
|
||||
12
include/fc/example.hpp
Normal file
12
include/fc/example.hpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef _EXAMPLE_HPP_
|
||||
#define _EXAMPLE_HPP_
|
||||
#include <fc/reflect_fwd.hpp>
|
||||
|
||||
struct example {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
FC_REFLECTABLE( example )
|
||||
|
||||
#endif // _EXAMPLE_HPP_
|
||||
54
include/fc/exception.hpp
Normal file
54
include/fc/exception.hpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef _FC_EXCEPTION_HPP_
|
||||
#define _FC_EXCEPTION_HPP_
|
||||
#include <fc/shared_ptr.hpp>
|
||||
#include <fc/string.hpp>
|
||||
|
||||
// provided for easy integration with boost.
|
||||
namespace boost { class exception_ptr; }
|
||||
|
||||
namespace fc {
|
||||
/**
|
||||
* Simply including boost/exception_ptr.hpp is enough to significantly
|
||||
* lengthen compile times. This header defines an 'opaque' exception
|
||||
* type that provides the most 'general' exception handling needs without
|
||||
* requiring a significant amount of code to be included.
|
||||
*/
|
||||
class exception_ptr {
|
||||
public:
|
||||
exception_ptr();
|
||||
exception_ptr( const boost::exception_ptr& c );
|
||||
exception_ptr( boost::exception_ptr&& c );
|
||||
exception_ptr( const exception_ptr& c );
|
||||
exception_ptr( exception_ptr&& c );
|
||||
~exception_ptr();
|
||||
|
||||
exception_ptr& operator=(const boost::exception_ptr& c);
|
||||
exception_ptr& operator=(boost::exception_ptr&& c);
|
||||
|
||||
exception_ptr& operator=(const exception_ptr& c);
|
||||
exception_ptr& operator=(exception_ptr&& c);
|
||||
|
||||
fc::string diagnostic_information()const;
|
||||
|
||||
operator bool()const;
|
||||
|
||||
operator const boost::exception_ptr& ()const;
|
||||
operator boost::exception_ptr& ();
|
||||
private:
|
||||
char my[sizeof(void*)*2];
|
||||
};
|
||||
|
||||
exception_ptr current_exception();
|
||||
template<typename T>
|
||||
inline exception_ptr copy_exception( T&& e ) {
|
||||
try { throw e; } catch (...) { return current_exception(); }
|
||||
return exception_ptr();
|
||||
}
|
||||
void rethrow_exception( const exception_ptr& e );
|
||||
|
||||
} // namespace fc
|
||||
|
||||
#define FC_THROW( X ) throw (X)
|
||||
|
||||
|
||||
#endif // _FC_EXCEPTION_HPP_
|
||||
50
include/fc/function.hpp
Normal file
50
include/fc/function.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef _FC_FUNCTION_HPP_
|
||||
#define _FC_FUNCTION_HPP_
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace detail {
|
||||
template<typename Functor>
|
||||
void call( void* functor ) {
|
||||
(*static_cast<Functor*>(functor*))();
|
||||
}
|
||||
}
|
||||
|
||||
class function {
|
||||
public:
|
||||
template<typename Functor>
|
||||
function( Functor&& f ) {
|
||||
static_assert( sizeof(f) <= sizeof(store) );
|
||||
new ((void*)&store[0]) Functor( fc::forward<Functor>(f) );
|
||||
call = &detail::call<Functor>;
|
||||
copy = &detail::copy<Functor>;
|
||||
move = &detail::move<Functor>;
|
||||
}
|
||||
|
||||
function( const function& f )
|
||||
:call(f.call),move(f.move),copy(f.copy){
|
||||
copy( &f.store[0], &store[0] );
|
||||
}
|
||||
|
||||
function( function&& f )
|
||||
:call(f.call),move(f.move),copy(f.copy){
|
||||
move( &f.store[0], &store[0] );
|
||||
}
|
||||
|
||||
function& operator = ( function&& f ) {
|
||||
|
||||
}
|
||||
|
||||
void operator()()const { call(&store[0]); }
|
||||
|
||||
private:
|
||||
uint64_t store[8];
|
||||
void (*call)(void*);
|
||||
void (*move)(void* src, void* dst);
|
||||
void (*copy)(const void*, void* dst);
|
||||
void (*destroy)(void*);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _FC_FUNCTION_HPP_
|
||||
243
include/fc/future.hpp
Normal file
243
include/fc/future.hpp
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
#ifndef _FC_FUTURE_HPP_
|
||||
#define _FC_FUTURE_HPP_
|
||||
#include <fc/utility.hpp>
|
||||
#include <fc/time.hpp>
|
||||
#include <fc/shared_ptr.hpp>
|
||||
#include <fc/exception.hpp>
|
||||
#include <fc/spin_yield_lock.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
|
||||
namespace fc {
|
||||
class abstract_thread;
|
||||
class void_t;
|
||||
class priority;
|
||||
class exception_ptr;
|
||||
class thread;
|
||||
|
||||
namespace detail {
|
||||
class completion_handler {
|
||||
public:
|
||||
virtual ~completion_handler(){};
|
||||
virtual void on_complete( const void* v, const fc::exception_ptr& e ) = 0;
|
||||
};
|
||||
|
||||
template<typename Functor, typename T>
|
||||
class completion_handler_impl : public completion_handler {
|
||||
public:
|
||||
completion_handler_impl( Functor&& f ):_func(fc::move(f)){}
|
||||
completion_handler_impl( const Functor& f ):_func(f){}
|
||||
|
||||
virtual void on_complete( const void* v, const fc::exception_ptr& e ) {
|
||||
_func( *static_cast<const T*>(v), e);
|
||||
}
|
||||
private:
|
||||
Functor _func;
|
||||
};
|
||||
template<typename Functor>
|
||||
class completion_handler_impl<Functor,void> : public completion_handler {
|
||||
public:
|
||||
completion_handler_impl( Functor&& f ):_func(fc::move(f)){}
|
||||
completion_handler_impl( const Functor& f ):_func(f){}
|
||||
virtual void on_complete( const void* v, const fc::exception_ptr& e ) {
|
||||
_func(e);
|
||||
}
|
||||
private:
|
||||
Functor _func;
|
||||
};
|
||||
}
|
||||
|
||||
class promise_base : virtual public retainable {
|
||||
public:
|
||||
typedef shared_ptr<promise_base> ptr;
|
||||
promise_base(const char* desc="");
|
||||
|
||||
const char* get_desc()const;
|
||||
|
||||
void cancel();
|
||||
bool ready()const;
|
||||
bool error()const;
|
||||
|
||||
void set_exception( const fc::exception_ptr& e );
|
||||
|
||||
protected:
|
||||
void _wait( const microseconds& timeout_us );
|
||||
void _wait_until( const time_point& timeout_us );
|
||||
void _enqueue_thread();
|
||||
void _notify();
|
||||
void _set_timeout();
|
||||
void _set_value(const void* v);
|
||||
|
||||
void _on_complete( detail::completion_handler* c );
|
||||
private:
|
||||
friend class thread;
|
||||
friend struct context;
|
||||
friend class thread_d;
|
||||
|
||||
bool _ready;
|
||||
mutable spin_yield_lock _spin_yield;
|
||||
thread* _blocked_thread;
|
||||
time_point _timeout;
|
||||
fc::exception_ptr _except;
|
||||
bool _canceled;
|
||||
const char* _desc;
|
||||
detail::completion_handler* _compl;
|
||||
};
|
||||
|
||||
template<typename T = void>
|
||||
class promise : virtual public promise_base {
|
||||
public:
|
||||
typedef shared_ptr< promise<T> > ptr;
|
||||
promise( const char* desc = "" ):promise_base(desc){}
|
||||
promise( const T& val ){ set_value(val); }
|
||||
promise( T&& val ){ set_value(fc::move(val) ); }
|
||||
~promise(){}
|
||||
|
||||
const T& wait(const microseconds& timeout = microseconds::max() ){
|
||||
this->_wait( timeout );
|
||||
return *result;
|
||||
}
|
||||
const T& wait_until(const time_point& tp ) {
|
||||
this->_wait_until( tp );
|
||||
return *result;
|
||||
}
|
||||
|
||||
void set_value( const T& v ) {
|
||||
result = v;
|
||||
_set_value(&*result);
|
||||
}
|
||||
|
||||
void set_value( T&& v ) {
|
||||
result = fc::move(v);
|
||||
_set_value(&*result);
|
||||
}
|
||||
|
||||
template<typename CompletionHandler>
|
||||
void on_complete( CompletionHandler&& c ) {
|
||||
_on_complete( new detail::completion_handler_impl<CompletionHandler,T>(fc::forward<CompletionHandler>(c)) );
|
||||
}
|
||||
protected:
|
||||
optional<T> result;
|
||||
};
|
||||
|
||||
template<>
|
||||
class promise<void> : public promise_base {
|
||||
public:
|
||||
typedef shared_ptr< promise<void> > ptr;
|
||||
promise( const char* desc = "" ):promise_base(desc){}
|
||||
promise( const void_t& v ){ set_value(); }
|
||||
|
||||
void wait(const microseconds& timeout = microseconds::max() ){
|
||||
this->_wait( timeout );
|
||||
}
|
||||
void wait_until(const time_point& tp ) {
|
||||
this->_wait_until( tp );
|
||||
}
|
||||
|
||||
void set_value(){ this->_set_value(nullptr); }
|
||||
void set_value( const void_t& v ) { this->_set_value(nullptr); }
|
||||
|
||||
template<typename CompletionHandler>
|
||||
void on_complete( CompletionHandler&& c ) {
|
||||
_on_complete( new detail::completion_handler_impl<CompletionHandler,void>(fc::forward<CompletionHandler>(c)) );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief a placeholder for the result of an asynchronous operation.
|
||||
*
|
||||
* By calling future<T>::wait() you will block the current fiber until
|
||||
* the asynchronous operation completes.
|
||||
*
|
||||
* If you would like to use an asynchronous interface instead of the synchronous
|
||||
* 'wait' method you could specify a CompletionHandler which is a method that takes
|
||||
* two parameters, a const reference to the value and an exception_ptr. If the
|
||||
* exception_ptr is set, the value reference is invalid and accessing it is
|
||||
* 'undefined'.
|
||||
*
|
||||
* Promises have pointer semantics, futures have reference semantics that
|
||||
* contain a shared pointer to a promise.
|
||||
*/
|
||||
template<typename T>
|
||||
class future {
|
||||
public:
|
||||
future( const shared_ptr<promise<T>>& p ):m_prom(p){}
|
||||
future( shared_ptr<promise<T>>&& p ):m_prom(fc::move(p)){}
|
||||
future(){}
|
||||
|
||||
/// @pre valid()
|
||||
/// @post ready()
|
||||
/// @throws timeout
|
||||
const T& wait( const microseconds& timeout = microseconds::max() ){
|
||||
return m_prom->wait(timeout);
|
||||
}
|
||||
|
||||
/// @pre valid()
|
||||
/// @post ready()
|
||||
/// @throws timeout
|
||||
const T& wait_until( const time_point& tp ) {
|
||||
return m_prom->wait_until(tp);
|
||||
}
|
||||
|
||||
bool valid()const { return !!m_prom; }
|
||||
|
||||
/// @pre valid()
|
||||
bool ready()const { return m_prom->ready(); }
|
||||
|
||||
/// @pre valid()
|
||||
bool error()const { return m_prom->error(); }
|
||||
|
||||
/**
|
||||
* @pre valid()
|
||||
*
|
||||
* The given completion handler will be called from some
|
||||
* arbitrary thread and should not 'block'. Generally
|
||||
* it should post an event or start a new async operation.
|
||||
*/
|
||||
template<typename CompletionHandler>
|
||||
void on_complete( CompletionHandler&& c ) {
|
||||
m_prom->on_complete( fc::forward<CompletionHandler>(c) );
|
||||
}
|
||||
private:
|
||||
shared_ptr<promise<T>> m_prom;
|
||||
};
|
||||
|
||||
template<>
|
||||
class future<void> {
|
||||
public:
|
||||
future( const shared_ptr<promise<void>>& p ):m_prom(p){}
|
||||
future( shared_ptr<promise<void>>&& p ):m_prom(fc::move(p)){}
|
||||
future(){}
|
||||
|
||||
/// @pre valid()
|
||||
/// @post ready()
|
||||
/// @throws timeout
|
||||
void wait( const microseconds& timeout = microseconds::max() ){
|
||||
m_prom->wait(timeout);
|
||||
}
|
||||
|
||||
/// @pre valid()
|
||||
/// @post ready()
|
||||
/// @throws timeout
|
||||
void wait_until( const time_point& tp ) {
|
||||
m_prom->wait_until(tp);
|
||||
}
|
||||
|
||||
bool valid()const { return !!m_prom; }
|
||||
|
||||
/// @pre valid()
|
||||
bool ready()const { return m_prom->ready(); }
|
||||
|
||||
/// @pre valid()
|
||||
bool error()const { return m_prom->error(); }
|
||||
|
||||
template<typename CompletionHandler>
|
||||
void on_complete( CompletionHandler&& c ) {
|
||||
m_prom->on_complete( fc::forward<CompletionHandler>(c) );
|
||||
}
|
||||
|
||||
private:
|
||||
shared_ptr<promise<void>> m_prom;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _FC_FUTURE_HPP_
|
||||
45
include/fc/fwd.hpp
Normal file
45
include/fc/fwd.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef FC_FWD_HPP_
|
||||
#define FC_FWD_HPP_
|
||||
#include <fc/aligned.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
/**
|
||||
* @brief Used to forward declare value types.
|
||||
*
|
||||
*/
|
||||
template<typename T,unsigned int S, typename Align=double>
|
||||
class fwd {
|
||||
public:
|
||||
template<typename U> fwd( U&& u );
|
||||
fwd();
|
||||
|
||||
fwd( const fwd& f );
|
||||
fwd( fwd&& f );
|
||||
|
||||
operator const T&()const;
|
||||
operator T&();
|
||||
|
||||
T& operator*();
|
||||
const T& operator*()const;
|
||||
const T* operator->()const;
|
||||
|
||||
T* operator->();
|
||||
bool operator !()const;
|
||||
|
||||
template<typename U>
|
||||
T& operator = ( U&& u );
|
||||
|
||||
T& operator = ( fwd&& u );
|
||||
T& operator = ( const fwd& u );
|
||||
|
||||
~fwd();
|
||||
|
||||
private:
|
||||
aligned<S,Align> _store;
|
||||
};
|
||||
|
||||
|
||||
} // namespace fc
|
||||
|
||||
#endif
|
||||
117
include/fc/fwd_impl.hpp
Normal file
117
include/fc/fwd_impl.hpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
#ifndef _FC_FWD_IMPL_HPP_
|
||||
#define _FC_FWD_IMPL_HPP_
|
||||
|
||||
#include <fc/utility.hpp>
|
||||
#include <fc/fwd.hpp>
|
||||
#include <new>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace detail {
|
||||
template<typename A, typename U>
|
||||
struct add {
|
||||
typedef decltype( *((A*)0) + *((typename fc::remove_reference<U>::type*)0) ) type;
|
||||
};
|
||||
template<typename A, typename U>
|
||||
struct add_eq {
|
||||
typedef decltype( *((A*)0) += *((typename fc::remove_reference<U>::type*)0) ) type;
|
||||
};
|
||||
|
||||
template<typename A, typename U>
|
||||
struct sub {
|
||||
typedef decltype( *((A*)0) - *((typename fc::remove_reference<U>::type*)0) ) type;
|
||||
};
|
||||
|
||||
template<typename A, typename U>
|
||||
struct sub_eq {
|
||||
typedef decltype( *((A*)0) -= *((typename fc::remove_reference<U>::type*)0) ) type;
|
||||
};
|
||||
template<typename A, typename U>
|
||||
struct insert_op {
|
||||
typedef decltype( *((A*)0) << *((typename fc::remove_reference<U>::type*)0) ) type;
|
||||
};
|
||||
template<typename A, typename U>
|
||||
struct extract_op {
|
||||
A* a;
|
||||
U* u;
|
||||
typedef decltype( *a >> *u ) type;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
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); }
|
||||
|
||||
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); }
|
||||
|
||||
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; }
|
||||
|
||||
template<typename T, unsigned int S, typename U, typename A>
|
||||
auto operator >> ( U& u, fwd<T,S,A>& f ) -> typename detail::extract_op<U,T>::type { return u >> *f; }
|
||||
|
||||
template<typename T, unsigned int S, typename A>
|
||||
bool fwd<T,S,A>::operator !()const { return !(**this); }
|
||||
|
||||
|
||||
template<typename T,unsigned int S,typename A>
|
||||
template<typename U>
|
||||
fwd<T,S,A>::fwd( U&& u ) {
|
||||
static_assert( sizeof(_store) >= sizeof(*this), "Failed to reserve enough space" );
|
||||
new (this) T( fc::forward<U>(u) );
|
||||
}
|
||||
template<typename T,unsigned int S,typename A>
|
||||
fwd<T,S,A>::fwd() {
|
||||
static_assert( sizeof(_store) >= sizeof(*this), "Failed to reserve enough space" );
|
||||
new (this) T();
|
||||
}
|
||||
template<typename T,unsigned int S,typename A>
|
||||
fwd<T,S,A>::fwd( const fwd<T,S,A>& f ){
|
||||
new (this) T( *f );
|
||||
}
|
||||
template<typename T,unsigned int S,typename A>
|
||||
fwd<T,S,A>::fwd( fwd<T,S,A>&& f ){
|
||||
new (this) T( fc::move(*f) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T,unsigned int S, typename A>
|
||||
fwd<T,S,A>::operator T&() { return *(( T*)this); }
|
||||
template<typename T,unsigned int S, typename A>
|
||||
fwd<T,S,A>::operator const T&()const { return *((const T*)this); }
|
||||
|
||||
template<typename T,unsigned int S, typename A>
|
||||
T& fwd<T,S,A>::operator*() { return *((T*)this); }
|
||||
template<typename T,unsigned int S, typename A>
|
||||
const T& fwd<T,S,A>::operator*()const { return *((const T*)this); }
|
||||
template<typename T,unsigned int S, typename A>
|
||||
const T* fwd<T,S,A>::operator->()const { return ((const T*)this); }
|
||||
|
||||
template<typename T,unsigned int S, typename A>
|
||||
T* fwd<T,S,A>::operator->(){ return ((T*)this); }
|
||||
|
||||
|
||||
template<typename T,unsigned int S, typename A>
|
||||
fwd<T,S,A>::~fwd() {
|
||||
((T*)this)->~T();
|
||||
}
|
||||
template<typename T,unsigned int S, typename A>
|
||||
template<typename U>
|
||||
T& fwd<T,S,A>::operator = ( U&& u ) {
|
||||
return **this = fc::forward<U>(u);
|
||||
}
|
||||
|
||||
template<typename T,unsigned int S, typename A>
|
||||
T& fwd<T,S,A>::operator = ( fwd<T,S,A>&& u ) {
|
||||
return **this = fc::move(*u);
|
||||
}
|
||||
template<typename T,unsigned int S, typename A>
|
||||
T& fwd<T,S,A>::operator = ( const fwd<T,S,A>& u ) {
|
||||
return **this = *u;
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
|
||||
#endif //_FC_FWD_IMPL_HPP_
|
||||
21
include/fc/fwd_reflect.hpp
Normal file
21
include/fc/fwd_reflect.hpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef _FC_FWD_REFLECT_HPP_
|
||||
#define _FC_FWD_REFLECT_HPP_
|
||||
#include <fc/reflect.hpp>
|
||||
#include <fc/fwd.hpp>
|
||||
|
||||
namespace fc {
|
||||
template<typename T,unsigned int S>
|
||||
class reflector<fwd<T,S>> : public detail::reflector_impl<fwd<T,S>, reflector<fwd<T,S>> >{
|
||||
public:
|
||||
virtual const char* name()const { return instance().name(); }
|
||||
virtual void visit( void* s, const abstract_visitor& v )const {
|
||||
instance().visit(s,v);
|
||||
}
|
||||
virtual void visit( const void* s, const abstract_const_visitor& v )const {
|
||||
instance().visit(s,v);
|
||||
}
|
||||
|
||||
static reflector<T>& instance() { return reflector<T>::instance(); }
|
||||
};
|
||||
} // namespace fc
|
||||
#endif //_FC_FWD_REFLECT_HPP_
|
||||
17
include/fc/invokeable.hpp
Normal file
17
include/fc/invokeable.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef _FC_INVOKEABLE_HPP_
|
||||
#define _FC_INVOKEABLE_HPP_
|
||||
|
||||
namespace fc {
|
||||
|
||||
class invokeable {
|
||||
public:
|
||||
virtual ~invokeable(){};
|
||||
|
||||
virtual void invoke( const promise::ptr& prom, const string& name, size_t num_params, reflect::cref* params );
|
||||
|
||||
void invoke( const std::string& name ) { invoke( promise::ptr(), name, 0, 0 ); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _FC_INVOKEABLE_HPP_
|
||||
28
include/fc/json.hpp
Normal file
28
include/fc/json.hpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef _FC_JSON_HPP_
|
||||
#define _FC_JSON_HPP_
|
||||
#include <fc/string.hpp>
|
||||
#include <fc/reflect_fwd.hpp>
|
||||
#include <fc/value_fwd.hpp>
|
||||
|
||||
namespace fc {
|
||||
class istream;
|
||||
class ostream;
|
||||
class cref;
|
||||
|
||||
namespace json {
|
||||
string to_string( const cref& o );
|
||||
value_fwd from_string( const string& s );
|
||||
value_fwd from_string( const char* s, const char* e );
|
||||
void from_string( const string&, const ref& o );
|
||||
|
||||
template<typename T>
|
||||
T from_string( const string& s ) {
|
||||
T tmp; from_string( s, tmp );
|
||||
return tmp;
|
||||
}
|
||||
string escape_string( const string& );
|
||||
string unescape_string( const string& );
|
||||
void write( ostream& out, const cref& val );
|
||||
} }
|
||||
|
||||
#endif
|
||||
71
include/fc/json_rpc_connection.hpp
Normal file
71
include/fc/json_rpc_connection.hpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#ifndef _JSON_RPC_CONNECTION_HPP_
|
||||
#define _JSON_RPC_CONNECTION_HPP_
|
||||
#include <fc/reflect_ptr.hpp>
|
||||
#include <fc/json.hpp>
|
||||
#include <fc/stream.hpp>
|
||||
#include <fc/future.hpp>
|
||||
|
||||
namespace fc { namespace json {
|
||||
namespace detail {
|
||||
struct pending_result : virtual public promise_base {
|
||||
typedef shared_ptr<pending_result> ptr;
|
||||
virtual void handle_result( const fc::string& ) = 0;
|
||||
void handle_error( const fc::string& );
|
||||
int64_t id;
|
||||
pending_result::ptr next;
|
||||
};
|
||||
template<typename T>
|
||||
struct pending_result_impl : virtual public promise<T>, virtual public pending_result {
|
||||
virtual void handle_result( const fc::string& s ) {
|
||||
set_value( fc::json::from_string<T>(s) );
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct pending_result_impl<void> : virtual public promise<void>, virtual public pending_result {
|
||||
virtual void handle_result( const fc::string& ) {
|
||||
set_value();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
This class is designed to be used like this:
|
||||
@code
|
||||
class my_api {
|
||||
|
||||
future<int> function( const string& arg, int arg2 ) {
|
||||
_con->invoke<int>( "function", {&arg,&arg2} );
|
||||
}
|
||||
private:
|
||||
rpc_connection* _con;
|
||||
};
|
||||
@endcode
|
||||
|
||||
*/
|
||||
class rpc_connection : virtual public retainable {
|
||||
public:
|
||||
rpc_connection();
|
||||
rpc_connection( istream& i, ostream& o );
|
||||
rpc_connection( rpc_connection&& c );
|
||||
~rpc_connection();
|
||||
|
||||
rpc_connection& operator=(rpc_connection&& m);
|
||||
|
||||
void init( istream& i, ostream& o );
|
||||
|
||||
template<typename R, uint16_t N>
|
||||
future<R> invoke( const fc::string& method, const cptr (¶ms)[N] ) {
|
||||
auto r = new detail::pending_result_impl<R>();
|
||||
invoke( detail::pending_result::ptr(r), method, N, params );
|
||||
return promise<R>::ptr( r, true );
|
||||
}
|
||||
|
||||
private:
|
||||
void invoke( detail::pending_result::ptr&& p, const fc::string& m,
|
||||
uint16_t nparam, const cptr* param );
|
||||
class rpc_connection_d* my;
|
||||
};
|
||||
} } // fc::json
|
||||
|
||||
|
||||
#endif // _JSON_RPC_CONNECTION_HPP_
|
||||
33
include/fc/log.hpp
Normal file
33
include/fc/log.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef _FC_LOG_HPP_
|
||||
#define _FC_LOG_HPP_
|
||||
#include <fc/utility.hpp>
|
||||
|
||||
namespace boost { class mutex; }
|
||||
|
||||
namespace fc {
|
||||
/** wrapper on printf */
|
||||
void log( const char* color, const char* file_name, size_t line_num, const char* method_name, const char* format, ... );
|
||||
|
||||
/** used to add extra fields to be printed (thread,fiber,time,etc) */
|
||||
void add_log_field( void (*f)() );
|
||||
void remove_log_field( void (*f)() );
|
||||
|
||||
boost::mutex& log_mutex();
|
||||
}
|
||||
|
||||
#ifndef __func__
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
#define COLOR_CONSOLE 1
|
||||
#endif
|
||||
#include <fc/console_defines.h>
|
||||
|
||||
#define dlog(...) do { fc::log( CONSOLE_DEFAULT, __FILE__, __LINE__, __func__, __VA_ARGS__ ); }while(false)
|
||||
#define slog(...) do { fc::log( CONSOLE_DEFAULT, __FILE__, __LINE__, __func__, __VA_ARGS__ ); }while(false)
|
||||
#define wlog(...) do { fc::log( CONSOLE_BROWN, __FILE__, __LINE__, __func__, __VA_ARGS__ ); }while(false)
|
||||
#define elog(...) do { fc::log( CONSOLE_RED, __FILE__, __LINE__, __func__, __VA_ARGS__ ); }while(false)
|
||||
|
||||
|
||||
#endif // _FC_LOG_HPP_
|
||||
18
include/fc/map.hpp
Normal file
18
include/fc/map.hpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef _FC_MAP_HPP_
|
||||
namespace fc {
|
||||
|
||||
namespace detail {
|
||||
class map_impl {
|
||||
public:
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
template<typename K, typename V>
|
||||
class map : public map_impl {
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
90
include/fc/optional.hpp
Normal file
90
include/fc/optional.hpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#ifndef _FC_OPTIONAL_HPP_
|
||||
#define _FC_OPTIONAL_HPP_
|
||||
#include <fc/utility.hpp>
|
||||
|
||||
namespace fc {
|
||||
/**
|
||||
* @brief provides stack-based nullable value similar to boost::optional
|
||||
*
|
||||
* Simply including boost::optional adds 35,000 lines to each object file, using
|
||||
* fc::optional adds less than 400.
|
||||
*/
|
||||
template<typename T>
|
||||
class optional {
|
||||
public:
|
||||
optional():_valid(0){}
|
||||
~optional(){ if( _valid ) (**this).~T(); }
|
||||
|
||||
optional( const optional& o )
|
||||
:_valid(false) {
|
||||
if( o._valid ) new (&**this) T( *o );
|
||||
_valid = o._valid;
|
||||
}
|
||||
|
||||
optional( optional&& o )
|
||||
:_valid(false) {
|
||||
if( o._valid ) new (&**this) T( fc::move(*o) );
|
||||
_valid = o._valid;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
optional( U&& u )
|
||||
:_valid(false) {
|
||||
new (&**this) T( fc::forward<U>(u) );
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
optional& operator=( U&& u ) {
|
||||
if( &u == &**this ) return *this;
|
||||
if( !_valid ) {
|
||||
new (&**this) T( fc::forward<U>(u) );
|
||||
_valid = true;
|
||||
} else {
|
||||
**this = u;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
optional& operator=( const optional& o ) {
|
||||
if( _valid && o.valid ) { **this = *o; }
|
||||
else if( !_valid && o._valid ) {
|
||||
*this = **o;
|
||||
} // else !_valid && !o._valid == same!
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator!()const { return !_valid; }
|
||||
|
||||
T& operator*() { void* v = &_value[0]; return *static_cast<T*>(v); }
|
||||
const T& operator*()const { const void* v = &_value[0]; return *static_cast<const T*>(v); }
|
||||
|
||||
T& operator->() { void* v = &_value[0]; return *static_cast<T*>(v); }
|
||||
const T& operator->()const { const void* v = &_value[0]; return *static_cast<const T*>(v); }
|
||||
|
||||
private:
|
||||
// force alignment... to 8 byte boundaries
|
||||
double _value[(sizeof(T)+sizeof(double)-1)/sizeof(double)];
|
||||
bool _valid;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool operator == ( const optional<T>& left, const optional<T>& right ) {
|
||||
return (!left == !right) || (!!left && *left == *right);
|
||||
}
|
||||
template<typename T, typename U>
|
||||
bool operator == ( const optional<T>& left, const U& u ) {
|
||||
return !!left && *left == u;
|
||||
}
|
||||
template<typename T>
|
||||
bool operator != ( const optional<T>& left, const optional<T>& right ) {
|
||||
return (!left != !right) || (!!left && *left != *right);
|
||||
}
|
||||
template<typename T, typename U>
|
||||
bool operator != ( const optional<T>& left, const U& u ) {
|
||||
return !left || *left != u;
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
|
||||
#endif
|
||||
19
include/fc/priority.hpp
Normal file
19
include/fc/priority.hpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _FC_PRIORITY_HPP_
|
||||
#define _FC_PRIORITY_HPP_
|
||||
|
||||
namespace fc {
|
||||
/**
|
||||
* An integer value used to sort asynchronous tasks. The higher the
|
||||
* prioirty the sooner it will be run.
|
||||
*/
|
||||
class priority {
|
||||
public:
|
||||
explicit priority( int v = 0):value(v){}
|
||||
priority( const priority& p ):value(p.value){}
|
||||
bool operator < ( const priority& p )const {
|
||||
return value < p.value;
|
||||
}
|
||||
int value;
|
||||
};
|
||||
}
|
||||
#endif // _FC_PRIORITY_HPP_
|
||||
197
include/fc/reflect.hpp
Normal file
197
include/fc/reflect.hpp
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
#ifndef _FC_REFLECT_HPP_
|
||||
#define _FC_REFLECT_HPP_
|
||||
#include <stdint.h>
|
||||
#include <fc/abstract_types.hpp>
|
||||
#include <fc/fwd.hpp>
|
||||
#include <fc/reflect_fwd.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
class string;
|
||||
|
||||
class abstract_visitor;
|
||||
class abstract_const_visitor;
|
||||
class abstract_reflector;
|
||||
|
||||
// provides reference semantics
|
||||
class ref {
|
||||
public:
|
||||
template<typename T>
|
||||
ref( T& v );
|
||||
|
||||
ref( const ref& v )
|
||||
:_obj(v._obj),_reflector(v._reflector){}
|
||||
|
||||
ref( void* o, abstract_reflector& r )
|
||||
:_obj(o),_reflector(r){}
|
||||
|
||||
void* _obj;
|
||||
abstract_reflector& _reflector;
|
||||
|
||||
private:
|
||||
ref& operator=(const ref& o);
|
||||
};
|
||||
|
||||
class cref {
|
||||
public:
|
||||
template<typename T>
|
||||
cref( const T& v );
|
||||
|
||||
cref( const cref& v )
|
||||
:_obj(v._obj),_reflector(v._reflector){}
|
||||
|
||||
cref( const ref& v )
|
||||
:_obj(v._obj),_reflector(v._reflector){}
|
||||
|
||||
cref( const void* o, abstract_reflector& r )
|
||||
:_obj(o),_reflector(r){}
|
||||
|
||||
const void* _obj;
|
||||
abstract_reflector& _reflector;
|
||||
|
||||
private:
|
||||
cref& operator=(const cref& o);
|
||||
};
|
||||
|
||||
|
||||
class abstract_reflector : virtual public abstract_value_type {
|
||||
public:
|
||||
virtual ~abstract_reflector(){}
|
||||
virtual const char* name()const = 0;
|
||||
virtual void visit( void* s, const abstract_visitor& v )const = 0;
|
||||
virtual void visit( const void* s, const abstract_const_visitor& v )const = 0;
|
||||
virtual ref get_member(void*, uint64_t) = 0;
|
||||
virtual cref get_member(const void*, uint64_t) = 0;
|
||||
virtual ref get_member(void*, const char*) = 0;
|
||||
virtual cref get_member(const void*, const char*) = 0;
|
||||
virtual size_t member_count(const void*) = 0;
|
||||
|
||||
};
|
||||
|
||||
class abstract_visitor {
|
||||
public:
|
||||
virtual ~abstract_visitor(){}
|
||||
virtual void visit()const=0;
|
||||
virtual void visit( char& c )const=0;
|
||||
virtual void visit( uint8_t& c )const=0;
|
||||
virtual void visit( uint16_t& c )const=0;
|
||||
virtual void visit( uint32_t& c )const=0;
|
||||
virtual void visit( uint64_t& c )const=0;
|
||||
virtual void visit( int8_t& c )const=0;
|
||||
virtual void visit( int16_t& c )const=0;
|
||||
virtual void visit( int32_t& c )const=0;
|
||||
virtual void visit( int64_t& c )const=0;
|
||||
virtual void visit( double& c )const=0;
|
||||
virtual void visit( float& c )const=0;
|
||||
virtual void visit( bool& c )const=0;
|
||||
virtual void visit( fc::string& c )const=0;
|
||||
virtual void visit( const char* member, int idx, int size, const ref& v)const=0;
|
||||
virtual void visit( int idx, int size, const ref& v)const=0;
|
||||
virtual void array_size( int size )const=0;
|
||||
virtual void object_size( int size )const=0;
|
||||
};
|
||||
|
||||
class abstract_const_visitor {
|
||||
public:
|
||||
virtual ~abstract_const_visitor(){}
|
||||
virtual void visit()const=0;
|
||||
virtual void visit( const char& c )const=0;
|
||||
virtual void visit( const uint8_t& c )const=0;
|
||||
virtual void visit( const uint16_t& c )const=0;
|
||||
virtual void visit( const uint32_t& c )const=0;
|
||||
virtual void visit( const uint64_t& c )const=0;
|
||||
virtual void visit( const int8_t& c )const=0;
|
||||
virtual void visit( const int16_t& c )const=0;
|
||||
virtual void visit( const int32_t& c )const=0;
|
||||
virtual void visit( const int64_t& c )const=0;
|
||||
virtual void visit( const double& c )const=0;
|
||||
virtual void visit( const float& c )const=0;
|
||||
virtual void visit( const bool& c )const=0;
|
||||
virtual void visit( const fc::string& c )const=0;
|
||||
virtual void visit( const char* member, int idx, int size, const cref& v)const=0;
|
||||
virtual void visit( int idx, int size, const cref& v)const=0;
|
||||
virtual void array_size( int size )const=0;
|
||||
virtual void object_size( int size )const=0;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template<typename T, typename Derived>
|
||||
class reflector_impl : virtual public value_type<T>, virtual public abstract_reflector {
|
||||
virtual ref get_member(void*, uint64_t) {
|
||||
int x = 0;
|
||||
return x;
|
||||
}
|
||||
virtual cref get_member(const void*, uint64_t) {
|
||||
int x = 0;
|
||||
return x;
|
||||
}
|
||||
// throw if field is not found
|
||||
virtual ref get_member(void*, const char*) {
|
||||
int x = 0;
|
||||
return x;
|
||||
// init static hash map the first time it is called...
|
||||
// lookup field in hash map, return ref
|
||||
//return ref();
|
||||
}
|
||||
// throw if field is not found
|
||||
virtual cref get_member(const void*, const char*) {
|
||||
int x = 0;
|
||||
return x;
|
||||
// init static hash map the first time it is called...
|
||||
// lookup field in hash map, return ref
|
||||
//return cref();
|
||||
}
|
||||
// throw if field is not found
|
||||
virtual size_t member_count(const void*) {
|
||||
// init static hash map the first time it is called...
|
||||
// lookup field in hash map, return ref
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct get_typename {};
|
||||
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<int16_t> { static const char* name() { return "int16_t"; } };
|
||||
template<> struct get_typename<int8_t> { static const char* name() { return "int8_t"; } };
|
||||
template<> struct get_typename<uint32_t> { static const char* name() { return "uint32_t"; } };
|
||||
template<> struct get_typename<uint64_t> { static const char* name() { return "uint64_t"; } };
|
||||
template<> struct get_typename<uint16_t> { static const char* name() { return "uint16_t"; } };
|
||||
template<> struct get_typename<uint8_t> { static const char* name() { return "uint8_t"; } };
|
||||
template<> struct get_typename<double> { static const char* name() { return "double"; } };
|
||||
template<> struct get_typename<float> { static const char* name() { return "float"; } };
|
||||
template<> struct get_typename<bool> { static const char* name() { return "bool"; } };
|
||||
template<> struct get_typename<string> { static const char* name() { return "string"; } };
|
||||
|
||||
template<typename T>
|
||||
class reflector : public detail::reflector_impl<T, reflector<T> >{
|
||||
public:
|
||||
virtual const char* name()const { return get_typename<T>::name(); }
|
||||
virtual void visit( void* s, const abstract_visitor& v )const {
|
||||
v.visit( *((T*)s) );
|
||||
}
|
||||
virtual void visit( const void* s, const abstract_const_visitor& v )const {
|
||||
v.visit( *((const T*)s) );
|
||||
}
|
||||
|
||||
static reflector& instance() { static reflector inst; return inst; }
|
||||
};
|
||||
|
||||
template<typename T> reflector<T>& reflect( const T& ) { return reflector<T>::instance(); }
|
||||
|
||||
template<typename T>
|
||||
ref::ref( T& v ) :_obj(&v),_reflector(reflector<T>::instance()){}
|
||||
|
||||
template<typename T>
|
||||
cref::cref( const T& v ) :_obj(&v),_reflector(reflector<T>::instance()){}
|
||||
|
||||
template<typename T,unsigned int S>
|
||||
class reflector<fwd<T,S>>;
|
||||
|
||||
} // namespace fc
|
||||
|
||||
|
||||
#endif // _REFLECT_HPP_
|
||||
40
include/fc/reflect_cast.hpp
Normal file
40
include/fc/reflect_cast.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef _REFLECT_CAST_HPP_
|
||||
#define _REFLECT_CAST_HPP_
|
||||
#include <fc/reflect.hpp>
|
||||
|
||||
namespace fc {
|
||||
/**
|
||||
* This is specialized for each type to implement a cast
|
||||
* from a reflected value.
|
||||
*
|
||||
* By default the cast will only work for 'exact' matches of
|
||||
* type. Use duck_cast<T> for a more flexible field-by-field
|
||||
* cast.
|
||||
*/
|
||||
template<typename T>
|
||||
class const_cast_visitor : public abstract_const_visitor {
|
||||
public:
|
||||
const_cast_visitor( T& s ):_s(s){}
|
||||
|
||||
virtual void visit()=0;
|
||||
virtual void visit( const char& c )const=0;
|
||||
virtual void visit( const uint8_t& c )const=0;
|
||||
virtual void visit( const uint16_t& c )const=0;
|
||||
virtual void visit( const uint32_t& c )const=0;
|
||||
virtual void visit( const uint64_t& c )const=0;
|
||||
virtual void visit( const int8_t& c )const=0;
|
||||
virtual void visit( const int16_t& c )const=0;
|
||||
virtual void visit( const int32_t& c )const=0;
|
||||
virtual void visit( const int64_t& c )const=0;
|
||||
virtual void visit( const double& c )const=0;
|
||||
virtual void visit( const float& c )const=0;
|
||||
virtual void visit( const bool& c )const=0;
|
||||
virtual void visit( const fc::string& c )const=0;
|
||||
virtual void visit( const char* member, int idx, int size, const cref& v)const=0;
|
||||
virtual void visit( int idx, int size, const cref& v)const=0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace fc
|
||||
#endif // _REFLECT_CAST_HPP_
|
||||
31
include/fc/reflect_fwd.hpp
Normal file
31
include/fc/reflect_fwd.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef _FC_REFLECT_FWD_HPP_
|
||||
#define _FC_REFLECT_FWD_HPP_
|
||||
/**
|
||||
* @file reflect_fwd.hpp
|
||||
* @brief forward declares types defined in reflect.hpp
|
||||
*
|
||||
* You should include this file in your headers to accelerate your
|
||||
* compile times over including reflect.hpp
|
||||
*/
|
||||
|
||||
namespace fc {
|
||||
class abstract_reflector;
|
||||
template<typename T> class reflector;
|
||||
class abstract_visitor;
|
||||
class abstract_const_visitor;
|
||||
class ref;
|
||||
class cref;
|
||||
}
|
||||
|
||||
#define FC_REFLECTABLE( TYPE ) \
|
||||
namespace fc{ \
|
||||
template<> class reflector<TYPE> : virtual public detail::reflector_impl<TYPE, reflector<TYPE> > { \
|
||||
public:\
|
||||
virtual const char* name()const; \
|
||||
virtual void visit( void* s, const abstract_visitor& v )const; \
|
||||
virtual void visit( const void* s, const abstract_const_visitor& v )const; \
|
||||
static reflector& instance(); \
|
||||
};\
|
||||
}
|
||||
|
||||
#endif// _FC_REFLECT_FWD_HPP_
|
||||
32
include/fc/reflect_impl.hpp
Normal file
32
include/fc/reflect_impl.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef _FC_REFLECT_IMPL_HPP_
|
||||
#define _FC_REFLECT_IMPL_HPP_
|
||||
#include <fc/reflect.hpp>
|
||||
#include <boost/preprocessor/seq/for_each_i.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
|
||||
/**
|
||||
* @file reflect_impl.hpp
|
||||
* @brief defines the FC_REFLECT() macro.
|
||||
*
|
||||
* This header uses the boost preprocessor library and
|
||||
*
|
||||
*/
|
||||
|
||||
#define FC_REFLECT_FIELD( r, data, i, elem ) \
|
||||
v.visit( BOOST_PP_STRINGIZE(elem), i, data, e-> elem );
|
||||
|
||||
#define FC_REFLECT( NAME, MEMBERS ) \
|
||||
namespace fc { \
|
||||
const char* reflector<NAME>::name()const { return BOOST_PP_STRINGIZE(NAME); } \
|
||||
void reflector<NAME>::visit( void* s, const abstract_visitor& v )const { \
|
||||
NAME* e = (NAME*)s; \
|
||||
BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_FIELD, BOOST_PP_SEQ_SIZE(MEMBERS), MEMBERS ) \
|
||||
} \
|
||||
void reflector<NAME>::visit( const void* s, const abstract_const_visitor& v )const { \
|
||||
const NAME* e = (const NAME*)s; \
|
||||
BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_FIELD, BOOST_PP_SEQ_SIZE(MEMBERS), MEMBERS ) \
|
||||
} \
|
||||
reflector<NAME>& reflector<NAME>::instance() { static reflector<NAME> inst; return inst; } \
|
||||
}
|
||||
|
||||
#endif // _FC_REFLECT_IMPL_HPP_
|
||||
48
include/fc/reflect_ptr.hpp
Normal file
48
include/fc/reflect_ptr.hpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef _FC_REFLECT_PTR_HPP_
|
||||
#define _FC_REFLECT_PTR_HPP_
|
||||
#include <fc/reflect.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
struct ptr {
|
||||
ptr():_obj(0),_reflector(0){}
|
||||
|
||||
template<typename T>
|
||||
ptr( T* v )
|
||||
:_obj(v),_reflector(&reflect(*v)){}
|
||||
|
||||
ptr( const ptr& v )
|
||||
:_obj(v._obj),_reflector(v._reflector){}
|
||||
|
||||
ref operator*()const { return ref( _obj, *_reflector); }
|
||||
|
||||
private:
|
||||
friend struct cptr;
|
||||
void* _obj;
|
||||
abstract_reflector* _reflector;
|
||||
};
|
||||
|
||||
// provides pointer semantics
|
||||
struct cptr {
|
||||
cptr():_obj(0),_reflector(0){}
|
||||
template<typename T>
|
||||
|
||||
cptr( const T* v )
|
||||
:_obj(v),_reflector(&reflect(*v)){}
|
||||
|
||||
cptr( const cptr& v )
|
||||
:_obj(v._obj),_reflector(v._reflector){}
|
||||
|
||||
cptr( const ptr& v )
|
||||
:_obj(v._obj),_reflector(v._reflector){}
|
||||
|
||||
cref operator*()const { return cref( _obj, *_reflector); }
|
||||
|
||||
private:
|
||||
const void* _obj;
|
||||
abstract_reflector* _reflector;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _FC_REFLECT_PTR_HPP
|
||||
0
include/fc/reflect_ref.hpp
Normal file
0
include/fc/reflect_ref.hpp
Normal file
125
include/fc/reflect_tmp.hpp
Normal file
125
include/fc/reflect_tmp.hpp
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
struct s {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
class visitor {
|
||||
void operator()( const char*, void*, abstract_reflector& r );
|
||||
};
|
||||
|
||||
class abstract_reflector {
|
||||
virtual void visit( void* s, visitor v ) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename S, typename Derived>
|
||||
class reflector_impl : public abstract_reflector {
|
||||
public:
|
||||
virtual void visit( void* s, visitor v ) {
|
||||
visit( *((S*)s), v );
|
||||
}
|
||||
static Derived& instance() {
|
||||
static Derived i;
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class reflector<s> : public reflector_impl< s, reflector<s> > {
|
||||
void visit( s&, visitor v ) {
|
||||
v( "a", &s.a, reflector<decltype(s.a)>::instance() )
|
||||
}
|
||||
const char* name() { return "s"; }
|
||||
}
|
||||
|
||||
class abstract_visitor {
|
||||
// fundamental types called directly
|
||||
virtual void operator()( double& d );
|
||||
virtual void operator()( float& d );
|
||||
virtual void operator()( int& d );
|
||||
|
||||
// objects call this operator for each named member..
|
||||
virtual void operator()( const char* member, int idx, void* d, abstract_reflector& v);
|
||||
|
||||
// called for each item in a collection
|
||||
virtual void operator()( int idx, void* d, abstract_reflector& v);
|
||||
};
|
||||
|
||||
class json_visitor : public visitor{
|
||||
virtual void operator()( double& d ) {
|
||||
|
||||
}
|
||||
virtual void operator()( float& d ) {
|
||||
|
||||
}
|
||||
virtual void operator()( int& d ) {
|
||||
}
|
||||
virtual void operator()( void* d, abstract_reflector& v) {
|
||||
to_json( d, v );
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
string to_json( const void*, abstract_reflector& r ) {
|
||||
r.visit( v, to_json_visitor( v ) );
|
||||
}
|
||||
void from_json( void*, abstract_reflector& r );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
string to_json( const T& v) {
|
||||
return detail::to_json( &v, reflect(v) );
|
||||
}
|
||||
|
||||
struct param {
|
||||
void* arg;
|
||||
reflector* ref;
|
||||
};
|
||||
|
||||
class invoker_impl {
|
||||
};
|
||||
|
||||
class my_interface {
|
||||
my_interface( invoker::ptr inv );
|
||||
|
||||
virtual int some_func( Arg a ) {
|
||||
// this can go in cpp...
|
||||
return inv->invoke( "some_func", a );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
*/
|
||||
class invoker {
|
||||
/**
|
||||
* If variadic templates are supported... use them here.
|
||||
*/
|
||||
template<typename T>
|
||||
future<R> invoke( string name ) {
|
||||
auto p = new promise<R>(...)
|
||||
invoke( p, name, 0 );
|
||||
return p;
|
||||
}
|
||||
|
||||
template<typename T, typename P1>
|
||||
future<R> invoke( const string& name, P1&& p ) {
|
||||
auto p = new promise<R>(...)
|
||||
pair<void*,reflector*> params[1];
|
||||
params[0].first = &p;
|
||||
params[0].second = reflector<P1>::instance() );
|
||||
inv->invoke( p, name, 1, params );
|
||||
return p;
|
||||
}
|
||||
virtual void invoke( promise::ptr p, const string& s, int num_params = 0, param* params = NULL) = 0;
|
||||
|
||||
/// up to max params...
|
||||
};
|
||||
|
||||
class json_rpc_client : public invoker {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
9
include/fc/reflect_value.hpp
Normal file
9
include/fc/reflect_value.hpp
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _FC_REFLECT_VALUE_HPP_
|
||||
#define _FC_REFLECT_VALUE_HPP_
|
||||
#include <fc/reflect.hpp>
|
||||
#include <fc/value.hpp>
|
||||
|
||||
FC_REFLECTABLE( fc::value )
|
||||
FC_REFLECTABLE( fc::value::member )
|
||||
|
||||
#endif // _FC_REFLECT_VALUE_HPP_
|
||||
27
include/fc/reflect_vector.hpp
Normal file
27
include/fc/reflect_vector.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef _FC_REFLECT_VECTOR_HPP_
|
||||
#define _FC_REFLECT_VECTOR_HPP_
|
||||
#include <fc/reflect.hpp>
|
||||
#include <fc/vector.hpp>
|
||||
namespace fc {
|
||||
template<typename T>
|
||||
class reflector<fc::vector<T>> : public detail::reflector_impl<vector<T>, reflector<vector<T>> >{
|
||||
public:
|
||||
virtual const char* name()const {
|
||||
static fc::string s = fc::string("vector<") + reflector<T>::instance().name() + '>';
|
||||
return s.c_str();
|
||||
}
|
||||
virtual void visit( void* s, const abstract_visitor& v )const {
|
||||
vector<T>& vec = *((vector<T>*)s);
|
||||
size_t si = vec.size();
|
||||
for( size_t i = 0; i < si; ++i ) v.visit( i, si, vec.at(i) );
|
||||
}
|
||||
virtual void visit( const void* s, const abstract_const_visitor& v )const {
|
||||
const vector<T>& vec = *((const vector<T>*)s);
|
||||
size_t si = vec.size();
|
||||
v.array_size(si);
|
||||
for( size_t i = 0; i < si; ++i ) v.visit( i, si, vec.at(i) );
|
||||
}
|
||||
static reflector& instance() { static reflector inst; return inst; }
|
||||
};
|
||||
} // namespace fc
|
||||
#endif // _FC_REFLECT_VECTOR_HPP_
|
||||
27
include/fc/server.hpp
Normal file
27
include/fc/server.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
|
||||
class istream {
|
||||
public:
|
||||
template<typename T>
|
||||
istream( T& s ) {
|
||||
|
||||
}
|
||||
|
||||
istream& read( char* buf, uint64_t s );
|
||||
int64_t readsome( char* buf, uint64_t s );
|
||||
bool eof()const;
|
||||
|
||||
private:
|
||||
struct vtable {
|
||||
void* (*read)(void*, char* buf, uint64_t s );
|
||||
int64_t (*readsome)(void*, char* buf, uint64_t s );
|
||||
bool (*eof)(void* )
|
||||
};
|
||||
|
||||
vtable& _vtable;
|
||||
void* _stream;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
75
include/fc/shared_ptr.hpp
Normal file
75
include/fc/shared_ptr.hpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#ifndef _FC_SHARED_PTR_HPP_
|
||||
#define _FC_SHARED_PTR_HPP_
|
||||
#include <fc/utility.hpp>
|
||||
|
||||
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:
|
||||
shared_ptr( T* t, bool inc = false )
|
||||
:_ptr(t) { if( inc ) t->retain(); }
|
||||
|
||||
shared_ptr():_ptr(0){}
|
||||
shared_ptr( const shared_ptr& p ) {
|
||||
_ptr = p._ptr;
|
||||
if( _ptr ) _ptr->retain();
|
||||
}
|
||||
shared_ptr( shared_ptr&& p ) {
|
||||
_ptr = p._ptr;
|
||||
p._ptr = 0;
|
||||
}
|
||||
~shared_ptr() {
|
||||
if( _ptr ) _ptr->release();
|
||||
}
|
||||
shared_ptr& reset( T* v = 0 ) {
|
||||
if( v == _ptr ) return;
|
||||
if( _ptr ) _ptr->release();
|
||||
_ptr = v;
|
||||
if( _ptr ) _ptr->retain();
|
||||
}
|
||||
|
||||
shared_ptr& operator=(const shared_ptr& p ) {
|
||||
shared_ptr tmp(p);
|
||||
fc::swap(tmp,*this);
|
||||
return *this;
|
||||
}
|
||||
shared_ptr& operator=(shared_ptr&& p ) {
|
||||
fc::swap(*this,p);
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
41
include/fc/spin_lock.hpp
Normal file
41
include/fc/spin_lock.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef _FC_SPIN_LOCK_HPP_
|
||||
#define _FC_SPIN_LOCK_HPP_
|
||||
|
||||
namespace boost {
|
||||
template<typename T> class atomic;
|
||||
}
|
||||
|
||||
namespace fc {
|
||||
class microseconds;
|
||||
class time_point;
|
||||
|
||||
/**
|
||||
* @class spin_lock
|
||||
* @brief modified spin-lock that yields on failure, but becomes a 'spin lock'
|
||||
* if there are no other tasks to yield to.
|
||||
*
|
||||
* This kind of lock is lighter weight than a full mutex, but potentially slower
|
||||
* than a staight spin_lock.
|
||||
*
|
||||
* This spin_lock does not block the current thread, but instead attempts to use
|
||||
* an atomic operation to aquire the lock. If unsuccessful, then it yields to
|
||||
* other tasks before trying again. If there are no other tasks then yield is
|
||||
* a no-op and spin_lock becomes a spin-lock.
|
||||
*/
|
||||
class spin_lock {
|
||||
public:
|
||||
spin_lock();
|
||||
bool try_lock();
|
||||
bool try_lock_for( const microseconds& rel_time );
|
||||
bool try_lock_until( const time_point& abs_time );
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
enum lock_store {locked,unlocked};
|
||||
int _lock;
|
||||
};
|
||||
|
||||
} // namespace fc
|
||||
|
||||
#endif // _FC_SPIN_LOCK_HPP_
|
||||
41
include/fc/spin_yield_lock.hpp
Normal file
41
include/fc/spin_yield_lock.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef _FC_SPIN_YIELD_LOCK_HPP_
|
||||
#define _FC_SPIN_YIELD_LOCK_HPP_
|
||||
|
||||
namespace boost {
|
||||
template<typename T> class atomic;
|
||||
}
|
||||
|
||||
namespace fc {
|
||||
class microseconds;
|
||||
class time_point;
|
||||
|
||||
/**
|
||||
* @class spin_yield_lock
|
||||
* @brief modified spin-lock that yields on failure, but becomes a 'spin lock'
|
||||
* if there are no other tasks to yield to.
|
||||
*
|
||||
* This kind of lock is lighter weight than a full mutex, but potentially slower
|
||||
* than a staight spin_lock.
|
||||
*
|
||||
* This spin_yield_lock does not block the current thread, but instead attempts to use
|
||||
* an atomic operation to aquire the lock. If unsuccessful, then it yields to
|
||||
* other tasks before trying again. If there are no other tasks then yield is
|
||||
* a no-op and spin_yield_lock becomes a spin-lock.
|
||||
*/
|
||||
class spin_yield_lock {
|
||||
public:
|
||||
spin_yield_lock();
|
||||
bool try_lock();
|
||||
bool try_lock_for( const microseconds& rel_time );
|
||||
bool try_lock_until( const time_point& abs_time );
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
enum lock_store {locked,unlocked};
|
||||
int _lock;
|
||||
};
|
||||
|
||||
} // namespace fc
|
||||
|
||||
#endif // _FC_SPIN_YIELD_LOCK_HPP_
|
||||
167
include/fc/stream.hpp
Normal file
167
include/fc/stream.hpp
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
#ifndef _FC_STREAM_HPP_
|
||||
#define _FC_STREAM_HPP_
|
||||
#include <fc/utility.hpp>
|
||||
#include <fc/log.hpp>
|
||||
|
||||
namespace fc {
|
||||
class string;
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
struct has_close {
|
||||
typedef char (&no_tag)[1];
|
||||
typedef char (&yes_tag)[2];
|
||||
|
||||
template<typename C, void (C::*)() > struct has_close_helper{};
|
||||
|
||||
template<typename C >
|
||||
static no_tag has_member_helper(...);
|
||||
|
||||
template<typename C>
|
||||
static yes_tag has_member_helper( has_close_helper<C,&C::close>* p);
|
||||
|
||||
enum closed_value { value = sizeof(has_member_helper<T>(0)) == sizeof(yes_tag) };
|
||||
};
|
||||
|
||||
template<typename C, bool HasClose = has_close<C>::value>
|
||||
struct if_close { static void close( C& c ) { c.close(); } };
|
||||
|
||||
template<typename C>
|
||||
struct if_close<C,false> { static void close( C& ) { } };
|
||||
|
||||
|
||||
|
||||
class abstract_istream {
|
||||
public:
|
||||
abstract_istream();
|
||||
virtual ~abstract_istream();
|
||||
size_t readsome( char* buf, size_t len );
|
||||
|
||||
virtual size_t readsome_impl( char* buf, size_t len ) = 0;
|
||||
|
||||
//private:
|
||||
// store a boost::iostreams device that will do
|
||||
// the actual reading/writing for the stream operators
|
||||
//void* _store[51];
|
||||
char _store[51*sizeof(void*)];
|
||||
};
|
||||
|
||||
template<typename IStream>
|
||||
class istream : public abstract_istream {
|
||||
public:
|
||||
istream( IStream& i ):_in(i){}
|
||||
|
||||
virtual size_t readsome_impl( char* buf, size_t len ) {
|
||||
return _in.readsome(buf,len);
|
||||
}
|
||||
|
||||
private:
|
||||
IStream& _in;
|
||||
};
|
||||
|
||||
class abstract_ostream {
|
||||
public:
|
||||
abstract_ostream();
|
||||
virtual ~abstract_ostream();
|
||||
size_t write( const char* buf, size_t len );
|
||||
void close();
|
||||
void flush();
|
||||
|
||||
virtual void close_impl() = 0;
|
||||
virtual void flush_impl() = 0;
|
||||
virtual size_t write_impl( const char* buf, size_t len ) = 0;
|
||||
// private:
|
||||
// store a boost::iostreams device that will do
|
||||
// the actual reading/writing for the stream operators
|
||||
void* _store[50];
|
||||
};
|
||||
|
||||
template<typename OStream>
|
||||
class ostream : public abstract_ostream {
|
||||
public:
|
||||
ostream( OStream& o ):_out(o){}
|
||||
|
||||
virtual size_t write_impl( const char* buf, size_t len ) {
|
||||
_out.write(buf,len);
|
||||
return len;
|
||||
}
|
||||
virtual void close_impl() { if_close<OStream>::close(_out); }
|
||||
virtual void flush_impl() { _out.flush(); }
|
||||
|
||||
private:
|
||||
OStream& _out;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class istream {
|
||||
public:
|
||||
template<typename IStream>
|
||||
istream( IStream& is ) {
|
||||
static_assert( sizeof(detail::istream<IStream>(is)) <= sizeof(_store), "Failed to reserve enough space");
|
||||
new ((void*)&_store[0]) detail::istream<IStream>(is);
|
||||
}
|
||||
~istream();
|
||||
|
||||
size_t readsome( char* buf, size_t len );
|
||||
|
||||
friend istream& operator>>( istream&, int64_t& );
|
||||
friend istream& operator>>( istream&, uint64_t& );
|
||||
friend istream& operator>>( istream&, int32_t& );
|
||||
friend istream& operator>>( istream&, uint32_t& );
|
||||
friend istream& operator>>( istream&, int16_t& );
|
||||
friend istream& operator>>( istream&, uint16_t& );
|
||||
friend istream& operator>>( istream&, int8_t& );
|
||||
friend istream& operator>>( istream&, uint8_t& );
|
||||
friend istream& operator>>( istream&, float& );
|
||||
friend istream& operator>>( istream&, double& );
|
||||
friend istream& operator>>( istream&, bool& );
|
||||
friend istream& operator>>( istream&, char& );
|
||||
friend istream& operator>>( istream&, fc::string& );
|
||||
|
||||
private:
|
||||
istream( const istream& );
|
||||
istream& operator=(const istream& );
|
||||
void* _store[54];
|
||||
};
|
||||
|
||||
class ostream {
|
||||
public:
|
||||
template<typename OStream>
|
||||
ostream( OStream& os ) {
|
||||
static_assert( sizeof(detail::ostream<OStream>(os)) <= sizeof(_store), "Failed to reserve enough space");
|
||||
new ((void*)&_store[0]) detail::ostream<OStream>(os);
|
||||
}
|
||||
|
||||
~ostream();
|
||||
|
||||
size_t write( const char* buf, size_t len );
|
||||
void close();
|
||||
void flush();
|
||||
|
||||
friend ostream& operator<<( ostream&, int64_t );
|
||||
friend ostream& operator<<( ostream&, uint64_t );
|
||||
friend ostream& operator<<( ostream&, int32_t );
|
||||
friend ostream& operator<<( ostream&, uint32_t );
|
||||
friend ostream& operator<<( ostream&, int16_t );
|
||||
friend ostream& operator<<( ostream&, uint16_t );
|
||||
friend ostream& operator<<( ostream&, int8_t );
|
||||
friend ostream& operator<<( ostream&, uint8_t );
|
||||
friend ostream& operator<<( ostream&, float );
|
||||
friend ostream& operator<<( ostream&, double );
|
||||
friend ostream& operator<<( ostream&, bool );
|
||||
friend ostream& operator<<( ostream&, char );
|
||||
friend ostream& operator<<( ostream&, const char* );
|
||||
friend ostream& operator<<( ostream&, const fc::string& );
|
||||
|
||||
private:
|
||||
ostream( const ostream& o );
|
||||
ostream& operator=(const ostream& o);
|
||||
char _store[54*sizeof(void*)];
|
||||
};
|
||||
|
||||
extern ostream cout;
|
||||
extern ostream cerr;
|
||||
extern istream cin;
|
||||
}
|
||||
|
||||
#endif // _FC_STREAM_HPP_
|
||||
62
include/fc/string.hpp
Normal file
62
include/fc/string.hpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#ifndef _FC_STRING_HPP_
|
||||
#define _FC_STRING_HPP_
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fc {
|
||||
/**
|
||||
* Including <string> results in 4000 lines of code
|
||||
* that must be included to build your header. This
|
||||
* class hides all of those details while maintaining
|
||||
* compatability with std::string. Using fc::string
|
||||
* instead of std::string can accelerate compile times
|
||||
* 10x.
|
||||
*/
|
||||
class string {
|
||||
public:
|
||||
typedef char* iterator;
|
||||
typedef const char* const_iterator;
|
||||
|
||||
string();
|
||||
string( const string& c );
|
||||
string( string&& c );
|
||||
string( const char* c );
|
||||
string( const_iterator b, const_iterator e );
|
||||
~string();
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
|
||||
const_iterator begin()const;
|
||||
const_iterator end()const;
|
||||
|
||||
char& operator[](uint64_t idx);
|
||||
const char& operator[](uint64_t idx)const;
|
||||
|
||||
string& operator =( const string& c );
|
||||
string& operator =( string&& c );
|
||||
|
||||
void reserve( uint64_t );
|
||||
uint64_t size()const;
|
||||
|
||||
void resize( uint64_t s );
|
||||
void clear();
|
||||
|
||||
const char* c_str()const;
|
||||
|
||||
bool operator == ( const char* s )const;
|
||||
bool operator == ( const string& s )const;
|
||||
bool operator != ( const string& s )const;
|
||||
|
||||
string& operator+=( const string& s );
|
||||
string& operator+=( char c );
|
||||
|
||||
friend string operator + ( const string&, const string& );
|
||||
friend string operator + ( const string&, char c );
|
||||
|
||||
private:
|
||||
void* my;
|
||||
};
|
||||
|
||||
} // namespace FC
|
||||
|
||||
#endif // _FC_STRING_HPP_
|
||||
86
include/fc/task.hpp
Normal file
86
include/fc/task.hpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#ifndef _FC_TASK_HPP_
|
||||
#define _FC_TASK_HPP_
|
||||
#include <fc/future.hpp>
|
||||
#include <fc/priority.hpp>
|
||||
|
||||
namespace fc {
|
||||
struct context;
|
||||
|
||||
class task_base : virtual public promise_base {
|
||||
public:
|
||||
~task_base();
|
||||
void run();
|
||||
protected:
|
||||
uint64_t _posted_num;
|
||||
priority _prio;
|
||||
time_point _when;
|
||||
void _set_active_context(context*);
|
||||
context* _active_context;
|
||||
task_base* _next;
|
||||
|
||||
task_base(void* func);
|
||||
// opaque internal / private data used by
|
||||
// thread/thread_private
|
||||
friend class thread;
|
||||
friend class thread_d;
|
||||
char _spinlock_store[sizeof(void*)];
|
||||
|
||||
// avoid rtti info for every possible functor...
|
||||
promise_base* _promise_impl;
|
||||
void* _functor;
|
||||
void (*_destroy_functor)(void*);
|
||||
void (*_run_functor)(void*, void* );
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
struct functor_destructor {
|
||||
static void destroy( void* v ) { ((T*)v)->~T(); }
|
||||
};
|
||||
template<typename T>
|
||||
struct functor_run {
|
||||
static void run( void* functor, void* prom ) {
|
||||
((promise<decltype((*((T*)functor))())>*)prom)->set_value( (*((T*)functor))() );
|
||||
}
|
||||
};
|
||||
template<typename T>
|
||||
struct void_functor_run {
|
||||
static void run( void* functor, void* prom ) {
|
||||
(*((T*)functor))();
|
||||
((promise<void>*)prom)->set_value();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename R,uint64_t FunctorSize=64>
|
||||
class task : virtual public task_base, virtual public promise<R> {
|
||||
public:
|
||||
template<typename Functor>
|
||||
task( Functor&& f ):task_base(&_functor[0]) {
|
||||
static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" );
|
||||
new ((char*)&_functor[0]) Functor( fc::forward<Functor>(f) );
|
||||
_destroy_functor = &detail::functor_destructor<Functor>::destroy;
|
||||
|
||||
_promise_impl = static_cast<promise<R>*>(this);
|
||||
_run_functor = &detail::functor_run<Functor>::run;
|
||||
}
|
||||
char _functor[FunctorSize];
|
||||
};
|
||||
template<uint64_t FunctorSize>
|
||||
class task<void,FunctorSize> : virtual public task_base, virtual public promise<void> {
|
||||
public:
|
||||
template<typename Functor>
|
||||
task( Functor&& f ):task_base(&_functor[0]) {
|
||||
static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" );
|
||||
new ((char*)&_functor[0]) Functor( fc::forward<Functor>(f) );
|
||||
_destroy_functor = &detail::functor_destructor<Functor>::destroy;
|
||||
|
||||
_promise_impl = static_cast<promise<void>*>(this);
|
||||
_run_functor = &detail::void_functor_run<Functor>::run;
|
||||
}
|
||||
char _functor[FunctorSize];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _FC_TASK_HPP_
|
||||
159
include/fc/thread.hpp
Normal file
159
include/fc/thread.hpp
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
#ifndef _FC_THREAD_HPP_
|
||||
#define _FC_THREAD_HPP_
|
||||
#include <fc/task.hpp>
|
||||
|
||||
namespace fc {
|
||||
class string;
|
||||
class time_point;
|
||||
class microseconds;
|
||||
|
||||
template<typename T> class vector; // forward declare
|
||||
|
||||
class thread {
|
||||
public:
|
||||
thread( const char* name = "" );
|
||||
thread( thread&& m );
|
||||
thread& operator=(thread&& t );
|
||||
|
||||
/**
|
||||
* Returns the current thread.
|
||||
*/
|
||||
static thread& current();
|
||||
|
||||
|
||||
/**
|
||||
* @brief returns the name given by @ref set_name() for this thread
|
||||
*/
|
||||
const string& name()const;
|
||||
|
||||
/**
|
||||
* @brief associates a name with this thread.
|
||||
*/
|
||||
void set_name( const string& n );
|
||||
|
||||
/**
|
||||
* @brief print debug info about the state of every context / promise.
|
||||
*
|
||||
* This method is helpful to figure out where your program is 'hung' by listing
|
||||
* every async operation (context) and what it is blocked on (future).
|
||||
*
|
||||
* @note debug info is more useful if you provide a description for your
|
||||
* async tasks and promises.
|
||||
*/
|
||||
void debug( const fc::string& d );
|
||||
|
||||
|
||||
/**
|
||||
* Calls function <code>f</code> in this thread and returns a future<T> that can
|
||||
* be used to wait on the result.
|
||||
*
|
||||
* @param f the operation to perform
|
||||
* @param prio the priority relative to other tasks
|
||||
*/
|
||||
template<typename Functor>
|
||||
auto async( Functor&& f, const char* desc ="", priority prio = priority()) -> fc::future<decltype(f())> {
|
||||
typedef decltype(f()) Result;
|
||||
fc::task<Result,sizeof(Functor)>* tsk = new fc::task<Result,sizeof(Functor)>( fc::forward<Functor>(f) );
|
||||
async_task(tsk,prio,desc);
|
||||
return fc::future<Result>(fc::shared_ptr< fc::promise<Result> >(tsk,true) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls function <code>f</code> in this thread and returns a future<T> that can
|
||||
* be used to wait on the result.
|
||||
*
|
||||
* @param f the method to be called
|
||||
* @param prio the priority of this method relative to others
|
||||
* @param when determines when this call will happen, as soon as
|
||||
* possible after <code>when</code>
|
||||
*/
|
||||
template<typename Functor>
|
||||
auto schedule( Functor&& f, const fc::time_point& when,
|
||||
const char* desc = "", priority prio = priority()) -> fc::future<decltype(f())> {
|
||||
typedef decltype(f()) Result;
|
||||
fc::task<Result,sizeof(Functor)>* tsk = new fc::task<Result,sizeof(Functor)>( fc::forward<Functor>(f) );
|
||||
async_task(tsk,prio,when,desc);
|
||||
return fc::future<Result>(fc::shared_ptr< fc::promise<Result> >(tsk,true) );
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will cancel all pending tasks causing them to throw cmt::error::thread_quit.
|
||||
*
|
||||
* If the <i>current</i> thread is not <code>this</code> thread, then the <i>current</i> thread will
|
||||
* wait for <code>this</code> thread to exit.
|
||||
*
|
||||
* This is a blocking wait via <code>boost::thread::join</code>
|
||||
* and other tasks in the <i>current</i> thread will not run while
|
||||
* waiting for <code>this</code> thread to quit.
|
||||
*
|
||||
* @todo make quit non-blocking of the calling thread by eliminating the call to <code>boost::thread::join</code>
|
||||
*/
|
||||
void quit();
|
||||
|
||||
/**
|
||||
* @return true unless quit() has been called.
|
||||
*/
|
||||
bool is_running()const;
|
||||
|
||||
priority current_priority()const;
|
||||
~thread();
|
||||
|
||||
private:
|
||||
thread( class thread_d* );
|
||||
friend class promise_base;
|
||||
friend class thread_d;
|
||||
friend void yield();
|
||||
friend void usleep(const microseconds&);
|
||||
friend void sleep_until(const time_point&);
|
||||
friend void exec();
|
||||
friend int wait_any( fc::vector<promise_base::ptr>&& v, const microseconds& );
|
||||
friend int wait_any_until( fc::vector<promise_base::ptr>&& v, const time_point& tp );
|
||||
void wait_until( promise_base::ptr && v, const time_point& tp );
|
||||
void notify( const promise_base::ptr& v );
|
||||
|
||||
void yield(bool reschedule=true);
|
||||
void sleep_until( const time_point& t );
|
||||
void exec();
|
||||
int wait_any_until( fc::vector<promise_base::ptr>&& v, const time_point& );
|
||||
|
||||
void async_task( task_base* t, const priority& p, const char* desc );
|
||||
void async_task( task_base* t, const priority& p, const time_point& tp, const char* desc );
|
||||
class thread_d* my;
|
||||
};
|
||||
|
||||
/**
|
||||
* Yields to other ready tasks before returning.
|
||||
*/
|
||||
void yield();
|
||||
|
||||
/**
|
||||
* Yields to other ready tasks for u microseconds.
|
||||
*/
|
||||
void usleep( const microseconds& u );
|
||||
|
||||
/**
|
||||
* Yields until the specified time in the future.
|
||||
*/
|
||||
void sleep_until( const time_point& tp );
|
||||
|
||||
/**
|
||||
* Enters the main loop processing tasks until quit() is called.
|
||||
*/
|
||||
void exec();
|
||||
|
||||
/**
|
||||
* Wait until either f1 or f2 is ready.
|
||||
*
|
||||
* @return 0 if f1 is ready, 1 if f2 is ready or throw on error.
|
||||
*/
|
||||
int wait_any( fc::vector<promise_base::ptr>&& v, const microseconds& timeout_us = microseconds::max() );
|
||||
int wait_any_until( fc::vector<promise_base::ptr>&& v, const time_point& tp );
|
||||
|
||||
template<typename Functor>
|
||||
auto async( Functor&& f, const char* desc ="", priority prio = priority()) -> fc::future<decltype(f())> {
|
||||
return fc::thread::current().async( fc::forward<Functor>(f), desc, prio );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
391
include/fc/thread_d.hpp
Normal file
391
include/fc/thread_d.hpp
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
#include <fc/thread.hpp>
|
||||
#include <fc/string.hpp>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include "context.hpp"
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/atomic.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace fc {
|
||||
class thread_d {
|
||||
public:
|
||||
thread_d(fc::thread& s)
|
||||
:self(s), boost_thread(0),
|
||||
task_in_queue(0),
|
||||
done(false),
|
||||
current(0),
|
||||
pt_head(0),
|
||||
ready_head(0),
|
||||
ready_tail(0),
|
||||
blocked(0)
|
||||
{
|
||||
static char cnt = 0;
|
||||
name = fc::string("th_") + char('a'+cnt);
|
||||
cnt++;
|
||||
}
|
||||
fc::thread& self;
|
||||
boost::thread* boost_thread;
|
||||
bc::stack_allocator stack_alloc;
|
||||
boost::mutex task_ready_mutex;
|
||||
boost::condition_variable task_ready;
|
||||
|
||||
boost::atomic<task*> task_in_queue;
|
||||
std::vector<task*> task_pqueue;
|
||||
std::vector<task*> task_sch_queue;
|
||||
std::vector<cmt::context*> sleep_pqueue;
|
||||
std::vector<cmt::context*> free_list;
|
||||
|
||||
bool done;
|
||||
std::string name;
|
||||
cmt::context* current;
|
||||
|
||||
cmt::context* pt_head;
|
||||
|
||||
cmt::context* ready_head;
|
||||
cmt::context* ready_tail;
|
||||
|
||||
cmt::context* blocked;
|
||||
|
||||
time_point check_for_timeouts();
|
||||
|
||||
|
||||
void debug( const std::string& s ) {
|
||||
boost::unique_lock<boost::mutex> lock(detail::log_mutex());
|
||||
|
||||
std::cerr<<"--------------------- "<<s<<" - "<<current;
|
||||
if( current && current->cur_task ) std::cerr<<'('<<current->cur_task->get_desc()<<')';
|
||||
std::cerr<<" ---------------------------\n";
|
||||
std::cerr<<" Ready\n";
|
||||
cmt::context* c = ready_head;
|
||||
while( c ) {
|
||||
std::cerr<<" "<<c;
|
||||
if( c->cur_task ) std::cerr<<'('<<c->cur_task->get_desc()<<')';
|
||||
cmt::context* p = c->caller_context;
|
||||
while( p ) {
|
||||
std::cerr<<" -> "<<p;
|
||||
p = p->caller_context;
|
||||
}
|
||||
std::cerr<<"\n";
|
||||
c = c->next;
|
||||
}
|
||||
std::cerr<<" Blocked\n";
|
||||
c = blocked;
|
||||
while( c ) {
|
||||
std::cerr<<" ctx: "<< c;
|
||||
if( c->cur_task ) std::cerr<<'('<<c->cur_task->get_desc()<<')';
|
||||
std::cerr << " blocked on prom: ";
|
||||
for( uint32_t i = 0; i < c->blocking_prom.size(); ++i ) {
|
||||
std::cerr<<c->blocking_prom[i].prom<<'('<<c->blocking_prom[i].prom->get_desc()<<')';
|
||||
if( i + 1 < c->blocking_prom.size() ) {
|
||||
std::cerr<<",";
|
||||
}
|
||||
}
|
||||
|
||||
cmt::context* p = c->caller_context;
|
||||
while( p ) {
|
||||
std::cerr<<" -> "<<p;
|
||||
p = p->caller_context;
|
||||
}
|
||||
std::cerr<<"\n";
|
||||
c = c->next_blocked;
|
||||
}
|
||||
std::cerr<<"-------------------------------------------------\n";
|
||||
}
|
||||
|
||||
// insert at from of blocked linked list
|
||||
inline void add_to_blocked( cmt::context* c ) {
|
||||
c->next_blocked = blocked;
|
||||
blocked = c;
|
||||
}
|
||||
|
||||
void pt_push_back(cmt::context* c) {
|
||||
c->next = pt_head;
|
||||
pt_head = c;
|
||||
/*
|
||||
cmt::context* n = pt_head;
|
||||
int i = 0;
|
||||
while( n ) {
|
||||
++i;
|
||||
n = n->next;
|
||||
}
|
||||
wlog( "idle context...%2% %1%", c, i );
|
||||
*/
|
||||
}
|
||||
cmt::context::ptr ready_pop_front() {
|
||||
cmt::context::ptr tmp = 0;
|
||||
if( ready_head ) {
|
||||
tmp = ready_head;
|
||||
ready_head = tmp->next;
|
||||
if( !ready_head )
|
||||
ready_tail = 0;
|
||||
tmp->next = 0;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
void ready_push_front( const cmt::context::ptr& c ) {
|
||||
c->next = ready_head;
|
||||
ready_head = c;
|
||||
if( !ready_tail )
|
||||
ready_tail = c;
|
||||
}
|
||||
void ready_push_back( const cmt::context::ptr& c ) {
|
||||
c->next = 0;
|
||||
if( ready_tail ) {
|
||||
ready_tail->next = c;
|
||||
} else {
|
||||
ready_head = c;
|
||||
}
|
||||
ready_tail = c;
|
||||
}
|
||||
struct task_priority_less {
|
||||
bool operator()( const task::ptr& a, const task::ptr& b ) {
|
||||
return a->prio.value < b->prio.value ? true : (a->prio.value > b->prio.value ? false : a->posted_num > b->posted_num );
|
||||
}
|
||||
};
|
||||
struct task_when_less {
|
||||
bool operator()( const task::ptr& a, const task::ptr& b ) {
|
||||
return a->when < b->when;
|
||||
}
|
||||
};
|
||||
|
||||
void enqueue( const task::ptr& t ) {
|
||||
time_point now = system_clock::now();
|
||||
task::ptr cur = t;
|
||||
while( cur ) {
|
||||
if( cur->when > now ) {
|
||||
task_sch_queue.push_back(cur);
|
||||
std::push_heap( task_sch_queue.begin(),
|
||||
task_sch_queue.end(), task_when_less() );
|
||||
} else {
|
||||
task_pqueue.push_back(cur);
|
||||
BOOST_ASSERT( this == thread::current().my );
|
||||
std::push_heap( task_pqueue.begin(),
|
||||
task_pqueue.end(), task_priority_less() );
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
task* dequeue() {
|
||||
// get a new task
|
||||
BOOST_ASSERT( this == thread::current().my );
|
||||
|
||||
task* pending = 0;
|
||||
|
||||
pending = task_in_queue.exchange(0,boost::memory_order_consume);
|
||||
if( pending ) { enqueue( pending ); }
|
||||
|
||||
task::ptr p(0);
|
||||
if( task_sch_queue.size() ) {
|
||||
if( task_sch_queue.front()->when <= system_clock::now() ) {
|
||||
p = task_sch_queue.front();
|
||||
std::pop_heap(task_sch_queue.begin(), task_sch_queue.end(), task_when_less() );
|
||||
task_sch_queue.pop_back();
|
||||
return p;
|
||||
}
|
||||
}
|
||||
if( task_pqueue.size() ) {
|
||||
p = task_pqueue.front();
|
||||
std::pop_heap(task_pqueue.begin(), task_pqueue.end(), task_priority_less() );
|
||||
task_pqueue.pop_back();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be before or after a context switch to
|
||||
* detect quit/cancel operations and throw an exception.
|
||||
*/
|
||||
void check_fiber_exceptions() {
|
||||
if( current && current->canceled ) {
|
||||
BOOST_THROW_EXCEPTION( error::task_canceled() );
|
||||
} else if( done ) {
|
||||
BOOST_THROW_EXCEPTION( error::thread_quit() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next available context and switch to it.
|
||||
* If none are available then create a new context and
|
||||
* have it wait for something to do.
|
||||
*/
|
||||
bool start_next_fiber( bool reschedule = false ) {
|
||||
check_for_timeouts();
|
||||
if( !current ) current = new cmt::context( &fc::thread::current() );
|
||||
|
||||
// check to see if any other contexts are ready
|
||||
if( ready_head ) {
|
||||
cmt::context* next = ready_pop_front();
|
||||
BOOST_ASSERT( next != current );
|
||||
if( reschedule ) ready_push_back(current);
|
||||
|
||||
// jump to next context, saving current context
|
||||
cmt::context* prev = current;
|
||||
current = next;
|
||||
bc::jump_fcontext( &prev->my_context, &next->my_context, 0 );
|
||||
current = prev;
|
||||
BOOST_ASSERT( current );
|
||||
} else { // all contexts are blocked, create a new context
|
||||
// that will process posted tasks...
|
||||
if( reschedule ) ready_push_back(current);
|
||||
|
||||
cmt::context* next;
|
||||
if( pt_head ) {
|
||||
next = pt_head;
|
||||
pt_head = pt_head->next;
|
||||
next->next = 0;
|
||||
} else {
|
||||
next = new cmt::context( &thread_d::start_process_tasks, stack_alloc,
|
||||
&fc::thread::current() );
|
||||
}
|
||||
cmt::context* prev = current;
|
||||
current = next;
|
||||
bc::jump_fcontext( &prev->my_context, &next->my_context, (intptr_t)this );
|
||||
current = prev;
|
||||
BOOST_ASSERT( current );
|
||||
}
|
||||
|
||||
if( current->canceled )
|
||||
BOOST_THROW_EXCEPTION( cmt::error::task_canceled() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void start_process_tasks( intptr_t my ) {
|
||||
thread_d* self = (thread_d*)my;
|
||||
try {
|
||||
self->process_tasks();
|
||||
} catch ( ... ) {
|
||||
std::cerr<<"fiber exited with uncaught exception:\n "<<
|
||||
boost::current_exception_diagnostic_information() <<std::endl;
|
||||
}
|
||||
self->free_list.push_back(self->current);
|
||||
self->start_next_fiber( false );
|
||||
}
|
||||
|
||||
bool run_next_task() {
|
||||
time_point timeout_time = check_for_timeouts();
|
||||
task* next = dequeue();
|
||||
if( next ) {
|
||||
next->set_active_context( current );
|
||||
current->cur_task = next;
|
||||
next->run();
|
||||
current->cur_task = 0;
|
||||
next->set_active_context(0);
|
||||
delete next;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool has_next_task() {
|
||||
if( task_pqueue.size() ||
|
||||
(task_sch_queue.size() && task_sch_queue.front()->when <= system_clock::now()) ||
|
||||
task_in_queue.load( boost::memory_order_relaxed ) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
void clear_free_list() {
|
||||
for( uint32_t i = 0; i < free_list.size(); ++i ) {
|
||||
delete free_list[i];
|
||||
}
|
||||
free_list.clear();
|
||||
}
|
||||
void process_tasks() {
|
||||
while( !done || blocked ) {
|
||||
if( run_next_task() ) continue;
|
||||
|
||||
// if I have something else to do other than
|
||||
// process tasks... do it.
|
||||
if( ready_head ) {
|
||||
pt_push_back( current );
|
||||
start_next_fiber(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
clear_free_list();
|
||||
|
||||
{ // lock scope
|
||||
boost::unique_lock<boost::mutex> lock(task_ready_mutex);
|
||||
if( has_next_task() ) continue;
|
||||
time_point timeout_time = check_for_timeouts();
|
||||
|
||||
if( timeout_time == time_point::max() ) {
|
||||
task_ready.wait( lock );
|
||||
} else if( timeout_time != time_point::min() ) {
|
||||
task_ready.wait_until( lock, timeout_time );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void yield_until( const time_point& tp, bool reschedule ) {
|
||||
check_fiber_exceptions();
|
||||
|
||||
if( tp <= system_clock::now() )
|
||||
return;
|
||||
|
||||
if( !current ) {
|
||||
current = new cmt::context(&cmt::thread::current());
|
||||
}
|
||||
|
||||
current->resume_time = tp;
|
||||
current->clear_blocking_promises();
|
||||
|
||||
sleep_pqueue.push_back(current);
|
||||
std::push_heap( sleep_pqueue.begin(),
|
||||
sleep_pqueue.end(), sleep_priority_less() );
|
||||
|
||||
start_next_fiber(reschedule);
|
||||
|
||||
// clear current context from sleep queue...
|
||||
for( uint32_t i = 0; i < sleep_pqueue.size(); ++i ) {
|
||||
if( sleep_pqueue[i] == current ) {
|
||||
sleep_pqueue[i] = sleep_pqueue.back();
|
||||
sleep_pqueue.pop_back();
|
||||
std::make_heap( sleep_pqueue.begin(),
|
||||
sleep_pqueue.end(), sleep_priority_less() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current->resume_time = time_point::max();
|
||||
check_fiber_exceptions();
|
||||
}
|
||||
|
||||
void wait( const promise_base::ptr& p, const time_point& timeout ) {
|
||||
if( p->ready() ) return;
|
||||
if( timeout < system_clock::now() )
|
||||
BOOST_THROW_EXCEPTION( cmt::error::future_wait_timeout() );
|
||||
|
||||
if( !current ) {
|
||||
current = new cmt::context(&cmt::thread::current());
|
||||
}
|
||||
|
||||
//slog( " %1% blocking on %2%", current, p.get() );
|
||||
current->add_blocking_promise(p.get(),true);
|
||||
|
||||
// if not max timeout, added to sleep pqueue
|
||||
if( timeout != time_point::max() ) {
|
||||
current->resume_time = timeout;
|
||||
sleep_pqueue.push_back(current);
|
||||
std::push_heap( sleep_pqueue.begin(),
|
||||
sleep_pqueue.end(),
|
||||
sleep_priority_less() );
|
||||
}
|
||||
|
||||
// elog( "blocking %1%", current );
|
||||
add_to_blocked( current );
|
||||
// debug("swtiching fibers..." );
|
||||
|
||||
|
||||
start_next_fiber();
|
||||
// slog( "resuming %1%", current );
|
||||
|
||||
//slog( " %1% unblocking blocking on %2%", current, p.get() );
|
||||
current->remove_blocking_promise(p.get());
|
||||
|
||||
check_fiber_exceptions();
|
||||
}
|
||||
};
|
||||
} // namespace fc
|
||||
37
include/fc/time.hpp
Normal file
37
include/fc/time.hpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef _FC_TIME_HPP_
|
||||
#define _FC_TIME_HPP_
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fc {
|
||||
class microseconds {
|
||||
public:
|
||||
explicit microseconds( int64_t c = 0) :_count(c){}
|
||||
static microseconds max() { return microseconds(0x7fffffffffffffffll); }
|
||||
friend microseconds operator + (const microseconds& l, const microseconds& r ) { return microseconds(l._count+r._count); }
|
||||
|
||||
bool operator==(const microseconds& c)const { return _count == c._count; }
|
||||
int64_t count()const { return _count; }
|
||||
private:
|
||||
friend class time_point;
|
||||
int64_t _count;
|
||||
};
|
||||
|
||||
class time_point {
|
||||
public:
|
||||
explicit time_point( microseconds e = microseconds() ) :elapsed(e){}
|
||||
static time_point now();
|
||||
static time_point max() { return time_point( microseconds::max() ); }
|
||||
static time_point min() { return time_point(); }
|
||||
const microseconds& time_since_epoch()const { return elapsed; }
|
||||
bool operator > ( const time_point& t )const { return elapsed._count > t.elapsed._count; }
|
||||
bool operator < ( const time_point& t )const { return elapsed._count < t.elapsed._count; }
|
||||
bool operator <=( const time_point& t )const { return elapsed._count <=t.elapsed._count; }
|
||||
bool operator ==( const time_point& t )const { return elapsed._count ==t.elapsed._count; }
|
||||
bool operator !=( const time_point& t )const { return elapsed._count !=t.elapsed._count; }
|
||||
friend time_point operator + ( const time_point& t, const microseconds& m ) { return time_point(t.elapsed+m); }
|
||||
friend microseconds operator - ( const time_point& t, const time_point& m ) { return microseconds(t.elapsed.count() - m.elapsed.count()); }
|
||||
private:
|
||||
microseconds elapsed;
|
||||
};
|
||||
}
|
||||
#endif // _FC_TIME_HPP_
|
||||
35
include/fc/unique_lock.hpp
Normal file
35
include/fc/unique_lock.hpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef _FC_UNIQUE_LOCK_HPP_
|
||||
#define _FC_UNIQUE_LOCK_HPP_
|
||||
|
||||
namespace fc {
|
||||
|
||||
/**
|
||||
* Including Boost's unique lock drastically increases compile times
|
||||
* for something that is this trivial!
|
||||
*/
|
||||
template<typename T>
|
||||
class unique_lock {
|
||||
public:
|
||||
unique_lock( T& l ):_lock(l) { _lock.lock(); }
|
||||
~unique_lock() { _lock.unlock(); }
|
||||
private:
|
||||
unique_lock( const unique_lock& );
|
||||
unique_lock& operator=( const unique_lock& );
|
||||
T& _lock;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emulate java with the one quirk that the open bracket must come before
|
||||
* the synchronized 'keyword'.
|
||||
*
|
||||
* <code>
|
||||
{ synchronized( lock_type )
|
||||
|
||||
}
|
||||
* </code>
|
||||
*/
|
||||
#define synchronized(X) fc::unique_lock<decltype((X))> __lock(((X)));
|
||||
|
||||
#endif
|
||||
39
include/fc/utility.hpp
Normal file
39
include/fc/utility.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef _FC_UTILITY_HPP_
|
||||
#define _FC_UTILITY_HPP_
|
||||
#include <stdint.h>
|
||||
#include <new>
|
||||
|
||||
typedef decltype(sizeof(int)) size_t;
|
||||
namespace std {
|
||||
typedef decltype(sizeof(int)) size_t;
|
||||
}
|
||||
|
||||
namespace fc {
|
||||
template<typename T> struct remove_reference { typedef T type; };
|
||||
template<typename T> struct remove_reference<T&> { typedef T type; };
|
||||
template<typename T> struct remove_reference<const T&> { typedef const T type; };
|
||||
template<typename T> struct remove_reference<T&&> { typedef T type; };
|
||||
|
||||
template<typename T>
|
||||
typename fc::remove_reference<T>::type&& move( T&& t ) { return static_cast<typename fc::remove_reference<T>::type&&>(t); }
|
||||
|
||||
template<typename T, typename U>
|
||||
inline T&& forward( U&& u ) { return static_cast<T&&>(u); }
|
||||
|
||||
namespace detail {
|
||||
template<typename T> char is_class_helper(void(T::*)());
|
||||
template<typename T> double is_class_helper(...);
|
||||
}
|
||||
template<typename T>
|
||||
struct is_class {
|
||||
enum { value = sizeof(char) == sizeof(detail::is_class_helper<T>(0)) };
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void swap( T& a, T& b ) {
|
||||
T tmp = fc::move(a);
|
||||
a = fc::move(b);
|
||||
b = fc::move(tmp);
|
||||
}
|
||||
}
|
||||
#endif // _FC_UTILITY_HPP_
|
||||
141
include/fc/value.hpp
Normal file
141
include/fc/value.hpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
#ifndef _FC_VALUE_HPP_
|
||||
#define _FC_VALUE_HPP_
|
||||
#include <stdint.h>
|
||||
#include <fc/utility.hpp>
|
||||
#include <fc/reflect_fwd.hpp>
|
||||
#include <fc/vector_fwd.hpp>
|
||||
#include <fc/fwd.hpp>
|
||||
|
||||
namespace fc {
|
||||
class string;
|
||||
|
||||
/**
|
||||
* @brief dynamic type that will store any reflected type.
|
||||
*
|
||||
* A struct can be stored directly or 'exploded' to be stored
|
||||
* as individual elements. Direct storage is more effecient (no
|
||||
* need to allocate/manage keys), but does not support adding / removing
|
||||
* keys.
|
||||
*
|
||||
*/
|
||||
class value {
|
||||
public:
|
||||
struct member {
|
||||
member();
|
||||
member(const char* key);
|
||||
member(string&& key );
|
||||
|
||||
const string& key()const;
|
||||
value& val();
|
||||
const value& val()const;
|
||||
|
||||
private:
|
||||
friend class value;
|
||||
friend class reflector<member>;
|
||||
fwd<string,8> _key;
|
||||
fwd<value,16> _val;
|
||||
};
|
||||
typedef member* iterator;
|
||||
typedef const member* const_iterator;
|
||||
|
||||
value();
|
||||
|
||||
template<typename T>
|
||||
explicit value( T&& t ):_obj(nullptr),_obj_type(nullptr) {
|
||||
*this = cref(fc::forward<T>(t));
|
||||
}
|
||||
|
||||
value( value&& v );
|
||||
value( const value& v );
|
||||
value( const cref& v );
|
||||
~value();
|
||||
|
||||
value& operator=( value&& v );
|
||||
value& operator=( const value& v );
|
||||
value& operator=( const cref& v );
|
||||
|
||||
template<typename T>
|
||||
value& operator=( T&& t ) {
|
||||
value temp(fc::forward<T>(t));
|
||||
swap(temp,*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
value& push_back( T&& v ) { return push_back( value( forward<T>(v) ) ); }
|
||||
value& push_back( value&& v );
|
||||
value& push_back( const value& v );
|
||||
|
||||
/**
|
||||
* These methods will create the key if it
|
||||
* does not exist.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @pre value is null or an object
|
||||
*/
|
||||
value& operator[]( const string& key );
|
||||
/**
|
||||
* @pre value is null or an object
|
||||
*/
|
||||
value& operator[]( const char* key );
|
||||
/**
|
||||
* @pre value is null or an array or index is 0
|
||||
*/
|
||||
value& operator[]( uint64_t index );
|
||||
value& operator[]( int index );
|
||||
/** @} */
|
||||
|
||||
value& operator[]( string&& key );
|
||||
|
||||
const value& operator[]( const string& key )const;
|
||||
const value& operator[]( const char* key )const;
|
||||
const value& operator[]( uint64_t )const;
|
||||
|
||||
bool key_exists( const string& key );
|
||||
bool key_exists( const char* key );
|
||||
bool is_array()const;
|
||||
bool is_object()const;
|
||||
bool is_null()const;
|
||||
bool is_string()const;
|
||||
bool is_real()const;
|
||||
bool is_float()const;
|
||||
bool is_double()const;
|
||||
bool is_integer()const;
|
||||
bool is_int64()const;
|
||||
bool is_int32()const;
|
||||
bool is_int16()const;
|
||||
bool is_int8()const;
|
||||
bool is_boolean()const;
|
||||
|
||||
template<typename T>
|
||||
bool is()const {
|
||||
return _obj_type == reflector<T>::instance();
|
||||
}
|
||||
|
||||
fwd<vector<string>,8> get_keys()const;
|
||||
|
||||
iterator find( const char* key );
|
||||
const_iterator find( const char* key )const;
|
||||
iterator begin();
|
||||
const_iterator begin()const;
|
||||
const_iterator end()const;
|
||||
|
||||
void* ptr();
|
||||
const void* ptr()const;
|
||||
abstract_reflector* type()const;
|
||||
private:
|
||||
template<typename T> friend const T& value_cast( const value& v );
|
||||
template<typename T> friend T& value_cast( value& v );
|
||||
template<typename T> friend T* value_cast( value* v );
|
||||
template<typename T> friend const T* value_cast( const value* v );
|
||||
template<typename T> friend T reinterpret_value_cast( const value& v );
|
||||
|
||||
void* _obj;
|
||||
abstract_reflector* _obj_type;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // _MACE_VALUE_HPP_
|
||||
100
include/fc/value_cast.hpp
Normal file
100
include/fc/value_cast.hpp
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#ifndef _FC_VALUE_CAST_HPP_
|
||||
#define _FC_VALUE_CAST_HPP_
|
||||
#include <fc/value.hpp>
|
||||
#include <fc/reflect.hpp>
|
||||
#include <fc/error.hpp>
|
||||
#include <fc/exception.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
template<typename T>
|
||||
const T& value_cast( const value& v ) {
|
||||
if( &reflector<T>::instance() == v._obj_type ) {
|
||||
if( v._obj_type->size_of() <= 8 ) {
|
||||
slog( "stack..." );
|
||||
return *((const T*)&v._obj);
|
||||
}
|
||||
slog( "heap..." );
|
||||
return *((const T*)v._obj);
|
||||
}
|
||||
FC_THROW( bad_cast() );
|
||||
}
|
||||
template<typename T>
|
||||
T& value_cast( value& v ) {
|
||||
if( &reflector<T>::instance() == v._obj_type ) {
|
||||
if( v._obj_type->size_of() <= 8 ) {
|
||||
slog( "stack..." );
|
||||
return *((T*)&v._obj);
|
||||
}
|
||||
slog( "heap..." );
|
||||
return *((T*)v._obj);
|
||||
}
|
||||
FC_THROW( bad_cast() );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* value_cast( value* v ) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* value_cast( const value* v ) {
|
||||
}
|
||||
|
||||
|
||||
template<typename T> class reinterpret_value_visitor;
|
||||
|
||||
#define CAST_VISITOR_DECL(X) \
|
||||
template<> class reinterpret_value_visitor<X> : public abstract_const_visitor { \
|
||||
private: X& _s; \
|
||||
public: \
|
||||
reinterpret_value_visitor( X& s ):_s(s){} \
|
||||
virtual void visit()const; \
|
||||
virtual void visit( const char& c )const; \
|
||||
virtual void visit( const uint8_t& c )const; \
|
||||
virtual void visit( const uint16_t& c )const; \
|
||||
virtual void visit( const uint32_t& c )const; \
|
||||
virtual void visit( const uint64_t& c )const; \
|
||||
virtual void visit( const int8_t& c )const; \
|
||||
virtual void visit( const int16_t& c )const; \
|
||||
virtual void visit( const int32_t& c )const; \
|
||||
virtual void visit( const int64_t& c )const; \
|
||||
virtual void visit( const double& c )const; \
|
||||
virtual void visit( const float& c )const; \
|
||||
virtual void visit( const bool& c )const; \
|
||||
virtual void visit( const string& c )const; \
|
||||
virtual void visit( const char* member, int idx, int size, const cref& v)const;\
|
||||
virtual void visit( int idx, int size, const cref& v)const; \
|
||||
virtual void array_size( int size )const{} \
|
||||
virtual void object_size( int size )const{} \
|
||||
}
|
||||
|
||||
CAST_VISITOR_DECL(int64_t);
|
||||
CAST_VISITOR_DECL(int32_t);
|
||||
CAST_VISITOR_DECL(int16_t);
|
||||
CAST_VISITOR_DECL(int8_t);
|
||||
CAST_VISITOR_DECL(uint64_t);
|
||||
CAST_VISITOR_DECL(uint32_t);
|
||||
CAST_VISITOR_DECL(uint16_t);
|
||||
CAST_VISITOR_DECL(uint8_t);
|
||||
CAST_VISITOR_DECL(double);
|
||||
CAST_VISITOR_DECL(float);
|
||||
CAST_VISITOR_DECL(bool);
|
||||
CAST_VISITOR_DECL(string);
|
||||
|
||||
|
||||
template<typename T>
|
||||
T reinterpret_value_cast( const value& v ) {
|
||||
if( v.is_null() ) FC_THROW( bad_cast() );
|
||||
T r;
|
||||
reinterpret_value_visitor<T> vis(r);
|
||||
if( v._obj_type->size_of() > sizeof(v._obj) )
|
||||
v._obj_type->visit( v._obj, vis );
|
||||
else
|
||||
v._obj_type->visit( &v._obj, vis );
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // _FC_VALUE_CAST_HPP_
|
||||
10
include/fc/value_fwd.hpp
Normal file
10
include/fc/value_fwd.hpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef _FC_VALUE_FWD_HPP_
|
||||
#define _FC_VALUE_FWD_HPP_
|
||||
#include <fc/fwd.hpp>
|
||||
|
||||
namespace fc {
|
||||
class value;
|
||||
typedef fwd<value,16> value_fwd;
|
||||
}
|
||||
|
||||
#endif // _MACE_VALUE_FWD_HPP_
|
||||
348
include/fc/vector.hpp
Normal file
348
include/fc/vector.hpp
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
#ifndef _FC_VECTOR_HPP_
|
||||
#define _FC_VECTOR_HPP_
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fc/utility.hpp>
|
||||
#include <fc/log.hpp>
|
||||
|
||||
namespace fc {
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
struct data {
|
||||
uint64_t size;
|
||||
uint64_t capacity;
|
||||
T first;
|
||||
|
||||
static data* allocate( uint64_t cap ) {
|
||||
data* d = nullptr;
|
||||
if( cap ){
|
||||
d = (data*)malloc(sizeof(data) + sizeof(T)*(cap-1));
|
||||
d->capacity = cap;
|
||||
} else {
|
||||
d = (data*)malloc(sizeof(data));
|
||||
d->capacity = 1;
|
||||
}
|
||||
d->size = 0;
|
||||
return d;
|
||||
}
|
||||
static data* reallocate( data* d, uint64_t cap ) {
|
||||
if( cap ){
|
||||
d = (data*)realloc(d,sizeof(data) + sizeof(T)*(cap-1));
|
||||
d->capacity = cap;
|
||||
} else {
|
||||
d = (data*)realloc(d,sizeof(data));
|
||||
d->capacity = 1;
|
||||
}
|
||||
if( d->size > d->capacity )
|
||||
d->size = d->capacity;
|
||||
return d;
|
||||
}
|
||||
private:
|
||||
data(){};
|
||||
};
|
||||
|
||||
template<typename T, bool IsClass=false>
|
||||
struct vector_impl {
|
||||
public:
|
||||
vector_impl():_data(nullptr){}
|
||||
vector_impl( vector_impl&& c):_data(c._data){c._data =nullptr; }
|
||||
vector_impl( const vector_impl& c):_data(nullptr) {
|
||||
if( c.size() ) {
|
||||
_data = data<T>::allocate( c.size() );
|
||||
memcpy(begin(),c.begin(),c.size() );
|
||||
}
|
||||
}
|
||||
vector_impl(uint64_t s):_data(nullptr){
|
||||
resize(s);
|
||||
}
|
||||
~vector_impl() {
|
||||
clear();
|
||||
}
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
|
||||
|
||||
uint64_t size()const { return _data ? _data->size : 0; }
|
||||
uint64_t capacity()const { return _data ? _data->capacity : 0; }
|
||||
|
||||
T& back() { return (&_data->first)[-1+_data->size]; }
|
||||
const T& back()const { return (&_data->first)[-1+_data->size]; }
|
||||
T& front() { return (&_data->first)[0]; }
|
||||
const T& front()const { return (&_data->first)[0]; }
|
||||
|
||||
iterator begin() { return _data ? &front() : 0;}
|
||||
const_iterator begin()const { return _data ? &front() : 0;}
|
||||
const_iterator end()const { return _data ? (&back())+1: 0;}
|
||||
|
||||
T& operator[]( uint64_t i ) { return (&_data->first)[i]; }
|
||||
const T& operator[]( uint64_t i )const { return (&_data->first)[i]; }
|
||||
|
||||
T& at( uint64_t i ) { return (&_data->first)[i]; }
|
||||
const T& at( uint64_t i )const { return (&_data->first)[i]; }
|
||||
|
||||
void pop_back() { erase( &back() ); }
|
||||
|
||||
void clear() {
|
||||
if( _data != nullptr )
|
||||
free(_data);
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
void reserve( uint64_t i ) {
|
||||
_data = data<T>::reallocate( _data, i );
|
||||
}
|
||||
|
||||
void resize( uint64_t i ) {
|
||||
if( capacity() < i )
|
||||
_data = data<T>::reallocate( _data, i );
|
||||
_data->size = i;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void push_back( U&& v ) {
|
||||
resize( size()+1 );
|
||||
back() = fc::forward<U>(v);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
iterator insert( const_iterator loc, U&& t ) {
|
||||
uint64_t pos = loc - begin();
|
||||
resize( size()+1 );
|
||||
char* src = &at(pos);
|
||||
if( src != &back() )
|
||||
memmove( src+1, src, (&back() - src) );
|
||||
&back = fc::forward<U>(t);
|
||||
return &at(pos);
|
||||
}
|
||||
|
||||
iterator insert( iterator pos, const_iterator first, const_iterator last ) {
|
||||
if( first >= last ) return pos;
|
||||
|
||||
uint64_t loc = pos - begin();
|
||||
uint64_t right_size = size() - loc;
|
||||
resize( size() + (last-first) );
|
||||
char* src = &at(loc);
|
||||
uint64_t s = last-first;
|
||||
memmove( src + s, src, right_size );
|
||||
memcpy( src, first, s );
|
||||
_data->size += (last-first);
|
||||
return src;
|
||||
}
|
||||
|
||||
iterator erase( iterator pos ) {
|
||||
memmove( pos, pos+1, (&back() - pos) );
|
||||
_data->size--;
|
||||
return pos;
|
||||
}
|
||||
|
||||
iterator erase( iterator first, iterator last ) {
|
||||
if( first != last ) {
|
||||
memmove( first, first + (last-first), (&back() - last) );
|
||||
_data->size -= last-first;
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
vector_impl& operator=( vector_impl&& v ) {
|
||||
fc::swap(_data,v._data);
|
||||
return *this;
|
||||
}
|
||||
vector_impl& operator=( const vector_impl& v ) {
|
||||
vector_impl tmp(v);
|
||||
fc::swap(tmp._data,_data);
|
||||
return *this;
|
||||
}
|
||||
protected:
|
||||
data<T>* _data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class vector_impl<T,true> {
|
||||
public:
|
||||
vector_impl():_data(nullptr){}
|
||||
vector_impl( vector_impl&& c):_data(c._data){c._data =nullptr; }
|
||||
vector_impl( const vector_impl& c):_data(nullptr) {
|
||||
if( c.size() ) {
|
||||
_data = data<T>::allocate( c.size() );
|
||||
auto i = begin();
|
||||
auto ci = c.begin();
|
||||
auto ce = c.end();
|
||||
while( ci != ce ) {
|
||||
new (i) T(*ci);
|
||||
++i;
|
||||
++_data->size;
|
||||
++ci;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector_impl(uint64_t s):_data(nullptr){
|
||||
resize(s);
|
||||
}
|
||||
~vector_impl() {
|
||||
clear();
|
||||
}
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
|
||||
|
||||
uint64_t size()const { return _data ? _data->size : 0; }
|
||||
uint64_t capacity()const { return _data ? _data->capacity : 0; }
|
||||
|
||||
T& back() { return (&_data->first)[-1+_data->size]; }
|
||||
const T& back()const { return (&_data->first)[-1+_data->size]; }
|
||||
T& front() { return (&_data->first)[0]; }
|
||||
const T& front()const { return (&_data->first)[0]; }
|
||||
|
||||
iterator begin() { return _data ? &front() : 0;}
|
||||
const_iterator begin()const { return _data ? &front() : 0;}
|
||||
const_iterator end()const { return _data ? (&back())+1: 0;}
|
||||
|
||||
T& operator[]( uint64_t i ) { return (&_data->first)[i]; }
|
||||
const T& operator[]( uint64_t i )const { return (&_data->first)[i]; }
|
||||
|
||||
T& at( uint64_t i ) { return (&_data->first)[i]; }
|
||||
const T& at( uint64_t i )const { return (&_data->first)[i]; }
|
||||
|
||||
void pop_back() { erase( &back() ); }
|
||||
|
||||
|
||||
void clear() {
|
||||
if( this->_data != nullptr ) {
|
||||
auto c = this->begin();
|
||||
auto e = this->end();
|
||||
while( c != e ) {
|
||||
(*c).~T();
|
||||
++c;
|
||||
}
|
||||
free(this->_data);
|
||||
}
|
||||
this->_data = nullptr;
|
||||
}
|
||||
|
||||
void reserve( uint64_t i ) {
|
||||
if( nullptr != this->_data && i <= this->_data->capacity )
|
||||
return;
|
||||
|
||||
auto _ndata = data<T>::allocate( i );
|
||||
auto nc = &_ndata->first;
|
||||
auto c = this->begin();
|
||||
auto e = this->end();
|
||||
while( c != e ) {
|
||||
new (nc) T(fc::move( *c ));
|
||||
(*c).~T();
|
||||
++_ndata->size;
|
||||
++c;
|
||||
++nc;
|
||||
}
|
||||
fc::swap( _ndata, this->_data );
|
||||
free(_ndata);
|
||||
}
|
||||
|
||||
void resize( uint64_t i ) {
|
||||
this->reserve(i);
|
||||
while( i < this->_data->size ) {
|
||||
this->back().~T();
|
||||
--this->_data->size;
|
||||
}
|
||||
while( this->_data->size < i ) {
|
||||
new (&this->back()+1) T();
|
||||
++this->_data->size;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void push_back( U&& v ) {
|
||||
this->reserve( this->size()+1 );
|
||||
new (&back()+1) T(fc::forward<U>(v));
|
||||
++this->_data->size;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
iterator insert( const_iterator loc, U&& t ) {
|
||||
uint64_t pos = loc - this->begin();
|
||||
this->reserve( this->size()+1 );
|
||||
loc = this->begin() + pos;
|
||||
if( this->size() != 0 ) {
|
||||
new (this->end()) T( fc::move(this->back()) );
|
||||
auto cur = this->back();
|
||||
++this->_data->size;
|
||||
while( cur != loc ) {
|
||||
*cur = fc::move( *(cur-1) );
|
||||
}
|
||||
*cur = fc::forward<U>(t);
|
||||
} else {
|
||||
new (this->end()) T( fc::forward<U>(t) );
|
||||
++this->_data->size;
|
||||
}
|
||||
return &this->at(pos);
|
||||
}
|
||||
|
||||
iterator insert( iterator pos, const_iterator first, const_iterator last ) {
|
||||
//static_assert( false, "Not Implemented" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
iterator erase( iterator pos ) {
|
||||
if( pos == this->end() ) { return pos; }
|
||||
auto next = pos + 1;
|
||||
while( next != this->end() ) {
|
||||
*pos = fc::move(*next);
|
||||
++pos; ++next;
|
||||
}
|
||||
pos->~T();
|
||||
this->_data->size--;
|
||||
return pos;
|
||||
}
|
||||
|
||||
iterator erase( iterator first, iterator last ) {
|
||||
iterator c = first;
|
||||
iterator m = last;
|
||||
iterator e = this->end();
|
||||
while( c != e ) {
|
||||
if( m != e ) *c = fc::move( *m );
|
||||
else c->~T();
|
||||
++c;
|
||||
++m;
|
||||
}
|
||||
this->_data->size -= last-first;
|
||||
return last;
|
||||
}
|
||||
vector_impl& operator=( vector_impl&& v ) {
|
||||
fc::swap(_data,v._data);
|
||||
return *this;
|
||||
}
|
||||
vector_impl& operator=( const vector_impl& v ) {
|
||||
vector_impl tmp(v);
|
||||
fc::swap(tmp._data,_data);
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
data<T>* _data;
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class vector : public detail::vector_impl<T, fc::is_class<T>::value> {
|
||||
public:
|
||||
vector(){}
|
||||
vector( uint64_t s ):detail::vector_impl<T, fc::is_class<T>::value>(s){}
|
||||
vector( const vector& v ):detail::vector_impl<T, fc::is_class<T>::value>(v){}
|
||||
vector( vector&& v ):detail::vector_impl<T, fc::is_class<T>::value>(fc::move(v)){}
|
||||
|
||||
vector& operator=( vector&& v ) {
|
||||
*((base*)this) = fc::move(v);
|
||||
return *this;
|
||||
}
|
||||
vector& operator=( const vector& v ) {
|
||||
*((base*)this) = v;
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
typedef detail::vector_impl<T, fc::is_class<T>::value> base;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif // _FC_VECTOR_HPP_
|
||||
8
include/fc/vector_fwd.hpp
Normal file
8
include/fc/vector_fwd.hpp
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _FC_VECTOR_FWD_HPP_
|
||||
#define _FC_VECTOR_FWD_HPP_
|
||||
namespace fc {
|
||||
template<typename T> class vector;
|
||||
template<typename T> class reflector;
|
||||
template<typename T> class reflector< fc::vector<T> >;
|
||||
};
|
||||
#endif // _FC_VECTOR_FWD_HPP_
|
||||
140
include/fc/vector_g.hpp
Normal file
140
include/fc/vector_g.hpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
#ifndef _FC_VECTOR_HPP_
|
||||
#define _FC_VECTOR_HPP_
|
||||
#include <fc/abstract_types.hpp>
|
||||
|
||||
namespace fc {
|
||||
class vector_impl {
|
||||
public:
|
||||
size_t size()const;
|
||||
size_t capacity()const;
|
||||
void pop_back();
|
||||
void clear();
|
||||
void resize( size_t );
|
||||
void reserve( size_t );
|
||||
|
||||
protected:
|
||||
vector_impl( abstract_value_type& v, size_t size );
|
||||
vector_impl( const vector_impl& );
|
||||
vector_impl( vector_impl&& );
|
||||
~vector_impl();
|
||||
|
||||
vector_impl& operator=( const vector_impl& v );
|
||||
vector_impl& operator=( vector_impl&& v );
|
||||
|
||||
void _push_back( const void* v );
|
||||
void _push_back_m( void* v );
|
||||
|
||||
void* _back();
|
||||
const void* _back()const;
|
||||
|
||||
void* _at(size_t);
|
||||
const void* _at(size_t)const;
|
||||
|
||||
void* _insert( void* pos, const void* t );
|
||||
void* _insert( void* pos, void* t );
|
||||
void* _erase( void* pos );
|
||||
void* _erase( void* first, void* last );
|
||||
|
||||
struct vector_impl_d* my;
|
||||
};
|
||||
|
||||
class vector_pod_impl {
|
||||
public:
|
||||
size_t size()const;
|
||||
size_t capacity()const;
|
||||
void pop_back();
|
||||
void clear();
|
||||
void resize( size_t );
|
||||
void reserve( size_t );
|
||||
|
||||
protected:
|
||||
vector_pod_impl( unsigned int size_of, size_t size );
|
||||
vector_pod_impl( const vector_pod_impl& );
|
||||
vector_pod_impl( vector_pod_impl&& );
|
||||
~vector_pod_impl();
|
||||
|
||||
vector_pod_impl& operator=( const vector_pod_impl& v );
|
||||
vector_pod_impl& operator=( vector_pod_impl&& v );
|
||||
|
||||
void _push_back( const void* v );
|
||||
void _push_back_m( void* v );
|
||||
|
||||
void* _back();
|
||||
const void* _back()const;
|
||||
|
||||
void* _at(size_t);
|
||||
const void* _at(size_t)const;
|
||||
|
||||
void* _insert( void* pos, const void* t );
|
||||
void* _erase( void* pos );
|
||||
void* _erase( void* first, void* last );
|
||||
|
||||
struct vector_pod_impl_d* my;
|
||||
};
|
||||
|
||||
template<typename T, bool is_class = true >
|
||||
class vector_base : public vector_impl {
|
||||
public:
|
||||
vector_base( size_t s ):vector_impl( value_type<T>::instance(), s ){};
|
||||
vector_base( const vector_base& c ):vector_impl( c ){};
|
||||
vector_base( vector_base&& c ):vector_impl( fc::move(c) ){};
|
||||
|
||||
vector_base& operator=( const vector_base& v ){ vector_impl::operator=(v); return *this; }
|
||||
vector_base& operator=( vector_base&& v ) { vector_impl::operator=(fc::move(v)); return *this; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class vector_base<T,false> : public vector_pod_impl {
|
||||
public:
|
||||
vector_base( size_t s ):vector_pod_impl( sizeof(T), s ){};
|
||||
vector_base( const vector_base& c ):vector_pod_impl( c ){};
|
||||
vector_base( vector_base&& c ):vector_pod_impl( fc::move(c) ){};
|
||||
|
||||
vector_base& operator=( const vector_base& v ){ vector_pod_impl::operator=(v); return *this; }
|
||||
vector_base& operator=( vector_base&& v ) { vector_pod_impl::operator=(fc::move(v)); return *this; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class vector : public vector_base<T, fc::is_class<T>::value > {
|
||||
public:
|
||||
vector( size_t size = 0 ):vector_base<T,fc::is_class<T>::value>( size ){}
|
||||
vector( const vector& v ):vector_base<T,fc::is_class<T>::value>(v){}
|
||||
vector( vector&& v ):vector_base<T,fc::is_class<T>::value>(fc::move(v)){}
|
||||
|
||||
vector& operator=( const vector& v ){ vector_base<T,fc::is_class<T>::value>::operator=(v); return *this; }
|
||||
vector& operator=( vector&& v ) { vector_base<T,fc::is_class<T>::value>::operator=(fc::move(v)); return *this; }
|
||||
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
|
||||
T* begin() { return &front(); }
|
||||
const T* begin()const { return &front(); }
|
||||
const T* end()const { return &back() + 1; }
|
||||
|
||||
void push_back( const T& t ) { _push_back(&t); }
|
||||
void push_back( T&& t ) { _push_back_m(&t); }
|
||||
|
||||
T& back() { return *((T*)this->_back()); }
|
||||
const T& back()const { return *((const T*)this->_back()); }
|
||||
|
||||
T& front() { return *((T*)this->_at(0)); }
|
||||
const T& front()const { return *((const T*)this->_at(0)); }
|
||||
|
||||
T& operator[]( size_t p ) { return *((T*)this->_at(p)); }
|
||||
const T& operator[]( size_t p )const { return *((const T*)this->_at(p)); }
|
||||
|
||||
T& at( size_t p ) { return *((T*)this->_at(p)); }
|
||||
const T& at( size_t p )const { return *((const T*)this->_at(p)); }
|
||||
|
||||
iterator insert( iterator pos, const T& t ) { return (iterator*)this->_insert( pos, &t ); }
|
||||
iterator insert( iterator pos, T&& t ) { return (iterator*)this->_insert_m(pos, &t); }
|
||||
iterator erase( iterator pos ) { return (iterator*)this->_erase(pos); }
|
||||
iterator erase( iterator first, iterator last ) { return (iterator*)this->_erase(first,last); }
|
||||
};
|
||||
namespace reflect {
|
||||
template<typename T> class reflector;
|
||||
template<typename T> class reflector<vector<T>>;
|
||||
}
|
||||
} // namespace fc
|
||||
|
||||
#endif // _FC_VECTOR_HPP_
|
||||
15
include/fc/wait_any.hpp
Normal file
15
include/fc/wait_any.hpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef _FC_WAIT_ANY_HPP_
|
||||
#define _FC_WAIT_ANY_HPP_
|
||||
#include <fc/vector.hpp>
|
||||
#include <fc/thread.hpp>
|
||||
|
||||
namespace fc {
|
||||
template<typename T1, typename T2>
|
||||
int wait_any( fc::future<T1>& f1, fc::future<T2>& f2, const microseconds& timeout_us = microseconds::max() ) {
|
||||
fc::vector<promise_base::ptr> p(2);
|
||||
p[0] = static_pointer_cast<promise_base*>(f1.promise());
|
||||
p[1] = static_pointer_cast<promise_base*>(f2.promise());
|
||||
return wait( fc::move(p), timeout_us );
|
||||
}
|
||||
}
|
||||
#endif // _FC_WAIT_ANY_HPP_
|
||||
174
src/bkup_json.cpp
Normal file
174
src/bkup_json.cpp
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
#include <fc/json.hpp>
|
||||
#include <fc/reflect.hpp>
|
||||
#include <fc/stream.hpp>
|
||||
|
||||
// TODO: replace sstream with light/fast compiling version
|
||||
#include <sstream>
|
||||
|
||||
namespace fc { namespace json {
|
||||
|
||||
class const_visitor : public fc::abstract_const_visitor {
|
||||
public:
|
||||
fc::ostream& out;
|
||||
const_visitor( fc::ostream& o ):out(o){}
|
||||
|
||||
virtual void visit()const{}
|
||||
virtual void visit( const char& c )const{ out << '"' << c << '"'; }
|
||||
virtual void visit( const uint8_t& c )const{ out << int(c); }
|
||||
virtual void visit( const uint16_t& c )const{ out << c; }
|
||||
virtual void visit( const uint32_t& c )const{ out << c; }
|
||||
virtual void visit( const uint64_t& c )const{ out << c; }
|
||||
virtual void visit( const int8_t& c )const{ out << int(c); }
|
||||
virtual void visit( const int16_t& c )const{ out << c;}
|
||||
virtual void visit( const int32_t& c )const{ out << c;}
|
||||
virtual void visit( const int64_t& c )const{ out << c;}
|
||||
virtual void visit( const double& c )const{ out << c;}
|
||||
virtual void visit( const float& c )const{ out << c;}
|
||||
virtual void visit( const bool& c )const{ out << (c?"true":"false"); }
|
||||
virtual void visit( const fc::string& c )const{ out << '"'<<c.c_str()<<'"'; }
|
||||
virtual void visit( const char* member, int idx, int size, const cref& v)const{
|
||||
if( !idx ) out <<"{";
|
||||
out<<'"'<<member<<"\":";
|
||||
v._reflector.visit( v._obj, *this );
|
||||
if( idx != size-1 ) {
|
||||
out <<',';
|
||||
} else {
|
||||
out << '}';
|
||||
}
|
||||
}
|
||||
virtual void visit( int idx, int size, const cref& v)const{
|
||||
if( !idx ) out << '[';
|
||||
v._reflector.visit( v._obj, *this );
|
||||
out << ((idx < (size -1) ) ? ',' : ']');
|
||||
}
|
||||
};
|
||||
|
||||
class visitor : public fc::abstract_visitor {
|
||||
public:
|
||||
virtual void visit(){}
|
||||
virtual void visit( char& c )const{}
|
||||
virtual void visit( uint8_t& c )const{}
|
||||
virtual void visit( uint16_t& c )const{}
|
||||
virtual void visit( uint32_t& c )const{}
|
||||
virtual void visit( uint64_t& c )const{}
|
||||
virtual void visit( int8_t& c )const{}
|
||||
virtual void visit( int16_t& c )const{}
|
||||
virtual void visit( int32_t& c )const{}
|
||||
virtual void visit( int64_t& c )const{}
|
||||
virtual void visit( double& c )const{}
|
||||
virtual void visit( float& c )const{}
|
||||
virtual void visit( bool& c )const{}
|
||||
virtual void visit( fc::string& c )const{}
|
||||
virtual void visit( const char* member, int idx, int size, const ref& v)const{}
|
||||
virtual void visit( int idx, int size, const ref& v)const{}
|
||||
};
|
||||
|
||||
string to_string( const cref& o ) {
|
||||
std::stringstream ss;
|
||||
{
|
||||
fc::ostream os(ss);
|
||||
o._reflector.visit( o._obj, fc::json::const_visitor(os) );
|
||||
}
|
||||
return ss.str().c_str();
|
||||
}
|
||||
void from_string( const string& s, const ref& o ) {
|
||||
|
||||
}
|
||||
|
||||
void write( ostream& out, const cref& val ) {
|
||||
val._reflector.visit( val._obj, fc::json::const_visitor(out) );
|
||||
}
|
||||
|
||||
uint8_t from_hex( char c ) {
|
||||
if( c >= '0' && c <= '9' )
|
||||
return c - '0';
|
||||
if( c >= 'a' && c <= 'f' )
|
||||
return c - 'a' + 10;
|
||||
if( c >= 'A' && c <= 'F' )
|
||||
return c - 'A' + 10;
|
||||
return c;
|
||||
}
|
||||
|
||||
string escape_string( const string& s ) {
|
||||
// calculate escape string size.
|
||||
uint32_t ecount = 0;
|
||||
for( auto i = s.begin(); i != s.end(); ++i ) {
|
||||
if( ' '<= *i && *i <= '~' && *i !='\\' && *i != '"' ) {
|
||||
ecount+=1;
|
||||
} else {
|
||||
switch( *i ) {
|
||||
case '\t' :
|
||||
case '\n' :
|
||||
case '\r' :
|
||||
case '\\' :
|
||||
case '"' :
|
||||
ecount += 2; break;
|
||||
default:
|
||||
ecount += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
// unless the size changed, just return it.
|
||||
if( ecount == s.size() ) { return s; }
|
||||
|
||||
// reserve the bytes
|
||||
string out; out.reserve(ecount);
|
||||
|
||||
// print it out.
|
||||
for( auto i = s.begin(); i != s.end(); ++i ) {
|
||||
if( ' '<= *i && *i <= '~' && *i !='\\' && *i != '"' ) {
|
||||
out += *i;
|
||||
} else {
|
||||
out += '\\';
|
||||
switch( *i ) {
|
||||
case '\t' : out += 't'; break;
|
||||
case '\n' : out += 'n'; break;
|
||||
case '\r' : out += 'r'; break;
|
||||
case '\\' : out += '\\'; break;
|
||||
case '"' : out += '"'; break;
|
||||
default:
|
||||
out += "x";
|
||||
const char* const hexdig = "0123456789abcdef";
|
||||
out += hexdig[*i >> 4];
|
||||
out += hexdig[*i & 0xF];
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
string unescape_string( const string& s ) {
|
||||
string out; out.reserve(s.size());
|
||||
for( auto i = s.begin(); i != s.end(); ++i ) {
|
||||
if( *i != '\\' ) {
|
||||
if( *i != '"' ) out += *i;
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
if( i == out.end() ) return out;
|
||||
switch( *i ) {
|
||||
case 't' : out += '\t'; break;
|
||||
case 'n' : out += '\n'; break;
|
||||
case 'r' : out += '\r'; break;
|
||||
case '\\' : out += '\\'; break;
|
||||
case '"' : out += '"'; break;
|
||||
case 'x' : {
|
||||
++i; if( i == out.end() ) return out;
|
||||
char c = from_hex(*i);
|
||||
++i; if( i == out.end() ) { out += c; return out; }
|
||||
c = c<<4 | from_hex(*i);
|
||||
out += c;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
out += '\\';
|
||||
out += *i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} }
|
||||
147
src/context.hpp
Normal file
147
src/context.hpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#ifndef _FC_CONTEXT_HPP_
|
||||
#define _FC_CONTEXT_HPP_
|
||||
#include <fc/thread.hpp>
|
||||
#include <fc/error.hpp>
|
||||
#include <boost/context/all.hpp>
|
||||
#include <fc/exception.hpp>
|
||||
|
||||
namespace fc {
|
||||
class thread;
|
||||
class promise_base;
|
||||
class task_base;
|
||||
|
||||
namespace bc = boost::ctx;
|
||||
|
||||
/**
|
||||
* maintains information associated with each context such as
|
||||
* where it is blocked, what time it should resume, priority,
|
||||
* etc.
|
||||
*/
|
||||
struct context {
|
||||
typedef fc::context* ptr;
|
||||
|
||||
|
||||
context( void (*sf)(intptr_t), bc::stack_allocator& alloc, fc::thread* t )
|
||||
: caller_context(0),
|
||||
stack_alloc(&alloc),
|
||||
next_blocked(0),
|
||||
next(0),
|
||||
ctx_thread(t),
|
||||
canceled(false),
|
||||
complete(false),
|
||||
cur_task(0)
|
||||
{
|
||||
my_context.fc_stack.base = alloc.allocate( bc::minimum_stacksize() );
|
||||
// slog( "new stack %1% bytes at %2%", bc::minimum_stacksize(), my_context.fc_stack.base );
|
||||
my_context.fc_stack.limit =
|
||||
static_cast<char*>( my_context.fc_stack.base) - bc::minimum_stacksize();
|
||||
make_fcontext( &my_context, sf );
|
||||
}
|
||||
|
||||
context( fc::thread* t)
|
||||
:caller_context(0),
|
||||
stack_alloc(0),
|
||||
next_blocked(0),
|
||||
next(0),
|
||||
ctx_thread(t),
|
||||
canceled(false),
|
||||
complete(false),
|
||||
cur_task(0)
|
||||
{}
|
||||
|
||||
~context() {
|
||||
if(stack_alloc) {
|
||||
stack_alloc->deallocate( my_context.fc_stack.base, bc::minimum_stacksize() );
|
||||
// slog("deallocate stack" );
|
||||
}
|
||||
}
|
||||
|
||||
struct blocked_promise {
|
||||
blocked_promise( promise_base* p=0, bool r=true )
|
||||
:prom(p),required(r){}
|
||||
|
||||
promise_base* prom;
|
||||
bool required;
|
||||
};
|
||||
|
||||
/**
|
||||
* @todo Have a list of promises so that we can wait for
|
||||
* P1 or P2 and either will unblock instead of requiring both
|
||||
* @param req - require this promise to 'unblock', otherwise try_unblock
|
||||
* will allow it to be one of many that could 'unblock'
|
||||
*/
|
||||
void add_blocking_promise( promise_base* p, bool req = true ) {
|
||||
for( auto i = blocking_prom.begin(); i != blocking_prom.end(); ++i ) {
|
||||
if( i->prom == p ) {
|
||||
i->required = req;
|
||||
return;
|
||||
}
|
||||
}
|
||||
blocking_prom.push_back( blocked_promise(p,req) );
|
||||
}
|
||||
/**
|
||||
* If all of the required promises and any optional promises then
|
||||
* return true, else false.
|
||||
* @todo check list
|
||||
*/
|
||||
bool try_unblock( promise_base* p ) {
|
||||
if( blocking_prom.size() == 0 ) {
|
||||
return true;
|
||||
}
|
||||
bool req = false;
|
||||
for( uint32_t i = 0; i < blocking_prom.size(); ++i ) {
|
||||
if( blocking_prom[i].prom == p ) {
|
||||
blocking_prom[i].required = false;
|
||||
return true;
|
||||
}
|
||||
req = req || blocking_prom[i].required;
|
||||
}
|
||||
return !req;
|
||||
}
|
||||
|
||||
void remove_blocking_promise( promise_base* p ) {
|
||||
for( auto i = blocking_prom.begin(); i != blocking_prom.end(); ++i ) {
|
||||
if( i->prom == p ) {
|
||||
blocking_prom.erase(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void timeout_blocking_promises() {
|
||||
for( auto i = blocking_prom.begin(); i != blocking_prom.end(); ++i ) {
|
||||
i->prom->set_exception( boost::copy_exception( future_wait_timeout() ) );
|
||||
}
|
||||
}
|
||||
template<typename Exception>
|
||||
void except_blocking_promises( const Exception& e ) {
|
||||
for( auto i = blocking_prom.begin(); i != blocking_prom.end(); ++i ) {
|
||||
i->prom->set_exception( boost::copy_exception( e ) );
|
||||
}
|
||||
}
|
||||
void clear_blocking_promises() {
|
||||
blocking_prom.clear();
|
||||
}
|
||||
|
||||
bool is_complete()const { return complete; }
|
||||
|
||||
|
||||
|
||||
bc::fcontext_t my_context;
|
||||
fc::context* caller_context;
|
||||
bc::stack_allocator* stack_alloc;
|
||||
priority prio;
|
||||
//promise_base* prom;
|
||||
std::vector<blocked_promise> blocking_prom;
|
||||
time_point resume_time;
|
||||
fc::context* next_blocked;
|
||||
fc::context* next;
|
||||
fc::thread* ctx_thread;
|
||||
bool canceled;
|
||||
bool complete;
|
||||
task_base* cur_task;
|
||||
};
|
||||
|
||||
} // naemspace fc
|
||||
|
||||
#endif // _FC_CONTEXT_HPP_
|
||||
69
src/exception.cpp
Normal file
69
src/exception.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#include <fc/exception.hpp>
|
||||
#include <boost/exception/all.hpp>
|
||||
|
||||
namespace fc {
|
||||
#define bexcept void* e = &my[0]; (*((boost::exception_ptr*)e))
|
||||
#define cbexcept const void* e = &my[0]; (*((const boost::exception_ptr*)e))
|
||||
|
||||
exception_ptr::exception_ptr() {
|
||||
new (&my[0]) boost::exception_ptr();
|
||||
}
|
||||
exception_ptr::exception_ptr( const boost::exception_ptr& c ){
|
||||
static_assert( sizeof(my) >= sizeof(c), "boost::exception_ptr is larger than space reserved for it" );
|
||||
new (&my[0]) boost::exception_ptr(c);
|
||||
}
|
||||
exception_ptr::exception_ptr( boost::exception_ptr&& c ){
|
||||
new (&my[0]) boost::exception_ptr(fc::move(c));
|
||||
}
|
||||
exception_ptr::exception_ptr( const exception_ptr& c ){
|
||||
new (&my[0]) boost::exception_ptr(c);
|
||||
}
|
||||
exception_ptr::exception_ptr( exception_ptr&& c ){
|
||||
new (&my[0]) boost::exception_ptr(fc::move(c));
|
||||
}
|
||||
exception_ptr::~exception_ptr(){
|
||||
bexcept.~exception_ptr();
|
||||
}
|
||||
exception_ptr& exception_ptr::operator=(const boost::exception_ptr& c){
|
||||
bexcept = c;
|
||||
return *this;
|
||||
}
|
||||
exception_ptr& exception_ptr::operator=(boost::exception_ptr&& c){
|
||||
bexcept = fc::move(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
exception_ptr& exception_ptr::operator=(const exception_ptr& c){
|
||||
bexcept = c;
|
||||
return *this;
|
||||
}
|
||||
exception_ptr& exception_ptr::operator=(exception_ptr&& c){
|
||||
bexcept = fc::move(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
fc::string exception_ptr::diagnostic_information()const{
|
||||
const void* e = &my[0];
|
||||
return boost::diagnostic_information( *((const boost::exception_ptr*)e) ).c_str();
|
||||
}
|
||||
|
||||
exception_ptr::operator const boost::exception_ptr& ()const{
|
||||
const void* e = &my[0];
|
||||
return (*((const boost::exception_ptr*)e));
|
||||
}
|
||||
exception_ptr::operator boost::exception_ptr& (){
|
||||
void* e = &my[0];
|
||||
return (*((boost::exception_ptr*)e));
|
||||
}
|
||||
|
||||
exception_ptr current_exception() {
|
||||
return boost::current_exception();
|
||||
}
|
||||
void rethrow_exception( const exception_ptr& e ) {
|
||||
boost::rethrow_exception( static_cast<boost::exception_ptr>(e) );
|
||||
}
|
||||
exception_ptr::operator bool()const {
|
||||
const void* e = &my[0];
|
||||
return (*((boost::exception_ptr*)e));
|
||||
}
|
||||
}
|
||||
91
src/future.cpp
Normal file
91
src/future.cpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#include <fc/future.hpp>
|
||||
#include <fc/spin_yield_lock.hpp>
|
||||
#include <fc/exception.hpp>
|
||||
#include <fc/thread.hpp>
|
||||
#include <fc/error.hpp>
|
||||
#include <fc/unique_lock.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
promise_base::promise_base( const char* desc )
|
||||
: _ready(false),
|
||||
_blocked_thread(nullptr),
|
||||
_timeout(time_point::max()),
|
||||
_canceled(false),
|
||||
_desc(desc),
|
||||
_compl(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
const char* promise_base::get_desc()const{
|
||||
return _desc;
|
||||
}
|
||||
|
||||
void promise_base::cancel(){
|
||||
_canceled = true;
|
||||
}
|
||||
bool promise_base::ready()const {
|
||||
return _ready;
|
||||
}
|
||||
bool promise_base::error()const {
|
||||
{ synchronized(_spin_yield)
|
||||
return _except;
|
||||
}
|
||||
}
|
||||
|
||||
void promise_base::set_exception( const fc::exception_ptr& e ){
|
||||
_except = e;
|
||||
_set_value(nullptr);
|
||||
}
|
||||
|
||||
void promise_base::_wait( const microseconds& timeout_us ){
|
||||
if( timeout_us == microseconds::max() ) _wait_until( time_point::max() );
|
||||
else _wait_until( time_point::now() + timeout_us );
|
||||
}
|
||||
void promise_base::_wait_until( const time_point& timeout_us ){
|
||||
{ synchronized(_spin_yield)
|
||||
if( _ready ) {
|
||||
if( _except ) fc::rethrow_exception( _except );
|
||||
return;
|
||||
}
|
||||
_enqueue_thread();
|
||||
}
|
||||
thread::current().wait_until( ptr(this,true), timeout_us );
|
||||
if( _ready ) {
|
||||
if( _except ) fc::rethrow_exception( _except );
|
||||
return;
|
||||
}
|
||||
FC_THROW( future_wait_timeout() );
|
||||
}
|
||||
void promise_base::_enqueue_thread(){
|
||||
_blocked_thread =&thread::current();
|
||||
}
|
||||
void promise_base::_notify(){
|
||||
if( _blocked_thread )
|
||||
_blocked_thread->notify(ptr(this,true));
|
||||
}
|
||||
void promise_base::_set_timeout(){
|
||||
if( _ready )
|
||||
return;
|
||||
set_exception( fc::copy_exception( future_wait_timeout() ) );
|
||||
}
|
||||
void promise_base::_set_value(const void* s){
|
||||
BOOST_ASSERT( !_ready );
|
||||
{ synchronized(_spin_yield)
|
||||
_ready = true;
|
||||
}
|
||||
_notify();
|
||||
if( _compl ) {
|
||||
_compl->on_complete(s,_except);
|
||||
}
|
||||
}
|
||||
void promise_base::_on_complete( detail::completion_handler* c ) {
|
||||
{ synchronized(_spin_yield)
|
||||
delete _compl;
|
||||
_compl = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
573
src/json.cpp
Normal file
573
src/json.cpp
Normal file
|
|
@ -0,0 +1,573 @@
|
|||
#include <fc/json.hpp>
|
||||
#include <fc/reflect_value.hpp>
|
||||
#include <fc/stream.hpp>
|
||||
#include <fc/value.hpp>
|
||||
#include <fc/fwd_impl.hpp>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
// TODO: replace sstream with light/fast compiling version
|
||||
#include <sstream>
|
||||
|
||||
namespace fc { namespace json {
|
||||
|
||||
|
||||
struct range {
|
||||
range( const char* s, const char* e )
|
||||
:start(s),end(e){ }
|
||||
|
||||
operator bool()const { return start < end; }
|
||||
char operator*()const { return *start; }
|
||||
|
||||
range& operator++() { ++start; return *this; }
|
||||
range& operator++(int) { ++start; return *this; }
|
||||
|
||||
operator string() { return string(start,end); }
|
||||
|
||||
const char* start;
|
||||
const char* end;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class const_visitor : public fc::abstract_const_visitor {
|
||||
public:
|
||||
fc::ostream& out;
|
||||
const_visitor( fc::ostream& o ):out(o){}
|
||||
|
||||
virtual void visit()const{}
|
||||
virtual void visit( const char& c )const{ out << '"' << c << '"'; }
|
||||
virtual void visit( const uint8_t& c )const{ out << int(c); }
|
||||
virtual void visit( const uint16_t& c )const{ out << c; }
|
||||
virtual void visit( const uint32_t& c )const{ out << c; }
|
||||
virtual void visit( const uint64_t& c )const{ out << c; }
|
||||
virtual void visit( const int8_t& c )const{ out << int(c); }
|
||||
virtual void visit( const int16_t& c )const{ out << c;}
|
||||
virtual void visit( const int32_t& c )const{ out << c;}
|
||||
virtual void visit( const int64_t& c )const{ out << c;}
|
||||
virtual void visit( const double& c )const{ out << c;}
|
||||
virtual void visit( const float& c )const{ out << c;}
|
||||
virtual void visit( const bool& c )const{ out << (c?"true":"false"); }
|
||||
virtual void visit( const fc::string& c )const{
|
||||
out << '"'<< escape_string(c)<<'"';
|
||||
}
|
||||
virtual void array_size( int size )const {
|
||||
if( size == 0 ) { out <<"[]"; }
|
||||
}
|
||||
virtual void object_size( int size )const {
|
||||
if( size == 0 ) { out <<"{}"; }
|
||||
}
|
||||
virtual void visit( const char* member, int idx, int size, const cref& v)const{
|
||||
if( !idx ) out <<"{";
|
||||
out<<'"'<<member<<"\":";
|
||||
v._reflector.visit( v._obj, *this );
|
||||
if( idx != size-1 ) {
|
||||
out <<',';
|
||||
} else {
|
||||
out << '}';
|
||||
}
|
||||
}
|
||||
virtual void visit( int idx, int size, const cref& v)const{
|
||||
if( !idx ) out << '[';
|
||||
v._reflector.visit( v._obj, *this );
|
||||
out << ((idx < (size -1) ) ? ',' : ']');
|
||||
}
|
||||
};
|
||||
/*
|
||||
class visitor : public fc::abstract_visitor {
|
||||
public:
|
||||
virtual void visit()const{}
|
||||
virtual void visit( char& c )const{}
|
||||
virtual void visit( uint8_t& c )const{}
|
||||
virtual void visit( uint16_t& c )const{}
|
||||
virtual void visit( uint32_t& c )const{}
|
||||
virtual void visit( uint64_t& c )const{}
|
||||
virtual void visit( int8_t& c )const{}
|
||||
virtual void visit( int16_t& c )const{}
|
||||
virtual void visit( int32_t& c )const{}
|
||||
virtual void visit( int64_t& c )const{}
|
||||
virtual void visit( double& c )const{}
|
||||
virtual void visit( float& c )const{}
|
||||
virtual void visit( bool& c )const{}
|
||||
virtual void visit( fc::string& c )const{}
|
||||
virtual void visit( const char* member, int idx, int size, const ref& v)const{}
|
||||
virtual void visit( int idx, int size, const ref& v)const{}
|
||||
};
|
||||
*/
|
||||
uint8_t from_hex( char c ) {
|
||||
if( c >= '0' && c <= '9' )
|
||||
return c - '0';
|
||||
if( c >= 'a' && c <= 'f' )
|
||||
return c - 'a' + 10;
|
||||
if( c >= 'A' && c <= 'F' )
|
||||
return c - 'A' + 10;
|
||||
return c;
|
||||
}
|
||||
|
||||
value to_value( char* start, char* end/*, error_collector& ec*/ );
|
||||
|
||||
/**
|
||||
* Any unescaped quotes are dropped.
|
||||
* Because unescaped strings are always shorter, we can simply reuse
|
||||
* the memory of s.
|
||||
*
|
||||
* @param s a null terminated string that contains one or more escape chars
|
||||
*/
|
||||
char* inplace_unescape_string( char* s ) {
|
||||
while( *s == '"' ) ++s;
|
||||
char* out = s;
|
||||
|
||||
for( auto i = s; *i != '\0'; ++i ) {
|
||||
if( *i != '\\' ) {
|
||||
if( *i != '"' ) {
|
||||
*out = *i;
|
||||
++out;
|
||||
}
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
if( *i == '\0' ) { *out = '\0'; return s; }
|
||||
switch( *i ) {
|
||||
case 't' : *out = '\t'; ++out; break;
|
||||
case 'n' : *out = '\n'; ++out; break;
|
||||
case 'r' : *out = '\r'; ++out; break;
|
||||
case '\\': *out = '\\'; ++out; break;
|
||||
case '"' : *out = '"'; ++out; break;
|
||||
case 'x' : {
|
||||
++i; if( *i == '\0' ){ *out = '\0'; return s; }
|
||||
char c = from_hex(*i);
|
||||
++i; if( *i == '\0' ){ *out = c; ++out; *out = '\0'; return s; }
|
||||
c = c<<4 | from_hex(*i);
|
||||
*out = c;
|
||||
++out;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
*out = '\\';
|
||||
++out;
|
||||
*out = *i;
|
||||
++out;
|
||||
}
|
||||
}
|
||||
}
|
||||
*out = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
string to_string( const cref& o ) {
|
||||
std::stringstream ss;
|
||||
{
|
||||
fc::ostream os(ss);
|
||||
o._reflector.visit( o._obj, fc::json::const_visitor(os) );
|
||||
}
|
||||
return ss.str().c_str();
|
||||
}
|
||||
|
||||
|
||||
string pretty_print( const char* v, size_t s, uint8_t indent ) {
|
||||
int level = 0;
|
||||
const char* e= v + s;
|
||||
std::stringstream ss;
|
||||
bool first = false;
|
||||
bool quote = false;
|
||||
bool escape = false;
|
||||
while( v < e ) {
|
||||
switch( *v ) {
|
||||
case '\\':
|
||||
if( !escape ) {
|
||||
if( quote )
|
||||
escape = true;
|
||||
} else { escape = false; }
|
||||
ss<<*v;
|
||||
break;
|
||||
case ':':
|
||||
if( !quote ) {
|
||||
ss<<": ";
|
||||
} else {
|
||||
ss<<':';
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
if( first ) {
|
||||
ss<<'\n';
|
||||
for( int i = 0; i < level*indent; ++i ) ss<<' ';
|
||||
first = false;
|
||||
}
|
||||
if( !escape ) {
|
||||
quote = !quote;
|
||||
}
|
||||
escape = false;
|
||||
ss<<'"';
|
||||
break;
|
||||
case '{':
|
||||
case '[':
|
||||
ss<<*v;
|
||||
if( !quote ) {
|
||||
++level;
|
||||
first = true;
|
||||
}else {
|
||||
escape = false;
|
||||
}
|
||||
break;
|
||||
case '}':
|
||||
case ']':
|
||||
if( !quote ) {
|
||||
if( *(v-1) != '[' && *(v-1) != '{' ) {
|
||||
ss<<'\n';
|
||||
}
|
||||
--level;
|
||||
if( !first ) {
|
||||
for( int i = 0; i < level*indent; ++i ) ss<<' ';
|
||||
}
|
||||
ss<<*v;
|
||||
break;
|
||||
} else {
|
||||
escape = false;
|
||||
ss<<*v;
|
||||
}
|
||||
case ',':
|
||||
if( !quote ) {
|
||||
ss<<',';
|
||||
first = true;
|
||||
} else {
|
||||
escape = false;
|
||||
ss<<',';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if( first ) {
|
||||
ss<<'\n';
|
||||
for( int i = 0; i < level*indent; ++i ) ss<<' ';
|
||||
first = false;
|
||||
}
|
||||
ss << *v;
|
||||
}
|
||||
}
|
||||
return ss.str().c_str();
|
||||
}
|
||||
|
||||
string to_pretty_string( const cref& o, uint8_t indent ) {
|
||||
auto s = to_string(o);
|
||||
return pretty_print( s.c_str(), s.size(), indent );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Ignores leading white space.
|
||||
* If it starts with [,", or reads until matching ],", or
|
||||
* If it starts with something else it reads until [{",}]: or whitespace only
|
||||
* allowing a starting - or a single .
|
||||
*
|
||||
* @note internal json syntax errors are not caught, only bracket errors
|
||||
* are caught by this method. This makes it easy for error recovery
|
||||
* when values are read recursivley.
|
||||
*
|
||||
* @param in start of input
|
||||
* @param end end of input
|
||||
* @param oend output parameter to the end of the value
|
||||
*
|
||||
* @return the range of inputs for the value
|
||||
*/
|
||||
range read_value( const range& in ) {
|
||||
range start = in;
|
||||
// ignore leading whitespace
|
||||
bool done = false;
|
||||
while( !done && start ) {
|
||||
switch( *start ) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case ',':
|
||||
++start;
|
||||
default:
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
if( !start ) return start;
|
||||
range out = start;
|
||||
|
||||
bool found_dot = false;
|
||||
// check for literal vs object, array or string
|
||||
switch( *start ) {
|
||||
case ':':
|
||||
case ',':
|
||||
case '=':
|
||||
out.end = start.start + 1;
|
||||
return out;
|
||||
case '[':
|
||||
case '{':
|
||||
case '"':
|
||||
break;
|
||||
default: { // literal
|
||||
// read until non-literal character
|
||||
// allow it to start with -
|
||||
// allow only one '.'
|
||||
while( start ) {
|
||||
switch( *start ) {
|
||||
case '[': case ']':
|
||||
case '{': case '}':
|
||||
case ':': case '=':
|
||||
case ',': case '"':
|
||||
case ' ': case '\t': case '\n': case '\r': {
|
||||
out.end = start.start;
|
||||
return out;
|
||||
}
|
||||
case '.':
|
||||
if( found_dot ) {
|
||||
out.end = start.start;
|
||||
return out;
|
||||
}
|
||||
found_dot = true;
|
||||
break;
|
||||
case '-':
|
||||
if( out.start-start.start ){
|
||||
out.end = start.start;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
++start;
|
||||
}
|
||||
out.end = start.start;
|
||||
return out;
|
||||
}
|
||||
} // end literal check
|
||||
|
||||
int depth = 0;
|
||||
bool in_quote = false;
|
||||
bool in_escape = false;
|
||||
// read until closing ] or " ignoring escaped "
|
||||
while( start ) {
|
||||
if( !in_quote ) {
|
||||
switch( *start) {
|
||||
case '[':
|
||||
case '{': ++depth; break;
|
||||
case ']':
|
||||
case '}': --depth; break;
|
||||
case '"':
|
||||
++depth;
|
||||
in_quote = true;
|
||||
break;
|
||||
default: // do nothing;
|
||||
break;
|
||||
}
|
||||
} else { // in quote
|
||||
switch( *start ) {
|
||||
case '"': if( !in_escape ) {
|
||||
--depth;
|
||||
in_quote = false;
|
||||
break;
|
||||
}
|
||||
case '\\':
|
||||
in_escape = !in_escape;
|
||||
break;
|
||||
default:
|
||||
in_escape = false;
|
||||
}
|
||||
}
|
||||
++start;
|
||||
if( !depth ) { return range( out.start, start.start ); }
|
||||
}
|
||||
if( depth != 0 ) {
|
||||
// TODO: Throw Parse Error!
|
||||
elog("Parse Error!!");
|
||||
}
|
||||
return range( out.start, start.start );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void write( ostream& out, const cref& val ) {
|
||||
val._reflector.visit( val._obj, fc::json::const_visitor(out) );
|
||||
}
|
||||
|
||||
void read( istream& in, ref& val ) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
string escape_string( const string& s ) {
|
||||
// calculate escape string size.
|
||||
uint32_t ecount = 0;
|
||||
for( auto i = s.begin(); i != s.end(); ++i ) {
|
||||
if( ' '<= *i && *i <= '~' && *i !='\\' && *i != '"' ) {
|
||||
ecount+=1;
|
||||
} else {
|
||||
switch( *i ) {
|
||||
case '\t' :
|
||||
case '\n' :
|
||||
case '\r' :
|
||||
case '\\' :
|
||||
case '"' :
|
||||
ecount += 2; break;
|
||||
default:
|
||||
ecount += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
// unless the size changed, just return it.
|
||||
if( ecount == s.size() ) { return s; }
|
||||
|
||||
// reserve the bytes
|
||||
string out; out.reserve(ecount);
|
||||
|
||||
// print it out.
|
||||
for( auto i = s.begin(); i != s.end(); ++i ) {
|
||||
if( ' '<= *i && *i <= '~' && *i !='\\' && *i != '"' ) {
|
||||
out += *i;
|
||||
} else {
|
||||
out += '\\';
|
||||
switch( *i ) {
|
||||
case '\t' : out += 't'; break;
|
||||
case '\n' : out += 'n'; break;
|
||||
case '\r' : out += 'r'; break;
|
||||
case '\\' : out += '\\'; break;
|
||||
case '"' : out += '"'; break;
|
||||
default:
|
||||
out += "x";
|
||||
const char* const hexdig = "0123456789abcdef";
|
||||
out += hexdig[*i >> 4];
|
||||
out += hexdig[*i & 0xF];
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
string unescape_string( const string& s ) {
|
||||
string out; out.reserve(s.size());
|
||||
for( auto i = s.begin(); i != s.end(); ++i ) {
|
||||
if( *i != '\\' ) {
|
||||
if( *i != '"' ) out += *i;
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
if( i == out.end() ) return out;
|
||||
switch( *i ) {
|
||||
case 't' : out += '\t'; break;
|
||||
case 'n' : out += '\n'; break;
|
||||
case 'r' : out += '\r'; break;
|
||||
case '\\' : out += '\\'; break;
|
||||
case '"' : out += '"'; break;
|
||||
case 'x' : {
|
||||
++i; if( i == out.end() ) return out;
|
||||
char c = from_hex(*i);
|
||||
++i; if( i == out.end() ) { out += c; return out; }
|
||||
c = c<<4 | from_hex(*i);
|
||||
out += c;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
out += '\\';
|
||||
out += *i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
range skip_separator( range r, char c ) {
|
||||
while( r ) {
|
||||
switch( *r ) {
|
||||
case ' ': case '\n': case '\t': case '\r':
|
||||
++r;
|
||||
continue;
|
||||
default:
|
||||
if( *r == c ) { ++r; }
|
||||
else {
|
||||
// wlog( "Expected ',' but found '%c'", *r );
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [A,B,C]
|
||||
*/
|
||||
value read_array( const range& r ) {
|
||||
BOOST_ASSERT( *r == '[' );
|
||||
BOOST_ASSERT( *(r.end-1) == ']' );
|
||||
value out;
|
||||
range cur_range = read_value( r );
|
||||
|
||||
while( cur_range ) {
|
||||
out.push_back( *from_string( cur_range.start, cur_range.end ) );
|
||||
cur_range = read_value( range( cur_range.end, r.end) );
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @pre *input == {
|
||||
* @pre *input.end-1 == }
|
||||
*/
|
||||
value read_object( const range& in ) {
|
||||
BOOST_ASSERT( *in == '{' );
|
||||
BOOST_ASSERT( *(in.end-1) == '}' );
|
||||
value v;
|
||||
range key = read_value( ++range(in) );
|
||||
range rest(key.end,in.end-1);
|
||||
while( rest ) {
|
||||
range val = skip_separator( range(key.end,in.end), ':' );
|
||||
val = read_value( val );
|
||||
v[string(key)] = *from_string( val.start, val.end );
|
||||
range key = read_value( rest );
|
||||
rest.start = key.end;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
value_fwd from_string( const string& s ) {
|
||||
return from_string( s.c_str(), s.c_str() + s.size() );
|
||||
}
|
||||
|
||||
value_fwd from_string( const char* start, const char* end ) {
|
||||
if( start == end ) return value();
|
||||
|
||||
range s = read_value( range(start,end) );
|
||||
switch( s.start[0] ) {
|
||||
case '[':
|
||||
return read_array( s );
|
||||
case '{':
|
||||
return read_object( s );
|
||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {
|
||||
for( const char* n = s.start+1; n != s.end; ++n ) {
|
||||
if( *n == '.' ) {
|
||||
return boost::lexical_cast<double>(std::string(s.start,s.end));
|
||||
}
|
||||
}
|
||||
return boost::lexical_cast<uint64_t>(std::string(s.start,s.end));
|
||||
}
|
||||
case '-': {
|
||||
for( const char* n = s.start+1; n != s.end; ++n ) {
|
||||
if( *n == '.' ) {
|
||||
return (value)boost::lexical_cast<double>(std::string(s.start,s.end));
|
||||
}
|
||||
}
|
||||
return (value)boost::lexical_cast<int64_t>(std::string(s.start,s.end));
|
||||
}
|
||||
case '.': {
|
||||
return (value)boost::lexical_cast<int64_t>(std::string(s.start,s.end));
|
||||
}
|
||||
case '\"': {
|
||||
return (value)unescape_string( string(s.start,s.end) );
|
||||
}
|
||||
case 'n': {
|
||||
if( strncmp(s.start,"null",4 ) ) return value();
|
||||
}
|
||||
case 't': {
|
||||
if( strncmp(s.start,"true",4 ) ) return true;
|
||||
}
|
||||
case 'f': {
|
||||
if( strncmp(s.start,"false",5 ) ) return false;
|
||||
}
|
||||
default:
|
||||
wlog( "return unable to parse... return as string" );
|
||||
return value( string( s.start, s.end) );
|
||||
}
|
||||
}
|
||||
|
||||
} } // fc::json
|
||||
63
src/json_rpc_connection.cpp
Normal file
63
src/json_rpc_connection.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#include <fc/json_rpc_connection.hpp>
|
||||
|
||||
namespace fc { namespace json {
|
||||
|
||||
class rpc_connection_d {
|
||||
public:
|
||||
rpc_connection_d()
|
||||
:_in(0),_out(0),_next_req_id(0){}
|
||||
istream* _in;
|
||||
ostream* _out;
|
||||
int64_t _next_req_id;
|
||||
detail::pending_result::ptr _pr_head;
|
||||
detail::pending_result::ptr _pr_tail;
|
||||
};
|
||||
rpc_connection::rpc_connection() {
|
||||
my = new rpc_connection_d();
|
||||
}
|
||||
rpc_connection::rpc_connection( istream& i, ostream& o ) {
|
||||
my = new rpc_connection_d();
|
||||
init( i, o );
|
||||
}
|
||||
rpc_connection::rpc_connection( rpc_connection&& c )
|
||||
:my(c.my) {
|
||||
c.my = 0;
|
||||
}
|
||||
rpc_connection::~rpc_connection() {
|
||||
delete my;
|
||||
}
|
||||
|
||||
rpc_connection& rpc_connection::operator=(rpc_connection&& m) {
|
||||
fc::swap(m.my,my);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void rpc_connection::init( istream& i, ostream& o ) {
|
||||
my->_in = &i;
|
||||
my->_out = &o;
|
||||
}
|
||||
void rpc_connection::invoke( detail::pending_result::ptr&& p, const fc::string& m,
|
||||
uint16_t nparam, const cptr* param ) {
|
||||
p->id = ++my->_next_req_id;
|
||||
|
||||
my->_pr_tail->next = fc::move(p);
|
||||
my->_pr_tail = my->_pr_tail->next;
|
||||
|
||||
ostream& out = *my->_out;
|
||||
out << "{\"id\":"<<p->id<<",\"method\":"<<escape_string(m);
|
||||
if( nparam > 0 ) {
|
||||
out <<",\"params\":[";
|
||||
uint16_t back = nparam -1;
|
||||
for( uint16_t i = 0; i < back; ++i ) {
|
||||
fc::json::write( out, *(param[i]) );
|
||||
out <<',';
|
||||
}
|
||||
fc::json::write( out, *(param[back]) );
|
||||
out<<']';
|
||||
}
|
||||
out<<"}\n";
|
||||
out.flush();
|
||||
}
|
||||
|
||||
|
||||
} } // fc::json
|
||||
45
src/log.cpp
Normal file
45
src/log.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include <fc/log.hpp>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace fc {
|
||||
const char* short_name( const char* file_name ) {
|
||||
const char* end = file_name + strlen(file_name);
|
||||
--end;
|
||||
while( end >= file_name ) {
|
||||
if( *end == '/' || *end == '\\' ) {
|
||||
return end + 1;
|
||||
}
|
||||
--end;
|
||||
}
|
||||
return file_name;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#define isatty _isatty
|
||||
#define fileno _fileno
|
||||
#endif // WIN32
|
||||
|
||||
void log( const char* color, const char* file_name, size_t line_num, const char* method_name, const char* format, ... ) {
|
||||
if(isatty(fileno(stderr)))
|
||||
fprintf( stderr, "%s", color );
|
||||
|
||||
fprintf( stderr, "%s:%zd %s ", short_name(file_name), line_num, method_name );
|
||||
va_list args;
|
||||
va_start(args,format);
|
||||
vfprintf( stderr, format, args );
|
||||
va_end(args);
|
||||
if (isatty(fileno(stderr)))
|
||||
fprintf( stderr, "%s", CONSOLE_DEFAULT );
|
||||
fprintf( stderr, "\n" );
|
||||
}
|
||||
|
||||
/** used to add extra fields to be printed (thread,fiber,time,etc) */
|
||||
void add_log_field( void (*f)( ) ) {
|
||||
}
|
||||
|
||||
void remove_log_field( void (*f)( ) ) {
|
||||
}
|
||||
}
|
||||
23
src/shared_ptr.cpp
Normal file
23
src/shared_ptr.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include <fc/shared_ptr.hpp>
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/memory_order.hpp>
|
||||
|
||||
namespace fc {
|
||||
retainable::retainable()
|
||||
:_ref_count(1) { }
|
||||
|
||||
void retainable::retain() {
|
||||
((boost::atomic<int32_t>*)&_ref_count)->fetch_add(1, boost::memory_order_relaxed );
|
||||
}
|
||||
|
||||
void retainable::release() {
|
||||
if( 1 == ((boost::atomic<int32_t>*)&_ref_count)->fetch_sub(1, boost::memory_order_release ) ) {
|
||||
boost::atomic_thread_fence(boost::memory_order_acquire);
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t retainable::retain_count()const {
|
||||
return _ref_count;
|
||||
}
|
||||
}
|
||||
46
src/spin_lock.cpp
Normal file
46
src/spin_lock.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#include <fc/spin_lock.hpp>
|
||||
#include <fc/time.hpp>
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <new>
|
||||
|
||||
namespace fc {
|
||||
#define define_self boost::atomic<int>* self = (boost::atomic<int>*)&_lock
|
||||
spin_lock::spin_lock()
|
||||
{
|
||||
define_self;
|
||||
new (self) boost::atomic<int>();
|
||||
static_assert( sizeof(boost::atomic<int>) == sizeof(_lock), "" );
|
||||
self->store(unlocked);
|
||||
}
|
||||
|
||||
bool spin_lock::try_lock() {
|
||||
define_self;
|
||||
return self->exchange(locked, boost::memory_order_acquire)!=locked;
|
||||
}
|
||||
|
||||
bool spin_lock::try_lock_for( const fc::microseconds& us ) {
|
||||
return try_lock_until( fc::time_point::now() + us );
|
||||
}
|
||||
|
||||
bool spin_lock::try_lock_until( const fc::time_point& abs_time ) {
|
||||
while( abs_time > time_point::now() ) {
|
||||
if( try_lock() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void spin_lock::lock() {
|
||||
define_self;
|
||||
while( self->exchange(locked, boost::memory_order_acquire)==locked) { }
|
||||
}
|
||||
|
||||
void spin_lock::unlock() {
|
||||
define_self;
|
||||
self->store(unlocked, boost::memory_order_release);
|
||||
}
|
||||
|
||||
#undef define_self
|
||||
|
||||
} // namespace fc
|
||||
51
src/spin_yield_lock.cpp
Normal file
51
src/spin_yield_lock.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include <fc/spin_yield_lock.hpp>
|
||||
#include <fc/time.hpp>
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <new>
|
||||
|
||||
namespace fc {
|
||||
void yield();
|
||||
|
||||
#define define_self boost::atomic<int>* self = (boost::atomic<int>*)&_lock
|
||||
|
||||
spin_yield_lock::spin_yield_lock()
|
||||
{
|
||||
define_self;
|
||||
new (self) boost::atomic<int>();
|
||||
static_assert( sizeof(boost::atomic<int>) == sizeof(_lock), "" );
|
||||
self->store(unlocked);
|
||||
}
|
||||
|
||||
bool spin_yield_lock::try_lock() {
|
||||
define_self;
|
||||
return self->exchange(locked, boost::memory_order_acquire)!=locked;
|
||||
}
|
||||
|
||||
bool spin_yield_lock::try_lock_for( const fc::microseconds& us ) {
|
||||
return try_lock_until( fc::time_point::now() + us );
|
||||
}
|
||||
|
||||
bool spin_yield_lock::try_lock_until( const fc::time_point& abs_time ) {
|
||||
while( abs_time > time_point::now() ) {
|
||||
if( try_lock() )
|
||||
return true;
|
||||
yield();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void spin_yield_lock::lock() {
|
||||
define_self;
|
||||
while( self->exchange(locked, boost::memory_order_acquire)==locked) {
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
void spin_yield_lock::unlock() {
|
||||
define_self;
|
||||
self->store(unlocked, boost::memory_order_release);
|
||||
}
|
||||
#undef define_self
|
||||
|
||||
} // namespace fc
|
||||
187
src/stream.cpp
Normal file
187
src/stream.cpp
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
#include <fc/stream.hpp>
|
||||
#include <iostream>
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
#include <fc/thread.hpp>
|
||||
|
||||
namespace fc {
|
||||
namespace detail {
|
||||
namespace io = boost::iostreams;
|
||||
class cin_source : public io::source {
|
||||
public:
|
||||
typedef char type;
|
||||
|
||||
template<typename T>
|
||||
cin_source(T):_cin_thread(NULL){}
|
||||
cin_source():_cin_thread(NULL){}
|
||||
|
||||
cin_source( const cin_source& s ):_cin_thread(s._cin_thread){}
|
||||
|
||||
std::streamsize read( char* s, std::streamsize n ) {
|
||||
//if( !_cin_thread ) _cin_thread = new fc::thread("cin");
|
||||
|
||||
//if( _cin_thread != &fc::thread::current() ) {
|
||||
// return _cin_thread->async( [=](){ return this->read( s, n ); } ).wait();
|
||||
// }
|
||||
int r = std::cin.readsome(s,n);
|
||||
if( std::cin && r <= 0 ) {
|
||||
std::cin.read( s, 1 );
|
||||
if( std::cin.eof() ) return -1;
|
||||
return 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
private:
|
||||
fc::thread* _cin_thread;
|
||||
};
|
||||
std::istream& get_cin_stream() {
|
||||
static io::stream<cin_source> cin_stream;// = cin_source();
|
||||
cin_stream.open(NULL);
|
||||
return cin_stream;
|
||||
}
|
||||
|
||||
class abstract_source : public io::source {
|
||||
public:
|
||||
typedef char type;
|
||||
abstract_source( abstract_istream& ais ):_ais(ais){}
|
||||
|
||||
std::streamsize read( char* s, std::streamsize n ) {
|
||||
return _ais.readsome_impl( s, n );
|
||||
}
|
||||
abstract_istream& _ais;
|
||||
};
|
||||
abstract_istream::abstract_istream() {
|
||||
static_assert( sizeof(_store) >= sizeof( io::stream<abstract_source> ), "Failed to allocate enough space" );
|
||||
(new (&_store[0]) io::stream<abstract_source>( *this ));
|
||||
}
|
||||
size_t abstract_istream::readsome( char* buf, size_t len ) {
|
||||
auto iost = (io::stream<abstract_source>*)(&_store[0]);
|
||||
iost->read(buf,len);
|
||||
return len;
|
||||
}
|
||||
|
||||
class abstract_sink : public io::sink {
|
||||
public:
|
||||
struct category : io::sink::category, io::flushable_tag {};
|
||||
typedef char type;
|
||||
abstract_sink( abstract_ostream& aos ):_aos(aos){}
|
||||
|
||||
std::streamsize write( const char* s, std::streamsize n ) {
|
||||
return _aos.write_impl( s, n );
|
||||
}
|
||||
void close() { _aos.close_impl(); }
|
||||
bool flush() { _aos.flush_impl(); return true; }
|
||||
|
||||
abstract_ostream& _aos;
|
||||
};
|
||||
|
||||
abstract_ostream::abstract_ostream() {
|
||||
static_assert( sizeof(_store) >= sizeof( io::stream<abstract_sink> ), "Failed to allocate enough space" );
|
||||
(new (&_store[0]) io::stream<abstract_sink>( *this ));
|
||||
}
|
||||
size_t abstract_ostream::write( const char* buf, size_t len ) {
|
||||
auto iost = (io::stream<abstract_sink>*)(&_store[0]);
|
||||
iost->write(buf,len);
|
||||
return len;
|
||||
}
|
||||
void abstract_ostream::flush() {
|
||||
auto iost = (io::stream<abstract_sink>*)(&_store[0]);
|
||||
iost->flush();
|
||||
}
|
||||
void abstract_ostream::close() {
|
||||
auto iost = (io::stream<abstract_sink>*)(&_store[0]);
|
||||
iost->close();
|
||||
}
|
||||
|
||||
|
||||
abstract_istream::~abstract_istream() {
|
||||
}
|
||||
abstract_ostream::~abstract_ostream() {
|
||||
auto iost = (io::stream<abstract_sink>*)(&_store[0]);
|
||||
iost->~stream<abstract_sink>();
|
||||
}
|
||||
}
|
||||
|
||||
istream::~istream(){
|
||||
detail::abstract_istream* i = (detail::abstract_istream*)&_store[0];
|
||||
i->~abstract_istream();
|
||||
}
|
||||
|
||||
size_t istream::readsome( char* buf, size_t len ){
|
||||
detail::abstract_istream* i = (detail::abstract_istream*)&_store[0];
|
||||
return i->readsome(buf,len);
|
||||
}
|
||||
#define read_help \
|
||||
detail::abstract_istream* aos = (detail::abstract_istream*)&i._store[0];\
|
||||
auto iist = (detail::io::stream<detail::abstract_source>*)(&aos->_store[0]); \
|
||||
(*iist) >> s; \
|
||||
return i;
|
||||
|
||||
istream& operator>>( istream& i, int64_t& s){ read_help }
|
||||
istream& operator>>( istream& i, uint64_t& s){ read_help }
|
||||
istream& operator>>( istream& i, int32_t& s){ read_help }
|
||||
istream& operator>>( istream& i, uint32_t& s){ read_help }
|
||||
istream& operator>>( istream& i, int16_t& s){ read_help }
|
||||
istream& operator>>( istream& i, uint16_t& s){ read_help }
|
||||
istream& operator>>( istream& i, int8_t& s){ read_help }
|
||||
istream& operator>>( istream& i, uint8_t& s){ read_help }
|
||||
istream& operator>>( istream& i, float& s){ read_help }
|
||||
istream& operator>>( istream& i, double& s){ read_help }
|
||||
istream& operator>>( istream& i, bool& s){ read_help }
|
||||
istream& operator>>( istream& i, char& s){ read_help }
|
||||
istream& operator>>( istream& i, fc::string& s){
|
||||
std::string ss;
|
||||
detail::abstract_istream* aos = (detail::abstract_istream*)&i._store[0];
|
||||
auto iist = (detail::io::stream<detail::abstract_source>*)(&aos->_store[0]);
|
||||
(*iist) >> ss;
|
||||
s = ss.c_str();
|
||||
return i;
|
||||
}
|
||||
|
||||
#undef read_help
|
||||
|
||||
|
||||
ostream::~ostream(){
|
||||
detail::abstract_ostream* o = (detail::abstract_ostream*)&_store[0];
|
||||
close();
|
||||
o->~abstract_ostream();
|
||||
}
|
||||
|
||||
size_t ostream::write( const char* buf, size_t len ){
|
||||
detail::abstract_ostream* o = (detail::abstract_ostream*)&_store[0];
|
||||
return o->write(buf,len);
|
||||
}
|
||||
void ostream::close(){
|
||||
detail::abstract_ostream* o = (detail::abstract_ostream*)&_store[0];
|
||||
o->close();
|
||||
}
|
||||
void ostream::flush(){
|
||||
detail::abstract_ostream* o = (detail::abstract_ostream*)&_store[0];
|
||||
o->flush();
|
||||
}
|
||||
#define print_help \
|
||||
detail::abstract_ostream* aos = (detail::abstract_ostream*)&o._store[0];\
|
||||
auto iost = (detail::io::stream<detail::abstract_sink>*)(&aos->_store[0]); \
|
||||
(*iost) << s; \
|
||||
return o;
|
||||
|
||||
ostream& operator<<( ostream& o, int64_t s ){ print_help }
|
||||
ostream& operator<<( ostream& o, uint64_t s ){ print_help }
|
||||
ostream& operator<<( ostream& o, int32_t s ){ print_help }
|
||||
ostream& operator<<( ostream& o, uint32_t s ){ print_help }
|
||||
ostream& operator<<( ostream& o, int16_t s ){ print_help }
|
||||
ostream& operator<<( ostream& o, uint16_t s ){ print_help }
|
||||
ostream& operator<<( ostream& o, int8_t s ){ print_help }
|
||||
ostream& operator<<( ostream& o, uint8_t s ){ print_help }
|
||||
ostream& operator<<( ostream& o, float s ){ print_help }
|
||||
ostream& operator<<( ostream& o, double s ){ print_help }
|
||||
ostream& operator<<( ostream& o, bool s ){ print_help }
|
||||
ostream& operator<<( ostream& o, char s ){ print_help }
|
||||
ostream& operator<<( ostream& o, const char* s ){ print_help }
|
||||
ostream& operator<<( ostream& o, const fc::string& s ){ return o << s.c_str(); }
|
||||
|
||||
#undef print_help
|
||||
|
||||
ostream cout( std::cout );
|
||||
ostream cerr( std::cerr );
|
||||
istream cin( detail::get_cin_stream() );
|
||||
} //namespace fc
|
||||
101
src/string.cpp
Normal file
101
src/string.cpp
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
#include <fc/string.hpp>
|
||||
#include <fc/utility.hpp>
|
||||
|
||||
#include <string>
|
||||
namespace detail {
|
||||
void destroy( void* t ) {
|
||||
using namespace std;
|
||||
reinterpret_cast<std::string*>(t)->~string();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented with std::string for now.
|
||||
*/
|
||||
|
||||
namespace fc {
|
||||
|
||||
string::string() {
|
||||
static_assert( sizeof(*this) >= sizeof(std::string), "failed to reserve enough space" );
|
||||
new (this) std::string();
|
||||
}
|
||||
|
||||
string::string( const string& c ) {
|
||||
static_assert( sizeof(my) >= sizeof(std::string), "failed to reserve enough space" );
|
||||
new (this) std::string(reinterpret_cast<const std::string&>(c));
|
||||
}
|
||||
|
||||
|
||||
string::string( string&& m ) {
|
||||
static_assert( sizeof(my) >= sizeof(std::string), "failed to reserve enough space" );
|
||||
new (this) std::string(reinterpret_cast<std::string&&>(m));
|
||||
}
|
||||
|
||||
string::string( const char* c ){
|
||||
static_assert( sizeof(my) >= sizeof(std::string), "failed to reserve enough space" );
|
||||
new (this) std::string(c);
|
||||
}
|
||||
|
||||
string::string( const_iterator b, const_iterator e ) {
|
||||
static_assert( sizeof(my) >= sizeof(std::string), "failed to reserve enough space" );
|
||||
new (this) std::string(b,e);
|
||||
}
|
||||
|
||||
|
||||
string::~string() {
|
||||
::detail::destroy( this );
|
||||
}
|
||||
|
||||
string::iterator string::begin() { return &reinterpret_cast<std::string*>(this)->front(); }
|
||||
string::iterator string::end() { return &reinterpret_cast<std::string*>(this)->back() +1; }// my->str.size(); }
|
||||
string::const_iterator string::begin()const { return reinterpret_cast<const std::string*>(this)->c_str(); }
|
||||
string::const_iterator string::end()const { return reinterpret_cast<const std::string*>(this)->c_str() + reinterpret_cast<const std::string*>(this)->size(); }
|
||||
|
||||
char& string::operator[](uint64_t idx) { return reinterpret_cast<std::string*>(this)->at(idx); }
|
||||
const char& string::operator[](uint64_t idx)const { return reinterpret_cast<const std::string*>(this)->at(idx); }
|
||||
|
||||
void string::reserve(uint64_t r) { reinterpret_cast<std::string*>(this)->reserve(r); }
|
||||
uint64_t string::size()const { return reinterpret_cast<const std::string*>(this)->size(); }
|
||||
void string::clear() { return reinterpret_cast<std::string*>(this)->clear(); }
|
||||
void string::resize( uint64_t s ) { reinterpret_cast<std::string*>(this)->resize(s); }
|
||||
|
||||
const char* string::c_str()const { return reinterpret_cast<const std::string*>(this)->c_str(); }
|
||||
|
||||
bool string::operator == ( const char* s )const {
|
||||
return reinterpret_cast<const std::string&>(*this) == s;
|
||||
}
|
||||
bool string::operator == ( const string& s )const {
|
||||
return reinterpret_cast<const std::string&>(*this) == reinterpret_cast<const std::string&>(s);
|
||||
}
|
||||
bool string::operator != ( const string& s )const {
|
||||
return reinterpret_cast<const std::string&>(*this) != reinterpret_cast<const std::string&>(s);
|
||||
}
|
||||
|
||||
string& string::operator =( const string& c ) {
|
||||
reinterpret_cast<std::string&>(*this) = reinterpret_cast<const std::string&>(c);
|
||||
return *this;
|
||||
}
|
||||
string& string::operator =( string&& c ) {
|
||||
reinterpret_cast<std::string&>(*this) = fc::move( reinterpret_cast<std::string&>(c) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& string::operator+=( const string& s ) {
|
||||
reinterpret_cast<std::string&>(*this) += reinterpret_cast<const std::string&>(s);
|
||||
return *this;
|
||||
}
|
||||
string& string::operator+=( char c ) {
|
||||
reinterpret_cast<std::string&>(*this) += c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
string operator + ( const string& s, const string& c ) {
|
||||
return string(s) += c;
|
||||
}
|
||||
string operator + ( const string& s, char c ) {
|
||||
return string(s) += c;
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
|
||||
|
||||
29
src/task.cpp
Normal file
29
src/task.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#include <fc/task.hpp>
|
||||
#include <fc/exception.hpp>
|
||||
#include <fc/unique_lock.hpp>
|
||||
#include <fc/spin_lock.hpp>
|
||||
|
||||
namespace fc {
|
||||
task_base::task_base(void* func)
|
||||
:_functor(func){
|
||||
new (&_spinlock_store[0]) fc::spin_lock();
|
||||
}
|
||||
|
||||
void task_base::run() {
|
||||
try {
|
||||
_run_functor( _functor, _promise_impl );
|
||||
} catch ( ... ) {
|
||||
_promise_impl->set_exception( current_exception() );
|
||||
}
|
||||
}
|
||||
task_base::~task_base() {
|
||||
_destroy_functor( _functor );
|
||||
}
|
||||
|
||||
void task_base::_set_active_context(context* c) {
|
||||
void* p = &_spinlock_store[0];
|
||||
{ synchronized( *((fc::spin_lock*)p))
|
||||
_active_context = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
330
src/thread.cpp
Normal file
330
src/thread.cpp
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
#include <fc/thread.hpp>
|
||||
#include <fc/vector.hpp>
|
||||
#include "thread_d.hpp"
|
||||
|
||||
namespace fc {
|
||||
boost::mutex& log_mutex() {
|
||||
static boost::mutex m; return m;
|
||||
}
|
||||
|
||||
thread::thread( const char* name ) {
|
||||
promise<void>::ptr p(new promise<void>());
|
||||
boost::thread* t = new boost::thread( [this,p]() {
|
||||
try {
|
||||
this->my = new thread_d(*this);
|
||||
p->set_value();
|
||||
exec();
|
||||
} catch ( ... ) {
|
||||
elog( "Caught unhandled exception" );
|
||||
}
|
||||
} );
|
||||
p->wait();
|
||||
my->boost_thread = t;
|
||||
set_name(name);
|
||||
}
|
||||
thread::thread( thread_d* ) {
|
||||
my = new thread_d(*this);
|
||||
}
|
||||
|
||||
thread::thread( thread&& m ) {
|
||||
my = m.my;
|
||||
m.my = 0;
|
||||
}
|
||||
|
||||
thread& thread::operator=(thread&& t ) {
|
||||
fc::swap(t.my,my);
|
||||
return *this;
|
||||
}
|
||||
|
||||
thread::~thread() {
|
||||
delete my;
|
||||
}
|
||||
|
||||
thread& thread::current() {
|
||||
// Apple does not support __thread by default, but some custom gcc builds
|
||||
// for Mac OS X support it. Backup use boost::thread_specific_ptr
|
||||
#if defined(__APPLE__) && (__GNUC__ <= 4 && __GNUC_MINOR__ < 4)
|
||||
#warning using boost::thread_specific_ptr instead of __thread, use gcc 4.5 or newer for better performance.
|
||||
static boost::thread_specific_ptr<thread> t;
|
||||
if( !t.get() ) t.reset( new thread((thread_d*)0) );
|
||||
return *t.get();
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
static __declspec(thread) thread* t = NULL;
|
||||
#else
|
||||
static __thread thread* t = NULL;
|
||||
#endif
|
||||
if( !t ) t = new thread((thread_d*)0);
|
||||
return *t;
|
||||
#endif
|
||||
}
|
||||
const string& thread::name()const { return my->name; }
|
||||
void thread::set_name( const fc::string& n ) { my->name = n; }
|
||||
void thread::debug( const fc::string& d ) { my->debug(d); }
|
||||
|
||||
void thread::quit() {
|
||||
wlog( "quit!" );
|
||||
if( ¤t() != this ) {
|
||||
async( boost::bind( &thread::quit, this ) ).wait();
|
||||
if( my->boost_thread ) {
|
||||
my->boost_thread->join();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// break all promises, thread quit!
|
||||
fc::context* cur = my->blocked;
|
||||
while( cur ) {
|
||||
fc::context* n = cur->next;
|
||||
// this will move the context into the ready list.
|
||||
//cur->prom->set_exception( boost::copy_exception( error::thread_quit() ) );
|
||||
cur->except_blocking_promises( thread_quit() );
|
||||
cur = n;
|
||||
}
|
||||
BOOST_ASSERT( my->blocked == 0 );
|
||||
//my->blocked = 0;
|
||||
|
||||
|
||||
// move all sleep tasks to ready
|
||||
for( uint32_t i = 0; i < my->sleep_pqueue.size(); ++i ) {
|
||||
my->ready_push_front( my->sleep_pqueue[i] );
|
||||
}
|
||||
my->sleep_pqueue.clear();
|
||||
|
||||
// move all idle tasks to ready
|
||||
cur = my->pt_head;
|
||||
while( cur ) {
|
||||
fc::context* n = cur->next;
|
||||
cur->next = 0;
|
||||
my->ready_push_front( cur );
|
||||
cur = n;
|
||||
}
|
||||
|
||||
// mark all ready tasks (should be everyone)... as canceled
|
||||
cur = my->ready_head;
|
||||
while( cur ) {
|
||||
cur->canceled = true;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
my->done = true;
|
||||
|
||||
// now that we have poked all fibers... switch to the next one and
|
||||
// let them all quit.
|
||||
while( my->ready_head ) {
|
||||
my->start_next_fiber(true);
|
||||
my->check_for_timeouts();
|
||||
}
|
||||
my->clear_free_list();
|
||||
}
|
||||
|
||||
void thread::exec() {
|
||||
if( !my->current ) my->current = new fc::context(&fc::thread::current());
|
||||
my->process_tasks();
|
||||
delete my->current;
|
||||
my->current = 0;
|
||||
}
|
||||
|
||||
bool thread::is_running()const {
|
||||
return !my->done;
|
||||
}
|
||||
|
||||
priority thread::current_priority()const {
|
||||
BOOST_ASSERT(my);
|
||||
if( my->current ) return my->current->prio;
|
||||
return priority();
|
||||
}
|
||||
|
||||
void thread::yield(bool reschedule ) {
|
||||
my->check_fiber_exceptions();
|
||||
my->start_next_fiber(reschedule);
|
||||
my->check_fiber_exceptions();
|
||||
}
|
||||
void thread::sleep_until( const time_point& tp ) {
|
||||
my->check_fiber_exceptions();
|
||||
|
||||
BOOST_ASSERT( ¤t() == this );
|
||||
if( !my->current ) {
|
||||
my->current = new fc::context(&fc::thread::current());
|
||||
}
|
||||
|
||||
my->current->resume_time = tp;
|
||||
my->current->clear_blocking_promises();
|
||||
|
||||
my->sleep_pqueue.push_back(my->current);
|
||||
std::push_heap( my->sleep_pqueue.begin(),
|
||||
my->sleep_pqueue.end(), sleep_priority_less() );
|
||||
|
||||
my->start_next_fiber();
|
||||
my->current->resume_time = time_point::max();
|
||||
|
||||
my->check_fiber_exceptions();
|
||||
}
|
||||
int thread::wait_any_until( fc::vector<promise_base::ptr>&& p, const time_point& timeout) {
|
||||
for( size_t i = 0; i < p.size(); ++i ) {
|
||||
if( p[i]->ready() ) return i;
|
||||
}
|
||||
|
||||
if( timeout < time_point::now() )
|
||||
BOOST_THROW_EXCEPTION( future_wait_timeout() );
|
||||
|
||||
if( !my->current ) {
|
||||
my->current = new fc::context(&fc::thread::current());
|
||||
}
|
||||
|
||||
for( uint32_t i = 0; i < p.size(); ++i ) {
|
||||
my->current->add_blocking_promise(p[i].get(),false);
|
||||
};
|
||||
|
||||
// if not max timeout, added to sleep pqueue
|
||||
if( timeout != time_point::max() ) {
|
||||
my->current->resume_time = timeout;
|
||||
my->sleep_pqueue.push_back(my->current);
|
||||
std::push_heap( my->sleep_pqueue.begin(),
|
||||
my->sleep_pqueue.end(),
|
||||
sleep_priority_less() );
|
||||
}
|
||||
my->add_to_blocked( my->current );
|
||||
my->start_next_fiber();
|
||||
|
||||
for( auto i = p.begin(); i != p.end(); ++i ) {
|
||||
my->current->remove_blocking_promise(i->get());
|
||||
}
|
||||
|
||||
my->check_fiber_exceptions();
|
||||
|
||||
for( uint32_t i = 0; i < p.size(); ++i ) {
|
||||
if( p[i]->ready() ) return i;
|
||||
}
|
||||
BOOST_THROW_EXCEPTION( wait_any_error() );
|
||||
return -1;
|
||||
}
|
||||
|
||||
void thread::async_task( task_base* t, const priority& p, const char* desc ) {
|
||||
async_task( t, p, time_point::max(), desc );
|
||||
}
|
||||
|
||||
void thread::async_task( task_base* t, const priority& p, const time_point& tp, const char* desc ) {
|
||||
task_base* stale_head = my->task_in_queue.load(boost::memory_order_relaxed);
|
||||
do { t->_next = stale_head;
|
||||
}while( !my->task_in_queue.compare_exchange_weak( stale_head, t, boost::memory_order_release ) );
|
||||
|
||||
// Because only one thread can post the 'first task', only that thread will attempt
|
||||
// to aquire the lock and therefore there should be no contention on this lock except
|
||||
// when *this thread is about to block on a wait condition.
|
||||
if( this != ¤t() && !stale_head ) {
|
||||
boost::unique_lock<boost::mutex> lock(my->task_ready_mutex);
|
||||
my->task_ready.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void yield() {
|
||||
thread::current().yield();
|
||||
}
|
||||
void usleep( const microseconds& u ) {
|
||||
thread::current().sleep_until( time_point::now() + u);
|
||||
}
|
||||
void sleep_until( const time_point& tp ) {
|
||||
thread::current().sleep_until(tp);
|
||||
}
|
||||
|
||||
void exec() {
|
||||
return thread::current().exec();
|
||||
}
|
||||
|
||||
int wait_any( fc::vector<promise_base::ptr>&& v, const microseconds& timeout_us ) {
|
||||
return thread::current().wait_any_until( fc::move(v), time_point::now() + timeout_us );
|
||||
}
|
||||
int wait_any_until( fc::vector<promise_base::ptr>&& v, const time_point& tp ) {
|
||||
return thread::current().wait_any_until( fc::move(v), tp );
|
||||
}
|
||||
void thread::wait_until( promise_base::ptr&& p, const time_point& timeout ) {
|
||||
if( p->ready() ) return;
|
||||
if( timeout < time_point::now() )
|
||||
BOOST_THROW_EXCEPTION( future_wait_timeout() );
|
||||
|
||||
if( !my->current ) {
|
||||
my->current = new fc::context(&fc::thread::current());
|
||||
}
|
||||
|
||||
//slog( " %1% blocking on %2%", my->current, p.get() );
|
||||
my->current->add_blocking_promise(p.get(),true);
|
||||
|
||||
// if not max timeout, added to sleep pqueue
|
||||
if( timeout != time_point::max() ) {
|
||||
my->current->resume_time = timeout;
|
||||
my->sleep_pqueue.push_back(my->current);
|
||||
std::push_heap( my->sleep_pqueue.begin(),
|
||||
my->sleep_pqueue.end(),
|
||||
sleep_priority_less() );
|
||||
}
|
||||
|
||||
// elog( "blocking %1%", my->current );
|
||||
my->add_to_blocked( my->current );
|
||||
// my->debug("swtiching fibers..." );
|
||||
|
||||
|
||||
my->start_next_fiber();
|
||||
// slog( "resuming %1%", my->current );
|
||||
|
||||
//slog( " %1% unblocking blocking on %2%", my->current, p.get() );
|
||||
my->current->remove_blocking_promise(p.get());
|
||||
|
||||
my->check_fiber_exceptions();
|
||||
}
|
||||
|
||||
void thread::notify( const promise_base::ptr& p ) {
|
||||
BOOST_ASSERT(p->ready());
|
||||
if( ¤t() != this ) {
|
||||
this->async( boost::bind( &thread::notify, this, p ) );
|
||||
return;
|
||||
}
|
||||
//slog( " notify task complete %1%", p.get() );
|
||||
//debug( "begin notify" );
|
||||
// TODO: store a list of blocked contexts with the promise
|
||||
// to accelerate the lookup.... unless it introduces contention...
|
||||
|
||||
// iterate over all blocked contexts
|
||||
|
||||
|
||||
fc::context* cur_blocked = my->blocked;
|
||||
fc::context* prev_blocked = 0;
|
||||
while( cur_blocked ) {
|
||||
// if the blocked context is waiting on this promise
|
||||
// slog( "try unblock ctx %1% from prom %2%", cur_blocked, p.get() );
|
||||
if( cur_blocked->try_unblock( p.get() ) ) {
|
||||
//slog( "unblock!" );
|
||||
// remove it from the blocked list.
|
||||
|
||||
// remove this context from the sleep queue...
|
||||
for( uint32_t i = 0; i < my->sleep_pqueue.size(); ++i ) {
|
||||
if( my->sleep_pqueue[i] == cur_blocked ) {
|
||||
my->sleep_pqueue[i]->blocking_prom.clear();
|
||||
my->sleep_pqueue[i] = my->sleep_pqueue.back();
|
||||
my->sleep_pqueue.pop_back();
|
||||
std::make_heap( my->sleep_pqueue.begin(),my->sleep_pqueue.end(), sleep_priority_less() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto cur = cur_blocked;
|
||||
if( prev_blocked ) {
|
||||
prev_blocked->next_blocked = cur_blocked->next_blocked;
|
||||
cur_blocked = prev_blocked->next_blocked;
|
||||
} else {
|
||||
my->blocked = cur_blocked->next_blocked;
|
||||
cur_blocked = my->blocked;
|
||||
}
|
||||
cur->next_blocked = 0;
|
||||
my->ready_push_front( cur );
|
||||
} else { // goto the next blocked task
|
||||
prev_blocked = cur_blocked;
|
||||
cur_blocked = cur_blocked->next_blocked;
|
||||
}
|
||||
}
|
||||
//debug( "end notify" );
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
432
src/thread_d.hpp
Normal file
432
src/thread_d.hpp
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
#include <fc/thread.hpp>
|
||||
#include <fc/string.hpp>
|
||||
#include <fc/time.hpp>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include "context.hpp"
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/atomic.hpp>
|
||||
#include <vector>
|
||||
#include <fc/log.hpp>
|
||||
|
||||
namespace fc {
|
||||
struct sleep_priority_less {
|
||||
bool operator()( const context::ptr& a, const context::ptr& b ) {
|
||||
return a->resume_time > b->resume_time;
|
||||
}
|
||||
};
|
||||
class thread_d {
|
||||
public:
|
||||
thread_d(fc::thread& s)
|
||||
:self(s), boost_thread(0),
|
||||
task_in_queue(0),
|
||||
done(false),
|
||||
current(0),
|
||||
pt_head(0),
|
||||
ready_head(0),
|
||||
ready_tail(0),
|
||||
blocked(0)
|
||||
{
|
||||
static char cnt = 0;
|
||||
name = fc::string("th_") + char('a'+cnt);
|
||||
cnt++;
|
||||
}
|
||||
fc::thread& self;
|
||||
boost::thread* boost_thread;
|
||||
bc::stack_allocator stack_alloc;
|
||||
boost::mutex task_ready_mutex;
|
||||
boost::condition_variable task_ready;
|
||||
|
||||
boost::atomic<task_base*> task_in_queue;
|
||||
std::vector<task_base*> task_pqueue;
|
||||
std::vector<task_base*> task_sch_queue;
|
||||
std::vector<fc::context*> sleep_pqueue;
|
||||
std::vector<fc::context*> free_list;
|
||||
|
||||
bool done;
|
||||
fc::string name;
|
||||
fc::context* current;
|
||||
|
||||
fc::context* pt_head;
|
||||
|
||||
fc::context* ready_head;
|
||||
fc::context* ready_tail;
|
||||
|
||||
fc::context* blocked;
|
||||
|
||||
|
||||
|
||||
void debug( const fc::string& s ) {
|
||||
boost::unique_lock<boost::mutex> lock(log_mutex());
|
||||
|
||||
std::cerr<<"--------------------- "<<s.c_str()<<" - "<<current;
|
||||
if( current && current->cur_task ) std::cerr<<'('<<current->cur_task->get_desc()<<')';
|
||||
std::cerr<<" ---------------------------\n";
|
||||
std::cerr<<" Ready\n";
|
||||
fc::context* c = ready_head;
|
||||
while( c ) {
|
||||
std::cerr<<" "<<c;
|
||||
if( c->cur_task ) std::cerr<<'('<<c->cur_task->get_desc()<<')';
|
||||
fc::context* p = c->caller_context;
|
||||
while( p ) {
|
||||
std::cerr<<" -> "<<p;
|
||||
p = p->caller_context;
|
||||
}
|
||||
std::cerr<<"\n";
|
||||
c = c->next;
|
||||
}
|
||||
std::cerr<<" Blocked\n";
|
||||
c = blocked;
|
||||
while( c ) {
|
||||
std::cerr<<" ctx: "<< c;
|
||||
if( c->cur_task ) std::cerr<<'('<<c->cur_task->get_desc()<<')';
|
||||
std::cerr << " blocked on prom: ";
|
||||
for( uint32_t i = 0; i < c->blocking_prom.size(); ++i ) {
|
||||
std::cerr<<c->blocking_prom[i].prom<<'('<<c->blocking_prom[i].prom->get_desc()<<')';
|
||||
if( i + 1 < c->blocking_prom.size() ) {
|
||||
std::cerr<<",";
|
||||
}
|
||||
}
|
||||
|
||||
fc::context* p = c->caller_context;
|
||||
while( p ) {
|
||||
std::cerr<<" -> "<<p;
|
||||
p = p->caller_context;
|
||||
}
|
||||
std::cerr<<"\n";
|
||||
c = c->next_blocked;
|
||||
}
|
||||
std::cerr<<"-------------------------------------------------\n";
|
||||
}
|
||||
|
||||
// insert at from of blocked linked list
|
||||
inline void add_to_blocked( fc::context* c ) {
|
||||
c->next_blocked = blocked;
|
||||
blocked = c;
|
||||
}
|
||||
|
||||
void pt_push_back(fc::context* c) {
|
||||
c->next = pt_head;
|
||||
pt_head = c;
|
||||
/*
|
||||
fc::context* n = pt_head;
|
||||
int i = 0;
|
||||
while( n ) {
|
||||
++i;
|
||||
n = n->next;
|
||||
}
|
||||
wlog( "idle context...%2% %1%", c, i );
|
||||
*/
|
||||
}
|
||||
fc::context::ptr ready_pop_front() {
|
||||
fc::context::ptr tmp = 0;
|
||||
if( ready_head ) {
|
||||
tmp = ready_head;
|
||||
ready_head = tmp->next;
|
||||
if( !ready_head )
|
||||
ready_tail = 0;
|
||||
tmp->next = 0;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
void ready_push_front( const fc::context::ptr& c ) {
|
||||
c->next = ready_head;
|
||||
ready_head = c;
|
||||
if( !ready_tail )
|
||||
ready_tail = c;
|
||||
}
|
||||
void ready_push_back( const fc::context::ptr& c ) {
|
||||
c->next = 0;
|
||||
if( ready_tail ) {
|
||||
ready_tail->next = c;
|
||||
} else {
|
||||
ready_head = c;
|
||||
}
|
||||
ready_tail = c;
|
||||
}
|
||||
struct task_priority_less {
|
||||
bool operator()( task_base* a, task_base* b ) {
|
||||
return a->_prio.value < b->_prio.value ? true : (a->_prio.value > b->_prio.value ? false : a->_posted_num > b->_posted_num );
|
||||
}
|
||||
};
|
||||
struct task_when_less {
|
||||
bool operator()( task_base* a, task_base* b ) {
|
||||
return a->_when < b->_when;
|
||||
}
|
||||
};
|
||||
|
||||
void enqueue( task_base* t ) {
|
||||
time_point now = time_point::now();
|
||||
task_base* cur = t;
|
||||
while( cur ) {
|
||||
if( cur->_when > now ) {
|
||||
task_sch_queue.push_back(cur);
|
||||
std::push_heap( task_sch_queue.begin(),
|
||||
task_sch_queue.end(), task_when_less() );
|
||||
} else {
|
||||
task_pqueue.push_back(cur);
|
||||
BOOST_ASSERT( this == thread::current().my );
|
||||
std::push_heap( task_pqueue.begin(),
|
||||
task_pqueue.end(), task_priority_less() );
|
||||
}
|
||||
cur = cur->_next;
|
||||
}
|
||||
}
|
||||
task_base* dequeue() {
|
||||
// get a new task
|
||||
BOOST_ASSERT( this == thread::current().my );
|
||||
|
||||
task_base* pending = 0;
|
||||
|
||||
pending = task_in_queue.exchange(0,boost::memory_order_consume);
|
||||
if( pending ) { enqueue( pending ); }
|
||||
|
||||
task_base* p(0);
|
||||
if( task_sch_queue.size() ) {
|
||||
if( task_sch_queue.front()->_when <= time_point::now() ) {
|
||||
p = task_sch_queue.front();
|
||||
std::pop_heap(task_sch_queue.begin(), task_sch_queue.end(), task_when_less() );
|
||||
task_sch_queue.pop_back();
|
||||
return p;
|
||||
}
|
||||
}
|
||||
if( task_pqueue.size() ) {
|
||||
p = task_pqueue.front();
|
||||
std::pop_heap(task_pqueue.begin(), task_pqueue.end(), task_priority_less() );
|
||||
task_pqueue.pop_back();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be before or after a context switch to
|
||||
* detect quit/cancel operations and throw an exception.
|
||||
*/
|
||||
void check_fiber_exceptions() {
|
||||
if( current && current->canceled ) {
|
||||
BOOST_THROW_EXCEPTION( task_canceled() );
|
||||
} else if( done ) {
|
||||
BOOST_THROW_EXCEPTION( thread_quit() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next available context and switch to it.
|
||||
* If none are available then create a new context and
|
||||
* have it wait for something to do.
|
||||
*/
|
||||
bool start_next_fiber( bool reschedule = false ) {
|
||||
check_for_timeouts();
|
||||
if( !current ) current = new fc::context( &fc::thread::current() );
|
||||
|
||||
// check to see if any other contexts are ready
|
||||
if( ready_head ) {
|
||||
fc::context* next = ready_pop_front();
|
||||
BOOST_ASSERT( next != current );
|
||||
if( reschedule ) ready_push_back(current);
|
||||
|
||||
// jump to next context, saving current context
|
||||
fc::context* prev = current;
|
||||
current = next;
|
||||
bc::jump_fcontext( &prev->my_context, &next->my_context, 0 );
|
||||
current = prev;
|
||||
BOOST_ASSERT( current );
|
||||
} else { // all contexts are blocked, create a new context
|
||||
// that will process posted tasks...
|
||||
if( reschedule ) ready_push_back(current);
|
||||
|
||||
fc::context* next;
|
||||
if( pt_head ) {
|
||||
next = pt_head;
|
||||
pt_head = pt_head->next;
|
||||
next->next = 0;
|
||||
} else {
|
||||
next = new fc::context( &thread_d::start_process_tasks, stack_alloc,
|
||||
&fc::thread::current() );
|
||||
}
|
||||
fc::context* prev = current;
|
||||
current = next;
|
||||
bc::jump_fcontext( &prev->my_context, &next->my_context, (intptr_t)this );
|
||||
current = prev;
|
||||
BOOST_ASSERT( current );
|
||||
}
|
||||
|
||||
if( current->canceled )
|
||||
BOOST_THROW_EXCEPTION( task_canceled() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void start_process_tasks( intptr_t my ) {
|
||||
thread_d* self = (thread_d*)my;
|
||||
try {
|
||||
self->process_tasks();
|
||||
} catch ( ... ) {
|
||||
std::cerr<<"fiber exited with uncaught exception:\n "<<
|
||||
boost::current_exception_diagnostic_information() <<std::endl;
|
||||
}
|
||||
self->free_list.push_back(self->current);
|
||||
self->start_next_fiber( false );
|
||||
}
|
||||
|
||||
bool run_next_task() {
|
||||
check_for_timeouts();
|
||||
task_base* next = dequeue();
|
||||
if( next ) {
|
||||
next->_set_active_context( current );
|
||||
current->cur_task = next;
|
||||
next->run();
|
||||
current->cur_task = 0;
|
||||
next->_set_active_context(0);
|
||||
delete next;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool has_next_task() {
|
||||
if( task_pqueue.size() ||
|
||||
(task_sch_queue.size() && task_sch_queue.front()->_when <= time_point::now()) ||
|
||||
task_in_queue.load( boost::memory_order_relaxed ) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
void clear_free_list() {
|
||||
for( uint32_t i = 0; i < free_list.size(); ++i ) {
|
||||
delete free_list[i];
|
||||
}
|
||||
free_list.clear();
|
||||
}
|
||||
void process_tasks() {
|
||||
while( !done || blocked ) {
|
||||
if( run_next_task() ) continue;
|
||||
|
||||
// if I have something else to do other than
|
||||
// process tasks... do it.
|
||||
if( ready_head ) {
|
||||
pt_push_back( current );
|
||||
start_next_fiber(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
clear_free_list();
|
||||
|
||||
{ // lock scope
|
||||
boost::unique_lock<boost::mutex> lock(task_ready_mutex);
|
||||
if( has_next_task() ) continue;
|
||||
time_point timeout_time = check_for_timeouts();
|
||||
|
||||
if( timeout_time == time_point::max() ) {
|
||||
task_ready.wait( lock );
|
||||
} else if( timeout_time != time_point::min() ) {
|
||||
task_ready.wait_until( lock, boost::chrono::system_clock::time_point() +
|
||||
boost::chrono::microseconds(timeout_time.time_since_epoch().count()) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return system_clock::time_point::min() if tasks have timed out
|
||||
* Retunn system_clock::time_point::max() if there are no scheduled tasks
|
||||
* Return the time the next task needs to be run if there is anything scheduled.
|
||||
*/
|
||||
time_point check_for_timeouts() {
|
||||
if( !sleep_pqueue.size() && !task_sch_queue.size() ) {
|
||||
return time_point::max();
|
||||
}
|
||||
|
||||
|
||||
time_point next = time_point::max();
|
||||
if( task_sch_queue.size() && next > task_sch_queue.front()->_when )
|
||||
next = task_sch_queue.front()->_when;
|
||||
if( sleep_pqueue.size() && next > sleep_pqueue.front()->resume_time )
|
||||
next = sleep_pqueue.front()->resume_time;
|
||||
|
||||
time_point now = time_point::now();
|
||||
if( now < next ) { return next; }
|
||||
|
||||
// move all expired sleeping tasks to the ready queue
|
||||
while( sleep_pqueue.size() && sleep_pqueue.front()->resume_time < now ) {
|
||||
fc::context::ptr c = sleep_pqueue.front();
|
||||
std::pop_heap(sleep_pqueue.begin(), sleep_pqueue.end(), sleep_priority_less() );
|
||||
sleep_pqueue.pop_back();
|
||||
|
||||
if( c->blocking_prom.size() ) {
|
||||
c->timeout_blocking_promises();
|
||||
}
|
||||
else { ready_push_back( c ); }
|
||||
}
|
||||
return time_point::min();
|
||||
}
|
||||
|
||||
|
||||
void yield_until( const time_point& tp, bool reschedule ) {
|
||||
check_fiber_exceptions();
|
||||
|
||||
if( tp <= time_point::now() )
|
||||
return;
|
||||
|
||||
if( !current ) {
|
||||
current = new fc::context(&fc::thread::current());
|
||||
}
|
||||
|
||||
current->resume_time = tp;
|
||||
current->clear_blocking_promises();
|
||||
|
||||
sleep_pqueue.push_back(current);
|
||||
std::push_heap( sleep_pqueue.begin(),
|
||||
sleep_pqueue.end(), sleep_priority_less() );
|
||||
|
||||
start_next_fiber(reschedule);
|
||||
|
||||
// clear current context from sleep queue...
|
||||
for( uint32_t i = 0; i < sleep_pqueue.size(); ++i ) {
|
||||
if( sleep_pqueue[i] == current ) {
|
||||
sleep_pqueue[i] = sleep_pqueue.back();
|
||||
sleep_pqueue.pop_back();
|
||||
std::make_heap( sleep_pqueue.begin(),
|
||||
sleep_pqueue.end(), sleep_priority_less() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current->resume_time = time_point::max();
|
||||
check_fiber_exceptions();
|
||||
}
|
||||
|
||||
void wait( const promise_base::ptr& p, const time_point& timeout ) {
|
||||
if( p->ready() ) return;
|
||||
if( timeout < time_point::now() )
|
||||
BOOST_THROW_EXCEPTION( future_wait_timeout() );
|
||||
|
||||
if( !current ) {
|
||||
current = new fc::context(&fc::thread::current());
|
||||
}
|
||||
|
||||
//slog( " %1% blocking on %2%", current, p.get() );
|
||||
current->add_blocking_promise(p.get(),true);
|
||||
|
||||
// if not max timeout, added to sleep pqueue
|
||||
if( timeout != time_point::max() ) {
|
||||
current->resume_time = timeout;
|
||||
sleep_pqueue.push_back(current);
|
||||
std::push_heap( sleep_pqueue.begin(),
|
||||
sleep_pqueue.end(),
|
||||
sleep_priority_less() );
|
||||
}
|
||||
|
||||
// elog( "blocking %1%", current );
|
||||
add_to_blocked( current );
|
||||
// debug("swtiching fibers..." );
|
||||
|
||||
|
||||
start_next_fiber();
|
||||
// slog( "resuming %1%", current );
|
||||
|
||||
//slog( " %1% unblocking blocking on %2%", current, p.get() );
|
||||
current->remove_blocking_promise(p.get());
|
||||
|
||||
check_fiber_exceptions();
|
||||
}
|
||||
};
|
||||
} // namespace fc
|
||||
9
src/time.cpp
Normal file
9
src/time.cpp
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <fc/time.hpp>
|
||||
|
||||
namespace fc {
|
||||
namespace bch = boost::chrono;
|
||||
time_point time_point::now() {
|
||||
return time_point(microseconds(bch::duration_cast<bch::microseconds>(bch::system_clock::now().time_since_epoch()).count()));
|
||||
}
|
||||
}
|
||||
375
src/value.cpp
Normal file
375
src/value.cpp
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
#include <fc/fwd_reflect.hpp>
|
||||
#include <fc/value.hpp>
|
||||
#include <fc/reflect.hpp>
|
||||
#include <fc/string.hpp>
|
||||
#include <fc/reflect_vector.hpp>
|
||||
#include <fc/reflect_value.hpp>
|
||||
#include <fc/reflect_impl.hpp>
|
||||
#include <fc/fwd_impl.hpp>
|
||||
#include <fc/error.hpp>
|
||||
#include <fc/exception.hpp>
|
||||
|
||||
FC_REFLECT( fc::value::member, (_val) )
|
||||
|
||||
|
||||
namespace fc {
|
||||
value::member::member(){}
|
||||
value::member::member( const char* c )
|
||||
:_key(c){ }
|
||||
value::member::member( string&& c )
|
||||
:_key(fc::move(c)){ }
|
||||
|
||||
const string& value::member::key()const { return *_key; }
|
||||
value& value::member::val() { return *_val; }
|
||||
const value& value::member::val()const { return *_val; }
|
||||
|
||||
value::value()
|
||||
:_obj(nullptr),_obj_type(nullptr){ slog( "%p", this ); }
|
||||
|
||||
value::value( value&& v )
|
||||
:_obj(v._obj),_obj_type(v._obj_type)
|
||||
{
|
||||
slog( "move construct value" );
|
||||
v._obj_type = nullptr;
|
||||
v._obj = nullptr;
|
||||
}
|
||||
|
||||
value::~value() {
|
||||
slog( "~%p", this );
|
||||
if( nullptr != _obj_type ) {
|
||||
if( _obj != nullptr ) {
|
||||
slog( "obj_type %p", _obj_type );
|
||||
slog( "obj_type %s", _obj_type->name() );
|
||||
slog(".. obj type %p %s", _obj, _obj_type->name() );
|
||||
size_t s = _obj_type->size_of();
|
||||
if( s > sizeof(_obj) ) {
|
||||
slog( "destroy! %p", _obj );
|
||||
_obj_type->destroy( _obj );
|
||||
} else {
|
||||
slog( "destructor! %p", &_obj );
|
||||
_obj_type->destructor( &_obj );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value::value( const cref& v ) {
|
||||
slog( "this:%p %s from cref" , this, v._reflector.name());
|
||||
_obj_type = &v._reflector;
|
||||
size_t s = _obj_type->size_of();
|
||||
if( s > sizeof(_obj) ) {
|
||||
slog( "construct %s heap of size %d",_obj_type->name(),_obj_type->size_of() );
|
||||
_obj = new char[_obj_type->size_of()];
|
||||
slog( "v._obj %p", v._obj );
|
||||
_obj_type->copy_construct( _obj, v._obj );
|
||||
} else {
|
||||
slog( "construct %s in place %p type p %p", _obj_type->name(), _obj,_obj_type );
|
||||
_obj_type->copy_construct( &_obj, v._obj );
|
||||
}
|
||||
}
|
||||
|
||||
value::value( const value& v ) {
|
||||
slog( "%p", this );
|
||||
// slog( "copy v %s", v.type()->name() );
|
||||
_obj_type = v._obj_type;
|
||||
if( nullptr != _obj_type ) {
|
||||
size_t s = _obj_type->size_of();
|
||||
if( s > sizeof(_obj) ) {
|
||||
_obj = new char[_obj_type->size_of()];
|
||||
_obj_type->copy_construct( _obj, v._obj );
|
||||
} else {
|
||||
_obj_type->copy_construct( &_obj, &v._obj );
|
||||
}
|
||||
}
|
||||
}
|
||||
value& value::operator=( value&& v ) {
|
||||
swap( v._obj, _obj);
|
||||
swap( v._obj_type, _obj_type);
|
||||
return *this;
|
||||
if( v.type() == nullptr ) {
|
||||
return *this;
|
||||
}
|
||||
slog( "move assign v %s", v.type()->name() );
|
||||
size_t s = _obj_type->size_of();
|
||||
if( s > sizeof(_obj) ) {
|
||||
slog( "swap pointers to heap.." );
|
||||
fc::swap( _obj, v._obj );
|
||||
fc::swap( _obj_type, v._obj_type );
|
||||
} else {
|
||||
slog( "move construct in place %p %s", this, v._obj_type->name() );
|
||||
int64_t tmp;
|
||||
if( nullptr != _obj_type && nullptr != v._obj_type ) {
|
||||
slog( "swaping objs %s and %s", _obj_type->name(), v._obj_type->name() );
|
||||
slog( "swaping objs %p and %p", &_obj, &v._obj );
|
||||
slog( "&tmp = %p", &tmp );
|
||||
_obj_type->move_construct( &tmp, &_obj );
|
||||
slog( "move to tmp" );
|
||||
v._obj_type->move_construct( &_obj, &v._obj );
|
||||
slog( "move to dest" );
|
||||
_obj_type->move_construct( &v._obj, &tmp );
|
||||
slog( "move to src" );
|
||||
} else {
|
||||
fc::swap( _obj, v._obj );
|
||||
fc::swap( _obj_type, v._obj_type );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
value tmp(std::move(v));
|
||||
return *this;
|
||||
size_t s = _obj_type->size_of();
|
||||
if( s > sizeof(_obj) ) {
|
||||
slog( "" );
|
||||
fc::swap( _obj, v._obj );
|
||||
} else {
|
||||
slog( "swap..." );
|
||||
void* tmp;
|
||||
_obj_type->move( &tmp, &_obj );
|
||||
_obj_type->move( &_obj, &v._obj );
|
||||
_obj_type->move( &v._obj, &tmp );
|
||||
}
|
||||
fc::swap( _obj_type, v._obj_type );
|
||||
*/
|
||||
return *this;
|
||||
}
|
||||
value& value::operator=( const value& v ) {
|
||||
slog( "assign copy" );
|
||||
value t(v); fc::swap(t,*this);
|
||||
return *this;
|
||||
}
|
||||
value& value::operator=( const cref& v ) {
|
||||
//slog( "assign copy this %p %p %s obj_type %s",_obj,_obj_type, v._reflector.name(),_obj_type->name() );
|
||||
//if( _obj_type != null_ptr ) {
|
||||
//}
|
||||
wlog( ".." );
|
||||
value t(v);
|
||||
|
||||
wlog( "swap" );
|
||||
//swap( t._obj, _obj );
|
||||
//swap( t._obj_type, _obj_type );
|
||||
fc::swap(t,*this);
|
||||
slog( "done swap" );
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* @pre value is null or an object
|
||||
*/
|
||||
value& value::operator[]( const string& key ) {
|
||||
return (*this)[key.c_str()];
|
||||
}
|
||||
|
||||
value& value::operator[]( string&& key ) {
|
||||
if( is_null() ) {
|
||||
*this = vector<member>(1);
|
||||
}
|
||||
if( _obj_type == &reflector< vector<member> >::instance() ) {
|
||||
vector<member>& vec = *static_cast<vector<member>*>(ptr());
|
||||
for( uint32_t i = 0; i < vec.size(); ++i ) {
|
||||
if( vec[i].key() == key ) { return vec[i].val(); }
|
||||
}
|
||||
vec.push_back(member(fc::move(key)));
|
||||
return vec.back().val();
|
||||
}
|
||||
FC_THROW( bad_cast() );
|
||||
}
|
||||
|
||||
|
||||
const value& value::operator[]( const string& key )const {
|
||||
return (*this)[key.c_str()];
|
||||
}
|
||||
|
||||
value& value::operator[]( const char* key ) {
|
||||
if( is_null() ) {
|
||||
*this = vector<member>();
|
||||
}
|
||||
if( _obj_type == &reflector<vector<member> >::instance() ) {
|
||||
slog( "sizeof vector<member*>: %d", sizeof( vector<member*> ) );
|
||||
vector<member>& v = *static_cast<vector<member>*>((void*)&_obj);
|
||||
vector<member>::iterator i = v.begin();
|
||||
while( i != v.end() ) {
|
||||
// todo convert to string cmp to prevent temporary string??
|
||||
if( i->key() == key ) {
|
||||
return i->val();
|
||||
}
|
||||
++i;
|
||||
}
|
||||
v.push_back( member( key ) );
|
||||
return v.back().val();
|
||||
}
|
||||
// visit the native struct looking for key and return a ref to the value
|
||||
//
|
||||
// if not found, then convert native struct into vector<member> and recurse
|
||||
}
|
||||
const value& value::operator[]( const char* key )const {
|
||||
if( is_null() ) {
|
||||
// TODO: throw!
|
||||
}
|
||||
if( _obj_type == &reflector<vector<member> >::instance() ) {
|
||||
const vector<member>& v = *static_cast<const vector<member>*>((void*)&_obj);
|
||||
vector<member>::const_iterator i = v.begin();
|
||||
while( i != v.end() ) {
|
||||
if( i->key() == key ) {
|
||||
return i->val();
|
||||
}
|
||||
++i;
|
||||
}
|
||||
FC_THROW( range_error() );
|
||||
}
|
||||
FC_THROW( bad_cast() );
|
||||
}
|
||||
|
||||
value& value::operator[]( int index ) {
|
||||
return (*this)[uint64_t(index)];
|
||||
}
|
||||
value& value::operator[]( uint64_t index ) {
|
||||
if( is_null() ) {
|
||||
slog( "init from vector<value> of size %d", index+1 );
|
||||
//static_assert( sizeof(_obj) >= sizeof(vector<value>), "sanity check" );
|
||||
*this = vector<value>(index+1);
|
||||
//new (&_obj) vector<value>(index+1);
|
||||
//_obj_type = &reflector<vector<value> >::instance();
|
||||
}
|
||||
if( _obj_type == &reflector<vector<value> >::instance() ) {
|
||||
slog( "return ref to index..." );
|
||||
vector<value>& v = *static_cast<vector<value>*>(ptr());
|
||||
if( v.size() <= index ) { v.resize(index+1); }
|
||||
slog( "index %d vs size %d", index, v.size() );
|
||||
return v.at(index);
|
||||
}
|
||||
// visit the native struct looking for index...
|
||||
//
|
||||
//
|
||||
}
|
||||
const value& value::operator[]( uint64_t index )const {
|
||||
if( is_null() ) {
|
||||
// THROW
|
||||
while(1) ;
|
||||
}
|
||||
if( _obj_type == &reflector<vector<value> >::instance() ) {
|
||||
const vector<value>& v = *static_cast<const vector<value>*>(ptr());
|
||||
return v[index];
|
||||
}
|
||||
// visit the native struct looking for index... throw if not found.
|
||||
}
|
||||
|
||||
bool value::key_exists( const string& key ) {
|
||||
return key_exists(key.c_str());
|
||||
}
|
||||
bool value::key_exists( const char* key ) {
|
||||
return false;
|
||||
}
|
||||
bool value::is_array()const {
|
||||
return _obj_type == &reflector<vector<value> >::instance();
|
||||
}
|
||||
bool value::is_object()const {
|
||||
return _obj_type == &reflector<vector<member> >::instance();
|
||||
}
|
||||
bool value::is_null()const {
|
||||
return _obj_type == nullptr;
|
||||
}
|
||||
bool value::is_string()const {
|
||||
return _obj_type == &reflector<string>::instance();
|
||||
}
|
||||
bool value::is_float()const {
|
||||
return _obj_type == &reflector<float>::instance();
|
||||
}
|
||||
bool value::is_double()const {
|
||||
return _obj_type == &reflector<double>::instance();
|
||||
}
|
||||
bool value::is_real()const {
|
||||
return is_float() || is_double();
|
||||
}
|
||||
bool value::is_integer()const {
|
||||
return false;
|
||||
}
|
||||
bool value::is_boolean()const {
|
||||
return _obj_type == &reflector<bool>::instance();
|
||||
}
|
||||
fwd<vector<string>,8> value::get_keys()const {
|
||||
fwd<vector<string>,8> s;
|
||||
return s;
|
||||
}
|
||||
|
||||
value& value::push_back( const value& v ) {
|
||||
slog("here I go again... type %p %s", _obj_type, _obj_type ? _obj_type->name(): "null" );
|
||||
if( is_null() ) {
|
||||
wlog( "converting this to vector..." );
|
||||
*this = vector<value>();
|
||||
}
|
||||
if( _obj_type == &reflector<vector<value> >::instance() ) {
|
||||
vector<value>& vec = *static_cast<vector<value>*>(ptr());
|
||||
vec.push_back(v);
|
||||
} else {
|
||||
FC_THROW( bad_cast() );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
value& value::push_back( value&& v ) {
|
||||
slog("here I go again... type %p %s", _obj_type, _obj_type ? _obj_type->name(): "null" );
|
||||
if( is_null() ) {
|
||||
*this = vector<value>();
|
||||
}
|
||||
if( _obj_type == &reflector<vector<value> >::instance() ) {
|
||||
vector<value>& vec = *static_cast<vector<value>*>(ptr());
|
||||
vec.push_back(fc::move(v));
|
||||
} else {
|
||||
FC_THROW( bad_cast() );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void* value::ptr(){
|
||||
if( nullptr != _obj_type ) {
|
||||
if( _obj_type->size_of() > sizeof(_obj) )
|
||||
return _obj;
|
||||
return &_obj;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
const void* value::ptr()const {
|
||||
if( _obj_type ) {
|
||||
if( _obj_type->size_of() > sizeof(_obj) )
|
||||
return _obj;
|
||||
return &_obj;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
abstract_reflector* value::type()const { return _obj_type; }
|
||||
} // namespace fc
|
||||
|
||||
|
||||
namespace fc {
|
||||
const char* reflector<value>::name()const { return "value"; }
|
||||
void reflector<value>::visit( void* s, const abstract_visitor& v )const {
|
||||
}
|
||||
void reflector<value>::visit( const void* s, const abstract_const_visitor& v )const {
|
||||
const value& val = *((const value*)s);
|
||||
if( val.is_null() ) { v.visit(); }
|
||||
else if( val.is_array() ) {
|
||||
const vector<value>& vec = *static_cast<const vector<value>*>(val.ptr());
|
||||
auto s = vec.size();
|
||||
auto e = vec.end();
|
||||
int idx = 0;
|
||||
for( auto i = vec.begin(); i != e; ++i ) {
|
||||
v.visit( idx, s, *i );
|
||||
++idx;
|
||||
}
|
||||
} else if( val.is_object() ) {
|
||||
const vector<value::member>& vec = *static_cast<const vector<value::member>*>(val.ptr());
|
||||
auto s = vec.size();
|
||||
auto e = vec.end();
|
||||
int idx = 0;
|
||||
for( auto i = vec.begin(); i != e; ++i ) {
|
||||
v.visit( i->key().c_str(), idx, s, i->val() );
|
||||
++idx;
|
||||
}
|
||||
|
||||
} else {
|
||||
slog( "val type %s", val.type()->name() );
|
||||
val.type()->visit(val.ptr(), v );
|
||||
}
|
||||
}
|
||||
reflector<value>& reflector<value>::instance() { static reflector<value> inst; return inst; }
|
||||
} // namespace fc
|
||||
|
||||
95
src/value_cast.cpp
Normal file
95
src/value_cast.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
#include <fc/value_cast.hpp>
|
||||
#include <fc/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <fc/error.hpp>
|
||||
|
||||
|
||||
namespace fc {
|
||||
|
||||
#define CAST_VISITOR_IMPL(X) \
|
||||
void reinterpret_value_visitor<X>::visit()const{\
|
||||
FC_THROW( bad_cast() );\
|
||||
} \
|
||||
void reinterpret_value_visitor<X>::visit( const char& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const uint8_t& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const uint16_t& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const uint32_t& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const uint64_t& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const int8_t& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const int16_t& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const int32_t& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const int64_t& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const double& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const float& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const bool& c )const{ _s = c; } \
|
||||
void reinterpret_value_visitor<X>::visit( const string& c )const{\
|
||||
_s = boost::lexical_cast<X>( reinterpret_cast<const std::string&>(c) ); \
|
||||
} \
|
||||
void reinterpret_value_visitor<X>::visit( const char* member, int idx, int size, \
|
||||
const cref& v)const{\
|
||||
FC_THROW( bad_cast() );\
|
||||
}\
|
||||
void reinterpret_value_visitor<X>::visit( int idx, int size, const cref& v)const{\
|
||||
FC_THROW( bad_cast() );\
|
||||
}
|
||||
|
||||
CAST_VISITOR_IMPL(int64_t);
|
||||
CAST_VISITOR_IMPL(int32_t);
|
||||
CAST_VISITOR_IMPL(int16_t);
|
||||
CAST_VISITOR_IMPL(int8_t);
|
||||
CAST_VISITOR_IMPL(uint64_t);
|
||||
CAST_VISITOR_IMPL(uint32_t);
|
||||
CAST_VISITOR_IMPL(uint16_t);
|
||||
CAST_VISITOR_IMPL(uint8_t);
|
||||
CAST_VISITOR_IMPL(double);
|
||||
CAST_VISITOR_IMPL(float);
|
||||
CAST_VISITOR_IMPL(bool);
|
||||
|
||||
#undef CAST_VISITOR_IMPL
|
||||
|
||||
void reinterpret_value_visitor<string>::visit()const{
|
||||
FC_THROW( bad_cast() );
|
||||
}
|
||||
void reinterpret_value_visitor<string>::visit( const char& c )const{
|
||||
slog("" );
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c);
|
||||
}
|
||||
void reinterpret_value_visitor<string>::visit( const uint8_t& c )const{
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c); }
|
||||
void reinterpret_value_visitor<string>::visit( const uint16_t& c )const{
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c); }
|
||||
void reinterpret_value_visitor<string>::visit( const uint32_t& c )const{
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c); }
|
||||
void reinterpret_value_visitor<string>::visit( const uint64_t& c )const{
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c); }
|
||||
void reinterpret_value_visitor<string>::visit( const int8_t& c )const{
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c); }
|
||||
void reinterpret_value_visitor<string>::visit( const int16_t& c )const{
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c); }
|
||||
void reinterpret_value_visitor<string>::visit( const int32_t& c )const{
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c); }
|
||||
void reinterpret_value_visitor<string>::visit( const int64_t& c )const{
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c); }
|
||||
void reinterpret_value_visitor<string>::visit( const double& c )const{
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c); }
|
||||
void reinterpret_value_visitor<string>::visit( const float& c )const{
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c); }
|
||||
void reinterpret_value_visitor<string>::visit( const bool& c )const{
|
||||
reinterpret_cast<std::string&>(_s) = boost::lexical_cast<std::string>(c); }
|
||||
|
||||
void reinterpret_value_visitor<string>::visit( const string& c )const{
|
||||
slog( "" );
|
||||
_s = c;
|
||||
}
|
||||
void reinterpret_value_visitor<string>::visit( const char* member, int idx, int size,
|
||||
const cref& v)const{
|
||||
elog( "%s", member );
|
||||
FC_THROW( bad_cast() );
|
||||
}
|
||||
void reinterpret_value_visitor<string>::visit( int idx, int size, const cref& v)const{
|
||||
elog( "%d of %d", idx, size );
|
||||
FC_THROW( bad_cast() );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
186
src/vector.cpp
Normal file
186
src/vector.cpp
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
#include <fc/vector.hpp>
|
||||
|
||||
namespace fc {
|
||||
struct vector_impl_d {
|
||||
abstract_value_type& _vtbl;
|
||||
char* _data;
|
||||
size_t _size;
|
||||
size_t _capacity;
|
||||
|
||||
vector_impl_d( abstract_value_type& r, size_t size, size_t cap= 0 )
|
||||
:_vtbl(r),_data(0),_size(size),_capacity(cap) {
|
||||
if( _size > _capacity ) _capacity = _size;
|
||||
if( _capacity ) {
|
||||
const unsigned int so = _vtbl.size_of();
|
||||
_data = new char[_capacity*so];
|
||||
char* end = _data + _size *so;
|
||||
for( char* idx = _data; idx < end; idx += so ) {
|
||||
_vtbl.construct( idx );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector_impl_d( const vector_impl_d& cpy )
|
||||
:_vtbl(cpy._vtbl),_data(0),_size(cpy._size),_capacity(cpy._size) {
|
||||
if( _size ) {
|
||||
_data = new char[_size*_vtbl.size_of()];
|
||||
copy_from( cpy._data, cpy._size );
|
||||
}
|
||||
}
|
||||
|
||||
void copy_from( char* src, int cnt ) {
|
||||
const unsigned int so = _vtbl.size_of();
|
||||
char* end = _data + cnt * so;
|
||||
char* cpy_idx = src;
|
||||
for( char* idx = _data; idx < end; idx += so ) {
|
||||
_vtbl.copy_construct( idx, cpy_idx );
|
||||
cpy_idx += so;
|
||||
}
|
||||
}
|
||||
void move_from( char* src, int cnt ) {
|
||||
const unsigned int so = _vtbl.size_of();
|
||||
char* end = _data + cnt * so;
|
||||
char* cpy_idx = src;
|
||||
for( char* idx = _data; idx < end; idx += so ) {
|
||||
_vtbl.move_construct( idx, cpy_idx );
|
||||
cpy_idx += so;
|
||||
}
|
||||
}
|
||||
void destruct( char* src, int cnt ) {
|
||||
const unsigned int so = _vtbl.size_of();
|
||||
char* end = src + cnt * so;
|
||||
for( char* idx = src; idx < end; idx += so ) {
|
||||
_vtbl.destructor( idx );
|
||||
}
|
||||
}
|
||||
|
||||
~vector_impl_d() {
|
||||
clear();
|
||||
delete[] _data;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
const unsigned int so = _vtbl.size_of();
|
||||
char* end = _data + _size * so;
|
||||
for( char* idx = _data; idx < end; idx += so ) {
|
||||
_vtbl.destructor( idx );
|
||||
}
|
||||
_size = 0;
|
||||
}
|
||||
};
|
||||
|
||||
vector_impl::vector_impl( abstract_value_type& r, size_t s ) {
|
||||
my = new vector_impl_d(r,s);
|
||||
}
|
||||
|
||||
vector_impl::vector_impl( const vector_impl& cpy ) {
|
||||
my = new vector_impl_d(*cpy.my);
|
||||
}
|
||||
|
||||
vector_impl::vector_impl( vector_impl&& cpy ){
|
||||
my = cpy.my;
|
||||
cpy.my = 0;
|
||||
}
|
||||
|
||||
vector_impl::~vector_impl() {
|
||||
delete my;
|
||||
}
|
||||
|
||||
vector_impl& vector_impl::operator=( const vector_impl& v ) {
|
||||
clear();
|
||||
reserve(v.size());
|
||||
size_t s = v.size();
|
||||
for( size_t i = 0; i < s; ++i ) {
|
||||
_push_back( v._at(i) );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
vector_impl& vector_impl::operator=( vector_impl&& v ) {
|
||||
fc::swap(my,v.my);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void vector_impl::_push_back( const void* v ) {
|
||||
reserve( my->_size + 1 );
|
||||
my->_vtbl.copy_construct( _back(), v );
|
||||
my->_size++;
|
||||
}
|
||||
void vector_impl::_push_back_m( void* v ) {
|
||||
reserve( my->_size + 1 );
|
||||
my->_vtbl.move_construct( _back(), v );
|
||||
my->_size++;
|
||||
}
|
||||
|
||||
void* vector_impl::_back() {
|
||||
return my->_data + my->_vtbl.size_of() * (my->_size-1);
|
||||
}
|
||||
const void* vector_impl::_back()const {
|
||||
return my->_data + my->_vtbl.size_of() * (my->_size-1);
|
||||
}
|
||||
|
||||
void* vector_impl::_at(size_t p) {
|
||||
return my->_data + my->_vtbl.size_of() * p;
|
||||
}
|
||||
const void* vector_impl::_at(size_t p)const {
|
||||
return my->_data + my->_vtbl.size_of() * p;
|
||||
}
|
||||
|
||||
void vector_impl::pop_back() {
|
||||
my->_vtbl.destructor( _back() );
|
||||
my->_size--;
|
||||
}
|
||||
void vector_impl::clear() {
|
||||
my->clear();
|
||||
}
|
||||
|
||||
size_t vector_impl::size()const {
|
||||
return my->_size;
|
||||
}
|
||||
|
||||
void vector_impl::reserve( size_t s ) {
|
||||
if( s < my->_capacity ) {
|
||||
return;
|
||||
}
|
||||
char* new_data = new char[s*my->_vtbl.size_of()];
|
||||
fc::swap(new_data,my->_data);
|
||||
my->move_from(new_data,my->_size);
|
||||
my->destruct(new_data,my->_size);
|
||||
delete[] new_data;
|
||||
}
|
||||
void vector_impl::resize( size_t s ) {
|
||||
if( s <= my->_size ) {
|
||||
for( size_t i = s; i < my->_size; ++i ) {
|
||||
my->_vtbl.destructor( _at(i) );
|
||||
}
|
||||
my->_size = s;
|
||||
return;
|
||||
}
|
||||
if( s <= my->_capacity ) {
|
||||
|
||||
return;
|
||||
}
|
||||
const unsigned int so = my->_vtbl.size_of();
|
||||
char* new_data = new char[s*so];
|
||||
fc::swap(new_data,my->_data);
|
||||
my->_capacity = s;
|
||||
// move from old to new location
|
||||
my->move_from(new_data,my->_size);
|
||||
// destroy old location
|
||||
my->destruct(new_data,my->_size);
|
||||
delete[] new_data;
|
||||
|
||||
// default construct any left overs.
|
||||
char* cur = (char*)_back();
|
||||
char* end = (char*)my->_data + s * so;
|
||||
while( cur < end ) {
|
||||
my->_vtbl.construct(cur);
|
||||
cur += so;
|
||||
my->_size++;
|
||||
}
|
||||
}
|
||||
|
||||
size_t vector_impl::capacity()const {
|
||||
return my->_capacity;
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
Loading…
Reference in a new issue