Add Qt control station source
21
.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/.qmake.stash
|
||||||
|
/*.pro.user
|
||||||
|
/Makefile
|
||||||
|
/Makefile.*
|
||||||
|
/object_script.*
|
||||||
|
/bin/
|
||||||
|
/build/
|
||||||
|
/build_*/
|
||||||
|
/debug/
|
||||||
|
/release/
|
||||||
|
/dist/
|
||||||
|
/third_party/
|
||||||
|
/generated_cpp/*
|
||||||
|
!/generated_cpp/.gitkeep
|
||||||
|
/*.png
|
||||||
|
/*.log
|
||||||
|
/*.obj
|
||||||
|
/*.o
|
||||||
|
*.pfx
|
||||||
|
*.p12
|
||||||
|
*.key
|
||||||
199
CMakeLists.txt
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
project(CmvrControlStation VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
set(CMAKE_AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/ui")
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
|
||||||
|
set(CMVR_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||||
|
set(CMVR_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib")
|
||||||
|
set(CMVR_TOOLS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tools")
|
||||||
|
set(CMVR_CERT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/certs")
|
||||||
|
set(PROTO_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/protos")
|
||||||
|
set(GENERATED_ROOT "${CMAKE_CURRENT_BINARY_DIR}/generated_cpp")
|
||||||
|
set(PROTOC "${CMVR_TOOLS_DIR}/run_protoc.cmd")
|
||||||
|
set(GRPC_CPP_PLUGIN "${CMVR_TOOLS_DIR}/grpc_cpp_plugin.exe")
|
||||||
|
|
||||||
|
foreach(REQUIRED_FILE IN ITEMS
|
||||||
|
"${PROTOC}"
|
||||||
|
"${GRPC_CPP_PLUGIN}"
|
||||||
|
"${CMVR_LIB_DIR}/libgrpc++.a"
|
||||||
|
"${CMVR_LIB_DIR}/libprotobuf.a"
|
||||||
|
"${CMVR_LIB_DIR}/libavcodec.dll.a"
|
||||||
|
"${CMVR_LIB_DIR}/liburdfdom_model.dll.a"
|
||||||
|
"${CMVR_LIB_DIR}/msquic.dll")
|
||||||
|
if(NOT EXISTS "${REQUIRED_FILE}")
|
||||||
|
message(FATAL_ERROR "Required local dependency not found: ${REQUIRED_FILE}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
find_package(Qt5 5.12 REQUIRED COMPONENTS
|
||||||
|
Core Gui Widgets Multimedia 3DCore 3DRender 3DExtras 3DInput)
|
||||||
|
|
||||||
|
add_executable(CmvrControlStation WIN32
|
||||||
|
src/audiostreammanager.cpp
|
||||||
|
src/audiostreammanager.h
|
||||||
|
src/configeditorwidget.cpp
|
||||||
|
src/configeditorwidget.h
|
||||||
|
src/main.cpp
|
||||||
|
src/mainwindow.cpp
|
||||||
|
src/mainwindow_ui.cpp
|
||||||
|
src/mainwindow.h
|
||||||
|
src/quictestserver.cpp
|
||||||
|
src/quictestserver.h
|
||||||
|
src/rpcservicewidget.cpp
|
||||||
|
src/rpcservicewidget.h
|
||||||
|
src/robotclient.cpp
|
||||||
|
src/robotclient.h
|
||||||
|
src/trendwidget.cpp
|
||||||
|
src/trendwidget.h
|
||||||
|
src/urdfviewerwidget.cpp
|
||||||
|
src/urdfviewerwidget.h
|
||||||
|
src/videodecoder.cpp
|
||||||
|
src/videodecoder.h
|
||||||
|
ui/mainwindow.ui
|
||||||
|
ui/systemservicepage.ui
|
||||||
|
ui/armservicepage.ui
|
||||||
|
ui/cameraservicepage.ui
|
||||||
|
ui/agvservicepage.ui
|
||||||
|
ui/audioservicepage.ui
|
||||||
|
ui/quicserverpage.ui
|
||||||
|
ui/diagnosticspage.ui
|
||||||
|
ui/rpcservicewidget.ui
|
||||||
|
resources.qrc)
|
||||||
|
|
||||||
|
set_target_properties(CmvrControlStation PROPERTIES
|
||||||
|
DEBUG_POSTFIX "_d"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin/$<LOWER_CASE:$<CONFIG>>")
|
||||||
|
|
||||||
|
target_compile_definitions(CmvrControlStation PRIVATE
|
||||||
|
_WIN32_WINNT=0x0600 CMVR_WITH_GRPC=1)
|
||||||
|
target_include_directories(CmvrControlStation PRIVATE
|
||||||
|
"${CMVR_INCLUDE_DIR}"
|
||||||
|
"${CMVR_INCLUDE_DIR}/urdfdom_headers"
|
||||||
|
"${GENERATED_ROOT}")
|
||||||
|
target_link_libraries(CmvrControlStation PRIVATE
|
||||||
|
Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Multimedia
|
||||||
|
Qt5::3DCore Qt5::3DRender Qt5::3DExtras Qt5::3DInput)
|
||||||
|
|
||||||
|
set(PROTO_NAMES
|
||||||
|
cmvr/api/common
|
||||||
|
cmvr/msgs/agv
|
||||||
|
cmvr/api/agv_command
|
||||||
|
cmvr/api/agv_service
|
||||||
|
cmvr/api/arm_command
|
||||||
|
cmvr/api/arm_service
|
||||||
|
cmvr/api/biohead_command
|
||||||
|
cmvr/api/biohead_service
|
||||||
|
cmvr/api/camera_command
|
||||||
|
cmvr/api/camera_service
|
||||||
|
cmvr/api/configuration_command
|
||||||
|
cmvr/api/configuration_service
|
||||||
|
cmvr/api/dexhand_command
|
||||||
|
cmvr/api/dexhand_service
|
||||||
|
cmvr/api/hlc_command
|
||||||
|
cmvr/api/hlc_service
|
||||||
|
cmvr/api/microphone_command
|
||||||
|
cmvr/api/microphone_service
|
||||||
|
cmvr/api/speaker_command
|
||||||
|
cmvr/api/speaker_service
|
||||||
|
cmvr/api/system_command
|
||||||
|
cmvr/api/system_service
|
||||||
|
cmvr/api/test_service
|
||||||
|
cmvr/quic_edge/v1/quic_edge)
|
||||||
|
set(SERVICE_NAMES
|
||||||
|
cmvr/api/agv_service
|
||||||
|
cmvr/api/arm_service
|
||||||
|
cmvr/api/biohead_service
|
||||||
|
cmvr/api/camera_service
|
||||||
|
cmvr/api/configuration_service
|
||||||
|
cmvr/api/dexhand_service
|
||||||
|
cmvr/api/hlc_service
|
||||||
|
cmvr/api/microphone_service
|
||||||
|
cmvr/api/speaker_service
|
||||||
|
cmvr/api/system_service
|
||||||
|
cmvr/api/test_service)
|
||||||
|
|
||||||
|
set(GENERATED_FILES)
|
||||||
|
foreach(PROTO_NAME IN LISTS PROTO_NAMES)
|
||||||
|
set(PROTO_FILE "${PROTO_ROOT}/${PROTO_NAME}.proto")
|
||||||
|
set(PB_CC "${GENERATED_ROOT}/${PROTO_NAME}.pb.cc")
|
||||||
|
set(PB_H "${GENERATED_ROOT}/${PROTO_NAME}.pb.h")
|
||||||
|
get_filename_component(PROTO_OUTPUT_DIR "${PB_CC}" DIRECTORY)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${PB_CC}" "${PB_H}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${PROTO_OUTPUT_DIR}"
|
||||||
|
COMMAND "${PROTOC}"
|
||||||
|
--proto_path="${PROTO_ROOT}"
|
||||||
|
--cpp_out="${GENERATED_ROOT}"
|
||||||
|
"${PROTO_FILE}"
|
||||||
|
DEPENDS "${PROTO_FILE}" "${PROTOC}"
|
||||||
|
VERBATIM)
|
||||||
|
list(APPEND GENERATED_FILES "${PB_CC}" "${PB_H}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
foreach(SERVICE_NAME IN LISTS SERVICE_NAMES)
|
||||||
|
set(PROTO_FILE "${PROTO_ROOT}/${SERVICE_NAME}.proto")
|
||||||
|
set(GRPC_CC "${GENERATED_ROOT}/${SERVICE_NAME}.grpc.pb.cc")
|
||||||
|
set(GRPC_H "${GENERATED_ROOT}/${SERVICE_NAME}.grpc.pb.h")
|
||||||
|
get_filename_component(PROTO_OUTPUT_DIR "${GRPC_CC}" DIRECTORY)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${GRPC_CC}" "${GRPC_H}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${PROTO_OUTPUT_DIR}"
|
||||||
|
COMMAND "${PROTOC}"
|
||||||
|
--proto_path="${PROTO_ROOT}"
|
||||||
|
--grpc_out="${GENERATED_ROOT}"
|
||||||
|
--plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN}"
|
||||||
|
"${PROTO_FILE}"
|
||||||
|
DEPENDS "${PROTO_FILE}" "${PROTOC}" "${GRPC_CPP_PLUGIN}"
|
||||||
|
VERBATIM)
|
||||||
|
list(APPEND GENERATED_FILES "${GRPC_CC}" "${GRPC_H}")
|
||||||
|
endforeach()
|
||||||
|
target_sources(CmvrControlStation PRIVATE ${GENERATED_FILES})
|
||||||
|
|
||||||
|
file(GLOB ABSL_STATIC_LIBS "${CMVR_LIB_DIR}/libabsl_*.a")
|
||||||
|
target_link_libraries(CmvrControlStation PRIVATE
|
||||||
|
"-Wl,--start-group"
|
||||||
|
"${CMVR_LIB_DIR}/libgrpc++.a"
|
||||||
|
"${CMVR_LIB_DIR}/libgrpc.a"
|
||||||
|
"${CMVR_LIB_DIR}/libgpr.a"
|
||||||
|
"${CMVR_LIB_DIR}/libaddress_sorting.a"
|
||||||
|
"${CMVR_LIB_DIR}/libre2.a"
|
||||||
|
"${CMVR_LIB_DIR}/libupb.a"
|
||||||
|
"${CMVR_LIB_DIR}/libcares.a"
|
||||||
|
"${CMVR_LIB_DIR}/libssl.a"
|
||||||
|
"${CMVR_LIB_DIR}/libcrypto.a"
|
||||||
|
"${CMVR_LIB_DIR}/libzlibstatic.a"
|
||||||
|
"${CMVR_LIB_DIR}/libprotobuf.a"
|
||||||
|
${ABSL_STATIC_LIBS}
|
||||||
|
"-Wl,--end-group"
|
||||||
|
"${CMVR_LIB_DIR}/libavcodec.dll.a"
|
||||||
|
"${CMVR_LIB_DIR}/libavutil.dll.a"
|
||||||
|
"${CMVR_LIB_DIR}/libswscale.dll.a"
|
||||||
|
"${CMVR_LIB_DIR}/liburdfdom_model.dll.a"
|
||||||
|
ws2_32 crypt32 advapi32 bcrypt dbghelp iphlpapi secur32 ntdll)
|
||||||
|
|
||||||
|
file(GLOB CMVR_RUNTIME_DLLS "${CMVR_LIB_DIR}/*.dll")
|
||||||
|
foreach(RUNTIME_DLL IN LISTS CMVR_RUNTIME_DLLS)
|
||||||
|
add_custom_command(TARGET CmvrControlStation POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
"${RUNTIME_DLL}" "$<TARGET_FILE_DIR:CmvrControlStation>")
|
||||||
|
endforeach()
|
||||||
|
foreach(CERTIFICATE IN ITEMS quic-test-server.pfx quic-test-ca.crt)
|
||||||
|
add_custom_command(TARGET CmvrControlStation POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
"${CMVR_CERT_DIR}/${CERTIFICATE}"
|
||||||
|
"$<TARGET_FILE_DIR:CmvrControlStation>/${CERTIFICATE}")
|
||||||
|
endforeach()
|
||||||
|
add_custom_command(TARGET CmvrControlStation POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||||
|
"$<TARGET_FILE_DIR:CmvrControlStation>/models"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/models/demo_arm.urdf"
|
||||||
|
"$<TARGET_FILE_DIR:CmvrControlStation>/models/demo_arm.urdf")
|
||||||
|
|
||||||
|
install(TARGETS CmvrControlStation RUNTIME DESTINATION bin)
|
||||||
301
CmvrControlStation.pro
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
QT += core gui widgets multimedia 3dcore 3drender 3dextras 3dinput
|
||||||
|
|
||||||
|
CONFIG += c++14 warn_on debug_and_release
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
DEFINES += QT_DEPRECATED_WARNINGS _WIN32_WINNT=0x0600
|
||||||
|
|
||||||
|
INCLUDE_DIR = $$clean_path($$PWD/include)
|
||||||
|
LIB_DIR = $$clean_path($$PWD/lib)
|
||||||
|
TOOLS_DIR = $$clean_path($$PWD/tools)
|
||||||
|
CERT_DIR = $$clean_path($$PWD/certs)
|
||||||
|
PROTO_ROOT = $$clean_path($$PWD/protos)
|
||||||
|
PROTO_GEN_DIR = $$clean_path($$PWD/generated_cpp)
|
||||||
|
PROTOC = $$TOOLS_DIR/run_protoc.cmd
|
||||||
|
GRPC_CPP_PLUGIN = $$TOOLS_DIR/grpc_cpp_plugin.exe
|
||||||
|
MSQUIC_DLL = $$LIB_DIR/msquic.dll
|
||||||
|
MSQUIC_TEST_CERT = $$CERT_DIR/quic-test-server.pfx
|
||||||
|
MSQUIC_TEST_CA = $$CERT_DIR/quic-test-ca.crt
|
||||||
|
RUNTIME_DLLS = $$files($$LIB_DIR/*.dll)
|
||||||
|
DEMO_URDF = $$clean_path($$PWD/models/demo_arm.urdf)
|
||||||
|
QT_SCENEPARSER_DIR = $$clean_path($$[QT_INSTALL_PLUGINS]/sceneparsers)
|
||||||
|
|
||||||
|
!exists($$PROTOC): error("protoc launcher not found. Run scripts/build_native_deps.ps1 first.")
|
||||||
|
!exists($$GRPC_CPP_PLUGIN): error("grpc_cpp_plugin.exe not found. Run scripts/build_native_deps.ps1 first.")
|
||||||
|
!exists($$MSQUIC_DLL): error("msquic.dll not found. Run scripts/install_msquic.ps1 first.")
|
||||||
|
!exists($$MSQUIC_TEST_CERT): error("QUIC test certificate not found. Run scripts/install_msquic.ps1 first.")
|
||||||
|
!exists($$MSQUIC_TEST_CA): error("QUIC test CA not found. Run scripts/install_msquic.ps1 first.")
|
||||||
|
!exists($$INCLUDE_DIR/libavcodec/avcodec.h): error("FFmpeg headers not found in include.")
|
||||||
|
!exists($$LIB_DIR/avcodec-58.dll): error("FFmpeg runtime DLLs not found in lib.")
|
||||||
|
!exists($$INCLUDE_DIR/urdf_parser/urdf_parser.h): error("urdfdom headers not found in include.")
|
||||||
|
!exists($$LIB_DIR/liburdfdom_model.dll.a): error("urdfdom link library not found in lib.")
|
||||||
|
!exists($$LIB_DIR/liburdfdom_model.dll): error("urdfdom runtime DLL not found in lib.")
|
||||||
|
|
||||||
|
PROTO_FILES = \
|
||||||
|
$$PROTO_ROOT/cmvr/api/common.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/agv_command.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/agv_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/arm_command.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/arm_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/biohead_command.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/biohead_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/camera_command.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/camera_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/configuration_command.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/configuration_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/dexhand_command.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/dexhand_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/hlc_command.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/hlc_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/microphone_command.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/microphone_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/speaker_command.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/speaker_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/system_command.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/system_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/test_service.proto
|
||||||
|
|
||||||
|
GRPC_PROTO_FILES = \
|
||||||
|
$$PROTO_ROOT/cmvr/api/agv_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/arm_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/biohead_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/camera_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/configuration_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/dexhand_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/hlc_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/microphone_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/speaker_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/system_service.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/api/test_service.proto
|
||||||
|
|
||||||
|
MSG_PROTO_FILES = \
|
||||||
|
$$PROTO_ROOT/cmvr/msgs/agv.proto
|
||||||
|
|
||||||
|
CONFIG_PROTO_FILES = \
|
||||||
|
$$PROTO_ROOT/cmvr/config/agv_config/agv_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/arm_config/arm_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/aubo_robot_config/aubo_robot_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/biohead_config/biohead_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/camera_config/camera_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/cmvr_es_config/cmvr_es_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/device_manager_config/device_manager_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/dexhand_config/dexhand_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/grpc_server_config/grpc_server_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/logger_config/logger_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/microphone_config/microphone_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/motor_config/motor_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/quic_edge_config/quic_edge_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/self_collision_task_config/self_collision_task_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/speaker_config/speaker_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/task_manager_config/task_manager_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/touch_screen_task_config/touch_screen_task_config.proto
|
||||||
|
|
||||||
|
CONFIG_ROOT_PROTO_FILES = \
|
||||||
|
$$PROTO_ROOT/cmvr/config/cartesian_motion_validation_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/joint_limits_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/lawba_ik_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/pinocchio_dls_ik_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/pinocchio_qp_ik_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/srs_ik_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/touch_screen_algorithm_config.proto \
|
||||||
|
$$PROTO_ROOT/cmvr/config/touch_screen_common_config.proto
|
||||||
|
|
||||||
|
COMMON_PROTO_FILES = \
|
||||||
|
$$PROTO_ROOT/cmvr/common/geometry.proto
|
||||||
|
|
||||||
|
MUJOCO_PROTO_FILES = \
|
||||||
|
$$PROTO_ROOT/cmvr/config/mujoco_config/mujoco_world_config.proto
|
||||||
|
|
||||||
|
QUIC_PROTO_FILES = \
|
||||||
|
$$PROTO_ROOT/cmvr/quic_edge/v1/quic_edge.proto
|
||||||
|
|
||||||
|
# Show the complete local proto tree in Qt Creator without compiling unused APIs.
|
||||||
|
OTHER_FILES += $$files($$PROTO_ROOT/*.proto, true) $$DEMO_URDF
|
||||||
|
|
||||||
|
INCLUDEPATH += \
|
||||||
|
$$PROTO_GEN_DIR \
|
||||||
|
$$INCLUDE_DIR \
|
||||||
|
$$INCLUDE_DIR/urdfdom_headers
|
||||||
|
|
||||||
|
protobuf_compiler.name = Protobuf ${QMAKE_FILE_IN}
|
||||||
|
protobuf_compiler.input = PROTO_FILES
|
||||||
|
protobuf_compiler.output = $$PROTO_GEN_DIR/cmvr/api/${QMAKE_FILE_BASE}.pb.cc
|
||||||
|
protobuf_compiler.commands = $$quote($$PROTOC) --proto_path=$$quote($$PROTO_ROOT) --cpp_out=$$quote($$PROTO_GEN_DIR) $$quote($$PROTO_ROOT/cmvr/api/${QMAKE_FILE_BASE}.proto)
|
||||||
|
protobuf_compiler.depends = $$PROTO_FILES $$MSG_PROTO_FILES
|
||||||
|
protobuf_compiler.variable_out = SOURCES
|
||||||
|
protobuf_compiler.CONFIG += target_predeps
|
||||||
|
|
||||||
|
msg_protobuf_compiler.name = Protobuf ${QMAKE_FILE_IN}
|
||||||
|
msg_protobuf_compiler.input = MSG_PROTO_FILES
|
||||||
|
msg_protobuf_compiler.output = $$PROTO_GEN_DIR/cmvr/msgs/${QMAKE_FILE_BASE}.pb.cc
|
||||||
|
msg_protobuf_compiler.commands = $$quote($$PROTOC) --proto_path=$$quote($$PROTO_ROOT) --cpp_out=$$quote($$PROTO_GEN_DIR) $$quote($$PROTO_ROOT/cmvr/msgs/${QMAKE_FILE_BASE}.proto)
|
||||||
|
msg_protobuf_compiler.depends = $$MSG_PROTO_FILES
|
||||||
|
msg_protobuf_compiler.variable_out = SOURCES
|
||||||
|
msg_protobuf_compiler.CONFIG += target_predeps
|
||||||
|
|
||||||
|
config_protobuf_compiler.name = Protobuf ${QMAKE_FILE_IN}
|
||||||
|
config_protobuf_compiler.input = CONFIG_PROTO_FILES
|
||||||
|
config_protobuf_compiler.output = $$PROTO_GEN_DIR/cmvr/config/${QMAKE_FILE_BASE}/${QMAKE_FILE_BASE}.pb.cc
|
||||||
|
config_protobuf_compiler.commands = $$quote($$PROTOC) --proto_path=$$quote($$PROTO_ROOT) --cpp_out=$$quote($$PROTO_GEN_DIR) $$quote($$PWD/${QMAKE_FILE_IN})
|
||||||
|
config_protobuf_compiler.depends = $$CONFIG_PROTO_FILES
|
||||||
|
config_protobuf_compiler.variable_out = SOURCES
|
||||||
|
config_protobuf_compiler.CONFIG += target_predeps
|
||||||
|
|
||||||
|
config_root_protobuf_compiler.name = Protobuf ${QMAKE_FILE_IN}
|
||||||
|
config_root_protobuf_compiler.input = CONFIG_ROOT_PROTO_FILES
|
||||||
|
config_root_protobuf_compiler.output = $$PROTO_GEN_DIR/cmvr/config/${QMAKE_FILE_BASE}.pb.cc
|
||||||
|
config_root_protobuf_compiler.commands = $$quote($$PROTOC) --proto_path=$$quote($$PROTO_ROOT) --cpp_out=$$quote($$PROTO_GEN_DIR) $$quote($$PWD/${QMAKE_FILE_IN})
|
||||||
|
config_root_protobuf_compiler.depends = $$CONFIG_ROOT_PROTO_FILES $$COMMON_PROTO_FILES
|
||||||
|
config_root_protobuf_compiler.variable_out = SOURCES
|
||||||
|
config_root_protobuf_compiler.CONFIG += target_predeps
|
||||||
|
|
||||||
|
common_protobuf_compiler.name = Protobuf ${QMAKE_FILE_IN}
|
||||||
|
common_protobuf_compiler.input = COMMON_PROTO_FILES
|
||||||
|
common_protobuf_compiler.output = $$PROTO_GEN_DIR/cmvr/common/${QMAKE_FILE_BASE}.pb.cc
|
||||||
|
common_protobuf_compiler.commands = $$quote($$PROTOC) --proto_path=$$quote($$PROTO_ROOT) --cpp_out=$$quote($$PROTO_GEN_DIR) $$quote($$PWD/${QMAKE_FILE_IN})
|
||||||
|
common_protobuf_compiler.depends = $$COMMON_PROTO_FILES
|
||||||
|
common_protobuf_compiler.variable_out = SOURCES
|
||||||
|
common_protobuf_compiler.CONFIG += target_predeps
|
||||||
|
|
||||||
|
mujoco_protobuf_compiler.name = Protobuf ${QMAKE_FILE_IN}
|
||||||
|
mujoco_protobuf_compiler.input = MUJOCO_PROTO_FILES
|
||||||
|
mujoco_protobuf_compiler.output = $$PROTO_GEN_DIR/cmvr/config/mujoco_config/${QMAKE_FILE_BASE}.pb.cc
|
||||||
|
mujoco_protobuf_compiler.commands = $$quote($$PROTOC) --proto_path=$$quote($$PROTO_ROOT) --cpp_out=$$quote($$PROTO_GEN_DIR) $$quote($$PWD/${QMAKE_FILE_IN})
|
||||||
|
mujoco_protobuf_compiler.depends = $$MUJOCO_PROTO_FILES
|
||||||
|
mujoco_protobuf_compiler.variable_out = SOURCES
|
||||||
|
mujoco_protobuf_compiler.CONFIG += target_predeps
|
||||||
|
|
||||||
|
grpc_compiler.name = gRPC ${QMAKE_FILE_IN}
|
||||||
|
grpc_compiler.input = GRPC_PROTO_FILES
|
||||||
|
grpc_compiler.output = $$PROTO_GEN_DIR/cmvr/api/${QMAKE_FILE_BASE}.grpc.pb.cc
|
||||||
|
grpc_compiler.commands = $$quote($$PROTOC) --proto_path=$$quote($$PROTO_ROOT) --grpc_out=$$quote($$PROTO_GEN_DIR) --plugin=protoc-gen-grpc=$$quote($$GRPC_CPP_PLUGIN) $$quote($$PROTO_ROOT/cmvr/api/${QMAKE_FILE_BASE}.proto)
|
||||||
|
grpc_compiler.depends = $$PROTO_FILES $$MSG_PROTO_FILES
|
||||||
|
grpc_compiler.variable_out = SOURCES
|
||||||
|
grpc_compiler.CONFIG += target_predeps
|
||||||
|
|
||||||
|
quic_protobuf_compiler.name = Protobuf ${QMAKE_FILE_IN}
|
||||||
|
quic_protobuf_compiler.input = QUIC_PROTO_FILES
|
||||||
|
quic_protobuf_compiler.output = $$PROTO_GEN_DIR/cmvr/quic_edge/v1/${QMAKE_FILE_BASE}.pb.cc
|
||||||
|
quic_protobuf_compiler.commands = $$quote($$PROTOC) --proto_path=$$quote($$PROTO_ROOT) --cpp_out=$$quote($$PROTO_GEN_DIR) $$quote($$PROTO_ROOT/cmvr/quic_edge/v1/${QMAKE_FILE_BASE}.proto)
|
||||||
|
quic_protobuf_compiler.depends = $$QUIC_PROTO_FILES
|
||||||
|
quic_protobuf_compiler.variable_out = SOURCES
|
||||||
|
quic_protobuf_compiler.CONFIG += target_predeps
|
||||||
|
|
||||||
|
QMAKE_EXTRA_COMPILERS += protobuf_compiler msg_protobuf_compiler config_protobuf_compiler config_root_protobuf_compiler common_protobuf_compiler mujoco_protobuf_compiler grpc_compiler quic_protobuf_compiler
|
||||||
|
|
||||||
|
ABSL_STATIC_LIBS = $$files($$LIB_DIR/libabsl_*.a)
|
||||||
|
LIBS += \
|
||||||
|
-Wl,--start-group \
|
||||||
|
$$LIB_DIR/libgrpc++.a \
|
||||||
|
$$LIB_DIR/libgrpc.a \
|
||||||
|
$$LIB_DIR/libgpr.a \
|
||||||
|
$$LIB_DIR/libaddress_sorting.a \
|
||||||
|
$$LIB_DIR/libre2.a \
|
||||||
|
$$LIB_DIR/libupb.a \
|
||||||
|
$$LIB_DIR/libcares.a \
|
||||||
|
$$LIB_DIR/libssl.a \
|
||||||
|
$$LIB_DIR/libcrypto.a \
|
||||||
|
$$LIB_DIR/libzlibstatic.a \
|
||||||
|
$$LIB_DIR/libprotobuf.a \
|
||||||
|
$$ABSL_STATIC_LIBS \
|
||||||
|
-Wl,--end-group \
|
||||||
|
$$LIB_DIR/libavcodec.dll.a \
|
||||||
|
$$LIB_DIR/libavutil.dll.a \
|
||||||
|
$$LIB_DIR/libswscale.dll.a \
|
||||||
|
$$LIB_DIR/liburdfdom_model.dll.a \
|
||||||
|
-lws2_32 \
|
||||||
|
-lcrypt32 \
|
||||||
|
-ladvapi32 \
|
||||||
|
-lbcrypt \
|
||||||
|
-ldbghelp \
|
||||||
|
-liphlpapi \
|
||||||
|
-lsecur32 \
|
||||||
|
-lntdll
|
||||||
|
|
||||||
|
DEFINES += CMVR_WITH_GRPC=1
|
||||||
|
|
||||||
|
CONFIG(debug, debug|release) {
|
||||||
|
TARGET = CmvrControlStation_d
|
||||||
|
DESTDIR = $$clean_path($$PWD/bin/debug)
|
||||||
|
OBJECTS_DIR = build/debug/obj
|
||||||
|
MOC_DIR = build/debug/moc
|
||||||
|
RCC_DIR = build/debug/rcc
|
||||||
|
UI_DIR = build/debug/ui
|
||||||
|
DEFINES += CMVR_DEBUG_BUILD
|
||||||
|
ASSIMP_SCENE_PARSER = $$QT_SCENEPARSER_DIR/assimpsceneimportd.dll
|
||||||
|
} else {
|
||||||
|
TARGET = CmvrControlStation
|
||||||
|
DESTDIR = $$clean_path($$PWD/bin/release)
|
||||||
|
OBJECTS_DIR = build/release/obj
|
||||||
|
MOC_DIR = build/release/moc
|
||||||
|
RCC_DIR = build/release/rcc
|
||||||
|
UI_DIR = build/release/ui
|
||||||
|
DEFINES += NDEBUG
|
||||||
|
ASSIMP_SCENE_PARSER = $$QT_SCENEPARSER_DIR/assimpsceneimport.dll
|
||||||
|
}
|
||||||
|
|
||||||
|
!exists($$ASSIMP_SCENE_PARSER): error("Qt3D Assimp scene parser not found in the selected Qt Kit.")
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
src/audiostreammanager.cpp \
|
||||||
|
src/configeditorwidget.cpp \
|
||||||
|
src/main.cpp \
|
||||||
|
src/mainwindow.cpp \
|
||||||
|
src/mainwindow_ui.cpp \
|
||||||
|
src/quictestserver.cpp \
|
||||||
|
src/rpcservicewidget.cpp \
|
||||||
|
src/robotclient.cpp \
|
||||||
|
src/trendwidget.cpp \
|
||||||
|
src/urdfviewerwidget.cpp \
|
||||||
|
src/videodecoder.cpp \
|
||||||
|
src/videorenderwidget.cpp \
|
||||||
|
ui/handeyecalibrationwidget.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
src/audiostreammanager.h \
|
||||||
|
src/configeditorwidget.h \
|
||||||
|
src/mainwindow.h \
|
||||||
|
src/quictestserver.h \
|
||||||
|
src/rpcservicewidget.h \
|
||||||
|
src/robotclient.h \
|
||||||
|
src/trendwidget.h \
|
||||||
|
src/uiicons.h \
|
||||||
|
src/urdfviewerwidget.h \
|
||||||
|
src/videodecoder.h \
|
||||||
|
src/videoframe.h \
|
||||||
|
src/videorenderwidget.h \
|
||||||
|
ui/handeyecalibrationwidget.h
|
||||||
|
|
||||||
|
FORMS += \
|
||||||
|
ui/handeyecalibrationwidget.ui \
|
||||||
|
ui/mainwindow.ui \
|
||||||
|
ui/systemservicepage.ui \
|
||||||
|
ui/armservicepage.ui \
|
||||||
|
ui/cameraservicepage.ui \
|
||||||
|
ui/agvservicepage.ui \
|
||||||
|
ui/agvstatusdialog.ui \
|
||||||
|
ui/audioservicepage.ui \
|
||||||
|
ui/quicserverpage.ui \
|
||||||
|
ui/diagnosticspage.ui \
|
||||||
|
ui/rpcservicewidget.ui
|
||||||
|
|
||||||
|
RESOURCES += resources.qrc
|
||||||
|
|
||||||
|
runtime_library_deployment.files = $$RUNTIME_DLLS
|
||||||
|
runtime_library_deployment.path = $$DESTDIR
|
||||||
|
quic_certificate_deployment.files = $$MSQUIC_TEST_CERT
|
||||||
|
quic_certificate_deployment.path = $$DESTDIR
|
||||||
|
quic_ca_deployment.files = $$MSQUIC_TEST_CA
|
||||||
|
quic_ca_deployment.path = $$DESTDIR
|
||||||
|
demo_urdf_deployment.files = $$DEMO_URDF
|
||||||
|
demo_urdf_deployment.path = $$DESTDIR/models
|
||||||
|
assimp_scene_parser_deployment.files = $$ASSIMP_SCENE_PARSER
|
||||||
|
assimp_scene_parser_deployment.path = $$DESTDIR/sceneparsers
|
||||||
|
COPIES += runtime_library_deployment quic_certificate_deployment quic_ca_deployment demo_urdf_deployment assimp_scene_parser_deployment
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
QMAKE_POST_LINK += $$QMAKE_COPY_FILE $$shell_quote($$shell_path($$MSQUIC_TEST_CERT)) $$shell_quote($$shell_path($$DESTDIR/quic-test-server.pfx))
|
||||||
|
QMAKE_POST_LINK += $$escape_expand(\n\t) $$QMAKE_COPY_FILE $$shell_quote($$shell_path($$MSQUIC_TEST_CA)) $$shell_quote($$shell_path($$DESTDIR/quic-test-ca.crt))
|
||||||
|
}
|
||||||
|
|
||||||
|
win32:RC_ICONS =
|
||||||
85
NATIVE_DEPS.md
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# Windows native dependencies
|
||||||
|
|
||||||
|
The project uses Qt 5.12.4 with its 64-bit MinGW 7.3 kit:
|
||||||
|
|
||||||
|
- Qt: `C:\Qt\Qt5.12.4\5.12.4\mingw73_64`
|
||||||
|
- Compiler: `C:\Qt\Qt5.12.4\Tools\mingw730_64`
|
||||||
|
- gRPC 1.48.4 and Protobuf 3.19.5
|
||||||
|
- FFmpeg 4.4.5 with H.264, H.265/HEVC and MJPEG decoders
|
||||||
|
- MsQuic 2.5.9 OpenSSL x64
|
||||||
|
- urdfdom 4.0.3
|
||||||
|
|
||||||
|
Do not use an MSVC, 32-bit, or different MinGW kit. The native libraries in
|
||||||
|
`lib` use the Qt MinGW 7.3 64-bit ABI.
|
||||||
|
|
||||||
|
## Project layout
|
||||||
|
|
||||||
|
The application build has no dependency on `third_party/install`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
include/ dependency headers
|
||||||
|
lib/ static libraries, import libraries and runtime DLLs
|
||||||
|
tools/ protoc.exe, grpc_cpp_plugin.exe and the protoc launcher
|
||||||
|
certs/ QUIC test certificate and CA
|
||||||
|
```
|
||||||
|
|
||||||
|
Both qmake and CMake link only from `lib`. qmake copies every `lib/*.dll` into
|
||||||
|
the selected executable directory (`bin/debug` or `bin/release`) during the
|
||||||
|
build. QUIC certificates and the demo URDF are deployed beside the executable
|
||||||
|
at the same time.
|
||||||
|
|
||||||
|
`tools/run_protoc.cmd` adds `lib` to the proto compiler process PATH. This lets
|
||||||
|
`protoc.exe` and `grpc_cpp_plugin.exe` load their MinGW runtime DLLs without
|
||||||
|
duplicating DLL files under `tools`.
|
||||||
|
|
||||||
|
## Rebuilding dependencies
|
||||||
|
|
||||||
|
The checked-in `include`, `lib`, `tools`, and `certs` directories are enough to
|
||||||
|
build the application. To rebuild all native dependencies from source, run:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell -ExecutionPolicy Bypass -File .\scripts\build_native_deps.ps1 -Jobs 4
|
||||||
|
```
|
||||||
|
|
||||||
|
The script creates a temporary `third_party` download/build/install tree and
|
||||||
|
then runs `scripts/stage_native_deps.ps1` to refresh the four project
|
||||||
|
directories above. `third_party` is ignored and can be removed after staging.
|
||||||
|
|
||||||
|
To refresh only the staged files from an existing install tree:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell -ExecutionPolicy Bypass -File .\scripts\stage_native_deps.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Qt Creator
|
||||||
|
|
||||||
|
Open `CmvrControlStation.pro`, select the Desktop Qt 5.12.4 MinGW 64-bit kit,
|
||||||
|
run qmake, and then rebuild. Debug and Release are kept separate:
|
||||||
|
|
||||||
|
```text
|
||||||
|
bin/debug/CmvrControlStation_d.exe
|
||||||
|
bin/release/CmvrControlStation.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
Proto sources are read from the project-local `protos` directory and generated
|
||||||
|
under `generated_cpp`. No file from `cmvr-es` or another source repository is
|
||||||
|
required during compilation.
|
||||||
|
|
||||||
|
## QUIC certificate
|
||||||
|
|
||||||
|
To generate a test server certificate containing the machine LAN address:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\scripts\install_msquic.ps1 -ServerIp 192.168.0.118
|
||||||
|
.\scripts\stage_native_deps.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
The client must trust `certs/quic-test-ca.crt`. The PFX password is
|
||||||
|
`cmvr-test`.
|
||||||
|
|
||||||
|
## Application deployment
|
||||||
|
|
||||||
|
The `.pro` file deploys native DLLs maintained in `lib`, including FFmpeg,
|
||||||
|
MsQuic, urdfdom, zlib, and the MinGW runtime. Qt framework DLLs and Qt plugins
|
||||||
|
remain owned by the selected Qt kit; use `windeployqt` when producing a
|
||||||
|
standalone distribution outside Qt Creator.
|
||||||
25
certs/quic-test-ca.crt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEKzCCApOgAwIBAgIUTtZCyKM8INYxZKkfwbKdpHKLjn4wDQYJKoZIhvcNAQEL
|
||||||
|
BQAwHTEbMBkGA1UEAwwSQ01WUiBRVUlDIExvY2FsIENBMB4XDTI2MDcyNDA2NDQy
|
||||||
|
MFoXDTM2MDcyMTA2NDQyMFowHTEbMBkGA1UEAwwSQ01WUiBRVUlDIExvY2FsIENB
|
||||||
|
MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAmq2rHldOobaemqNfWggS
|
||||||
|
OVj3inKy6AYjfgtcXUfKs48DDbpZ9gyEd/YPJXA8C2jGPXpxzgnc7a4UCUVQZ8ah
|
||||||
|
ddoJtFcC+Q6BgjeMVqUdUubu5Y9HpkfU3lvnp4KhzvOeFnkKtrCzYIPa2nK3zLc7
|
||||||
|
uCiuLlB+91KQSRXPFbc6N7H/EAfGmUHIwlZGysAkRN7b2TAoR4C7E96JLVtuUQsS
|
||||||
|
VtlEGpunSfuefFzeeZCMS6avLbB+a8Q6yUzLt6pqnheNsDB+jCCXodlJs5XS1AOB
|
||||||
|
W2GOpGFMj7dLoTD+eBIlAlrhWFcwKjzFmtp6LGl/Jy0O+E99X4TL72oNSOdTrO2O
|
||||||
|
iavXABz9IvWR2BrAyo5AKlTJqO6tmZw77iVti8jYi+HsXIVGQKMYwvv5k0jdHeIZ
|
||||||
|
FaDToUbFPP/zj0m8ZraMy+8eNAhScnx6Zs56fcncBuDti6pT+zKisjV1rH/sFvZY
|
||||||
|
wO1UvJlOEbvXrfYLPp58Aqe/toG2nV45a2Q4+x6AETV1AgMBAAGjYzBhMB0GA1Ud
|
||||||
|
DgQWBBRdHz+g2vVmqghDZi2kEHtZfoyHZzAfBgNVHSMEGDAWgBRdHz+g2vVmqghD
|
||||||
|
Zi2kEHtZfoyHZzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkq
|
||||||
|
hkiG9w0BAQsFAAOCAYEASuEoMFiVcg4iTMxO2kshFTJ6LIrqqGXBn+1j+yQ1ennG
|
||||||
|
mqPMo5fBOe/Kp3YWCnREQWu0+EEPEC9qWgIDOIm3v7ch4mZiW31GUOqae6bjprBe
|
||||||
|
er7ySElKGZ5GefKAq++we19A6WHnNxtNAT9BE1VSKUmkxEsnIkuwd+QMmQ9eaIRm
|
||||||
|
8RvzshWdUcyiBJg07sI3rPzPD/YpnfcYlAa2a0+oXJ3o3zlhdbs2S+9fIl+Y/zFN
|
||||||
|
wBaUV6ZNk0RFzOCA+jUq2jU5Y1pODcot3Mp2jCHzp4uTFyVqsoqc5USRB2TUILCP
|
||||||
|
acSbEjD9GnKaNU4miTcftnC85fnBAiZ5btZkXIs72ij+J3VW7QnbcFQG8bElngoR
|
||||||
|
mWizh6ByPQrsvyT0evJjdjpuOzILsVTAn64m0cYpnlR4g5orcEkIJHv4DzMhpXc2
|
||||||
|
CvpcWwk2vJrUuws/LGxDATTAcqtIUIxAkxffqUsdB/6j8fdykNCvXFwNh/uPcawd
|
||||||
|
4kzh6dr+RFzHSMQ6oN16
|
||||||
|
-----END CERTIFICATE-----
|
||||||
1
generated_cpp/.gitkeep
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
||||||
2
icons/activity.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide activity, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"/></svg>
|
||||||
|
After Width: | Height: | Size: 352 B |
2
icons/bot.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide bot, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 8V4H8"/><rect width="16" height="12" x="4" y="8" rx="2"/><path d="M2 14h2M20 14h2M15 13v2M9 13v2"/></svg>
|
||||||
|
After Width: | Height: | Size: 325 B |
2
icons/braces.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide braces, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1M16 21h1a2 2 0 0 0 2-2v-5c0-1.1.9-2 2-2a2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1"/></svg>
|
||||||
|
After Width: | Height: | Size: 368 B |
2
icons/camera.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide camera, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/><circle cx="12" cy="13" r="3"/></svg>
|
||||||
|
After Width: | Height: | Size: 349 B |
2
icons/check.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide check, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
|
||||||
|
After Width: | Height: | Size: 242 B |
2
icons/chevron-down.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide chevron-down, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#66727d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
|
||||||
|
After Width: | Height: | Size: 249 B |
2
icons/chevron-up.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide chevron-up, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#66727d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m18 15-6-6-6 6"/></svg>
|
||||||
|
After Width: | Height: | Size: 249 B |
2
icons/copy.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide copy, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>
|
||||||
|
After Width: | Height: | Size: 337 B |
2
icons/crosshair.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide crosshair, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M22 12h-4M6 12H2M12 6V2M12 22v-4"/></svg>
|
||||||
|
After Width: | Height: | Size: 295 B |
2
icons/folder-open.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide folder-open, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2"/></svg>
|
||||||
|
After Width: | Height: | Size: 410 B |
2
icons/hand.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide hand, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 11V6a2 2 0 0 0-4 0M14 10V4a2 2 0 0 0-4 0v2M10 10.5V6a2 2 0 0 0-4 0v8M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15"/></svg>
|
||||||
|
After Width: | Height: | Size: 395 B |
2
icons/maximize.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide maximize, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3M21 8V5a2 2 0 0 0-2-2h-3M3 16v3a2 2 0 0 0 2 2h3M16 21h3a2 2 0 0 0 2-2v-3"/></svg>
|
||||||
|
After Width: | Height: | Size: 324 B |
2
icons/mic.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide mic, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2M12 19v3"/></svg>
|
||||||
|
After Width: | Height: | Size: 323 B |
2
icons/minus.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide minus, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/></svg>
|
||||||
|
After Width: | Height: | Size: 235 B |
2
icons/move.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide move, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v20M15 19l-3 3-3-3M19 9l3 3-3 3M2 12h20M5 9l-3 3 3 3M9 5l3-3 3 3"/></svg>
|
||||||
|
After Width: | Height: | Size: 295 B |
2
icons/octagon-x.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide octagon-x, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 9-6 6M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586zM9 9l6 6"/></svg>
|
||||||
|
After Width: | Height: | Size: 482 B |
2
icons/play.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide play, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="6 3 20 12 6 21 6 3"/></svg>
|
||||||
|
After Width: | Height: | Size: 252 B |
2
icons/power-off.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide power-off, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18.36 6.64A9 9 0 0 1 20.77 15M6.16 6.16a9 9 0 1 0 12.68 12.68M12 2v4M2 2l20 20"/></svg>
|
||||||
|
After Width: | Height: | Size: 310 B |
2
icons/power.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide power, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v10M18.4 6.6a9 9 0 1 1-12.77.04"/></svg>
|
||||||
|
After Width: | Height: | Size: 263 B |
2
icons/radio-tower.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide radio-tower, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.9 16.1C1 12.2 1 5.8 4.9 1.9M7.8 4.7a6.14 6.14 0 0 0-.8 7.5"/><circle cx="12" cy="9" r="2"/><path d="M16.2 4.8c2 2 2.26 5.11.8 7.47M19.1 1.9a9.96 9.96 0 0 1 0 14.1M9.5 18h5M8 22l4-11 4 11"/></svg>
|
||||||
|
After Width: | Height: | Size: 422 B |
2
icons/rotate-ccw.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide rotate-ccw, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8M3 3v5h5"/></svg>
|
||||||
|
After Width: | Height: | Size: 289 B |
2
icons/scan-face.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide scan-face, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2M8 14s1.5 2 4 2 4-2 4-2M9 9h.01M15 9h.01"/></svg>
|
||||||
|
After Width: | Height: | Size: 365 B |
2
icons/scroll-text.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide scroll-text, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 12h-5M15 8h-5M19 17V5a2 2 0 0 0-2-2H4M8 21h12a2 2 0 0 0 2-2v-1a1 1 0 0 0-1-1H11a1 1 0 0 0-1 1v1a2 2 0 1 1-4 0V5a2 2 0 1 0-4 0v2a1 1 0 0 0 1 1h3"/></svg>
|
||||||
|
After Width: | Height: | Size: 380 B |
2
icons/send.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide send, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11zM21.854 2.147l-10.94 10.939"/></svg>
|
||||||
|
After Width: | Height: | Size: 380 B |
2
icons/shield-check.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide shield-check, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1zM9 12l2 2 4-4"/></svg>
|
||||||
|
After Width: | Height: | Size: 409 B |
2
icons/square.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide square, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"/></svg>
|
||||||
|
After Width: | Height: | Size: 265 B |
4
icons/toggle-off.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="44" height="24" viewBox="0 0 44 24">
|
||||||
|
<rect x="0" y="0" width="44" height="24" rx="12" fill="#cbd3dc"/>
|
||||||
|
<circle cx="12" cy="12" r="9" fill="#ffffff"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 208 B |
4
icons/toggle-on.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="44" height="24" viewBox="0 0 44 24">
|
||||||
|
<rect x="0" y="0" width="44" height="24" rx="12" fill="#2878f0"/>
|
||||||
|
<circle cx="32" cy="12" r="9" fill="#ffffff"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 208 B |
2
icons/undo-2.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide undo-2, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 14 4 9l5-5M4 9h10.5a5.5 5.5 0 0 1 0 11H11"/></svg>
|
||||||
|
After Width: | Height: | Size: 272 B |
2
icons/volume-2.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide volume-2, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z"/><path d="M16 9a5 5 0 0 1 0 6M19.364 18.364a9 9 0 0 0 0-12.728"/></svg>
|
||||||
|
After Width: | Height: | Size: 462 B |
2
icons/x.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<!-- Lucide x, ISC license -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg>
|
||||||
|
After Width: | Height: | Size: 243 B |
159
include/absl/algorithm/algorithm.h
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: algorithm.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header file contains Google extensions to the standard <algorithm> C++
|
||||||
|
// header.
|
||||||
|
|
||||||
|
#ifndef ABSL_ALGORITHM_ALGORITHM_H_
|
||||||
|
#define ABSL_ALGORITHM_ALGORITHM_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace algorithm_internal {
|
||||||
|
|
||||||
|
// Performs comparisons with operator==, similar to C++14's `std::equal_to<>`.
|
||||||
|
struct EqualTo {
|
||||||
|
template <typename T, typename U>
|
||||||
|
bool operator()(const T& a, const U& b) const {
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename InputIter1, typename InputIter2, typename Pred>
|
||||||
|
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
||||||
|
InputIter2 last2, Pred pred, std::input_iterator_tag,
|
||||||
|
std::input_iterator_tag) {
|
||||||
|
while (true) {
|
||||||
|
if (first1 == last1) return first2 == last2;
|
||||||
|
if (first2 == last2) return false;
|
||||||
|
if (!pred(*first1, *first2)) return false;
|
||||||
|
++first1;
|
||||||
|
++first2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputIter1, typename InputIter2, typename Pred>
|
||||||
|
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
||||||
|
InputIter2 last2, Pred&& pred, std::random_access_iterator_tag,
|
||||||
|
std::random_access_iterator_tag) {
|
||||||
|
return (last1 - first1 == last2 - first2) &&
|
||||||
|
std::equal(first1, last1, first2, std::forward<Pred>(pred));
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we are using our own internal predicate that just applies operator==, we
|
||||||
|
// forward to the non-predicate form of std::equal. This enables an optimization
|
||||||
|
// in libstdc++ that can result in std::memcmp being used for integer types.
|
||||||
|
template <typename InputIter1, typename InputIter2>
|
||||||
|
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
||||||
|
InputIter2 last2, algorithm_internal::EqualTo /* unused */,
|
||||||
|
std::random_access_iterator_tag,
|
||||||
|
std::random_access_iterator_tag) {
|
||||||
|
return (last1 - first1 == last2 - first2) &&
|
||||||
|
std::equal(first1, last1, first2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename It>
|
||||||
|
It RotateImpl(It first, It middle, It last, std::true_type) {
|
||||||
|
return std::rotate(first, middle, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename It>
|
||||||
|
It RotateImpl(It first, It middle, It last, std::false_type) {
|
||||||
|
std::rotate(first, middle, last);
|
||||||
|
return std::next(first, std::distance(middle, last));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace algorithm_internal
|
||||||
|
|
||||||
|
// equal()
|
||||||
|
//
|
||||||
|
// Compares the equality of two ranges specified by pairs of iterators, using
|
||||||
|
// the given predicate, returning true iff for each corresponding iterator i1
|
||||||
|
// and i2 in the first and second range respectively, pred(*i1, *i2) == true
|
||||||
|
//
|
||||||
|
// This comparison takes at most min(`last1` - `first1`, `last2` - `first2`)
|
||||||
|
// invocations of the predicate. Additionally, if InputIter1 and InputIter2 are
|
||||||
|
// both random-access iterators, and `last1` - `first1` != `last2` - `first2`,
|
||||||
|
// then the predicate is never invoked and the function returns false.
|
||||||
|
//
|
||||||
|
// This is a C++11-compatible implementation of C++14 `std::equal`. See
|
||||||
|
// https://en.cppreference.com/w/cpp/algorithm/equal for more information.
|
||||||
|
template <typename InputIter1, typename InputIter2, typename Pred>
|
||||||
|
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
||||||
|
InputIter2 last2, Pred&& pred) {
|
||||||
|
return algorithm_internal::EqualImpl(
|
||||||
|
first1, last1, first2, last2, std::forward<Pred>(pred),
|
||||||
|
typename std::iterator_traits<InputIter1>::iterator_category{},
|
||||||
|
typename std::iterator_traits<InputIter2>::iterator_category{});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of equal() that performs comparison of two ranges specified by pairs
|
||||||
|
// of iterators using operator==.
|
||||||
|
template <typename InputIter1, typename InputIter2>
|
||||||
|
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
||||||
|
InputIter2 last2) {
|
||||||
|
return absl::equal(first1, last1, first2, last2,
|
||||||
|
algorithm_internal::EqualTo{});
|
||||||
|
}
|
||||||
|
|
||||||
|
// linear_search()
|
||||||
|
//
|
||||||
|
// Performs a linear search for `value` using the iterator `first` up to
|
||||||
|
// but not including `last`, returning true if [`first`, `last`) contains an
|
||||||
|
// element equal to `value`.
|
||||||
|
//
|
||||||
|
// A linear search is of O(n) complexity which is guaranteed to make at most
|
||||||
|
// n = (`last` - `first`) comparisons. A linear search over short containers
|
||||||
|
// may be faster than a binary search, even when the container is sorted.
|
||||||
|
template <typename InputIterator, typename EqualityComparable>
|
||||||
|
bool linear_search(InputIterator first, InputIterator last,
|
||||||
|
const EqualityComparable& value) {
|
||||||
|
return std::find(first, last, value) != last;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotate()
|
||||||
|
//
|
||||||
|
// Performs a left rotation on a range of elements (`first`, `last`) such that
|
||||||
|
// `middle` is now the first element. `rotate()` returns an iterator pointing to
|
||||||
|
// the first element before rotation. This function is exactly the same as
|
||||||
|
// `std::rotate`, but fixes a bug in gcc
|
||||||
|
// <= 4.9 where `std::rotate` returns `void` instead of an iterator.
|
||||||
|
//
|
||||||
|
// The complexity of this algorithm is the same as that of `std::rotate`, but if
|
||||||
|
// `ForwardIterator` is not a random-access iterator, then `absl::rotate`
|
||||||
|
// performs an additional pass over the range to construct the return value.
|
||||||
|
template <typename ForwardIterator>
|
||||||
|
ForwardIterator rotate(ForwardIterator first, ForwardIterator middle,
|
||||||
|
ForwardIterator last) {
|
||||||
|
return algorithm_internal::RotateImpl(
|
||||||
|
first, middle, last,
|
||||||
|
std::is_same<decltype(std::rotate(first, middle, last)),
|
||||||
|
ForwardIterator>());
|
||||||
|
}
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_ALGORITHM_ALGORITHM_H_
|
||||||
1774
include/absl/algorithm/container.h
Normal file
762
include/absl/base/attributes.h
Normal file
@ -0,0 +1,762 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// This header file defines macros for declaring attributes for functions,
|
||||||
|
// types, and variables.
|
||||||
|
//
|
||||||
|
// These macros are used within Abseil and allow the compiler to optimize, where
|
||||||
|
// applicable, certain function calls.
|
||||||
|
//
|
||||||
|
// Most macros here are exposing GCC or Clang features, and are stubbed out for
|
||||||
|
// other compilers.
|
||||||
|
//
|
||||||
|
// GCC attributes documentation:
|
||||||
|
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
|
||||||
|
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html
|
||||||
|
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html
|
||||||
|
//
|
||||||
|
// Most attributes in this file are already supported by GCC 4.7. However, some
|
||||||
|
// of them are not supported in older version of Clang. Thus, we check
|
||||||
|
// `__has_attribute()` first. If the check fails, we check if we are on GCC and
|
||||||
|
// assume the attribute exists on GCC (which is verified on GCC 4.7).
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_ATTRIBUTES_H_
|
||||||
|
#define ABSL_BASE_ATTRIBUTES_H_
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
// ABSL_HAVE_ATTRIBUTE
|
||||||
|
//
|
||||||
|
// A function-like feature checking macro that is a wrapper around
|
||||||
|
// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
|
||||||
|
// nonzero constant integer if the attribute is supported or 0 if not.
|
||||||
|
//
|
||||||
|
// It evaluates to zero if `__has_attribute` is not defined by the compiler.
|
||||||
|
//
|
||||||
|
// GCC: https://gcc.gnu.org/gcc-5/changes.html
|
||||||
|
// Clang: https://clang.llvm.org/docs/LanguageExtensions.html
|
||||||
|
#ifdef __has_attribute
|
||||||
|
#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
|
||||||
|
#else
|
||||||
|
#define ABSL_HAVE_ATTRIBUTE(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_CPP_ATTRIBUTE
|
||||||
|
//
|
||||||
|
// A function-like feature checking macro that accepts C++11 style attributes.
|
||||||
|
// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
|
||||||
|
// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
|
||||||
|
// find `__has_cpp_attribute`, will evaluate to 0.
|
||||||
|
#if defined(__cplusplus) && defined(__has_cpp_attribute)
|
||||||
|
// NOTE: requiring __cplusplus above should not be necessary, but
|
||||||
|
// works around https://bugs.llvm.org/show_bug.cgi?id=23435.
|
||||||
|
#define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
|
||||||
|
#else
|
||||||
|
#define ABSL_HAVE_CPP_ATTRIBUTE(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Function Attributes
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
||||||
|
// Clang: https://clang.llvm.org/docs/AttributeReference.html
|
||||||
|
|
||||||
|
// ABSL_PRINTF_ATTRIBUTE
|
||||||
|
// ABSL_SCANF_ATTRIBUTE
|
||||||
|
//
|
||||||
|
// Tells the compiler to perform `printf` format string checking if the
|
||||||
|
// compiler supports it; see the 'format' attribute in
|
||||||
|
// <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
|
||||||
|
//
|
||||||
|
// Note: As the GCC manual states, "[s]ince non-static C++ methods
|
||||||
|
// have an implicit 'this' argument, the arguments of such methods
|
||||||
|
// should be counted from two, not one."
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
|
||||||
|
__attribute__((__format__(__printf__, string_index, first_to_check)))
|
||||||
|
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \
|
||||||
|
__attribute__((__format__(__scanf__, string_index, first_to_check)))
|
||||||
|
#else
|
||||||
|
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check)
|
||||||
|
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_ALWAYS_INLINE
|
||||||
|
// ABSL_ATTRIBUTE_NOINLINE
|
||||||
|
//
|
||||||
|
// Forces functions to either inline or not inline. Introduced in gcc 3.1.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(always_inline) || \
|
||||||
|
(defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
|
||||||
|
#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_ALWAYS_INLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline))
|
||||||
|
#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_NOINLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_NO_TAIL_CALL
|
||||||
|
//
|
||||||
|
// Prevents the compiler from optimizing away stack frames for functions which
|
||||||
|
// end in a call to another function.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
|
||||||
|
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
|
||||||
|
#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
|
||||||
|
#elif defined(__GNUC__) && !defined(__clang__) && !defined(__e2k__)
|
||||||
|
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
|
||||||
|
#define ABSL_ATTRIBUTE_NO_TAIL_CALL \
|
||||||
|
__attribute__((optimize("no-optimize-sibling-calls")))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_NO_TAIL_CALL
|
||||||
|
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_WEAK
|
||||||
|
//
|
||||||
|
// Tags a function as weak for the purposes of compilation and linking.
|
||||||
|
// Weak attributes did not work properly in LLVM's Windows backend before
|
||||||
|
// 9.0.0, so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
|
||||||
|
// for further information.
|
||||||
|
// The MinGW compiler doesn't complain about the weak attribute until the link
|
||||||
|
// step, presumably because Windows doesn't use ELF binaries.
|
||||||
|
#if (ABSL_HAVE_ATTRIBUTE(weak) || \
|
||||||
|
(defined(__GNUC__) && !defined(__clang__))) && \
|
||||||
|
(!defined(_WIN32) || (defined(__clang__) && __clang_major__ >= 9)) && \
|
||||||
|
!defined(__MINGW32__)
|
||||||
|
#undef ABSL_ATTRIBUTE_WEAK
|
||||||
|
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
|
||||||
|
#define ABSL_HAVE_ATTRIBUTE_WEAK 1
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_WEAK
|
||||||
|
#define ABSL_HAVE_ATTRIBUTE_WEAK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_NONNULL
|
||||||
|
//
|
||||||
|
// Tells the compiler either (a) that a particular function parameter
|
||||||
|
// should be a non-null pointer, or (b) that all pointer arguments should
|
||||||
|
// be non-null.
|
||||||
|
//
|
||||||
|
// Note: As the GCC manual states, "[s]ince non-static C++ methods
|
||||||
|
// have an implicit 'this' argument, the arguments of such methods
|
||||||
|
// should be counted from two, not one."
|
||||||
|
//
|
||||||
|
// Args are indexed starting at 1.
|
||||||
|
//
|
||||||
|
// For non-static class member functions, the implicit `this` argument
|
||||||
|
// is arg 1, and the first explicit argument is arg 2. For static class member
|
||||||
|
// functions, there is no implicit `this`, and the first explicit argument is
|
||||||
|
// arg 1.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// /* arg_a cannot be null, but arg_b can */
|
||||||
|
// void Function(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(1);
|
||||||
|
//
|
||||||
|
// class C {
|
||||||
|
// /* arg_a cannot be null, but arg_b can */
|
||||||
|
// void Method(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(2);
|
||||||
|
//
|
||||||
|
// /* arg_a cannot be null, but arg_b can */
|
||||||
|
// static void StaticMethod(void* arg_a, void* arg_b)
|
||||||
|
// ABSL_ATTRIBUTE_NONNULL(1);
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// If no arguments are provided, then all pointer arguments should be non-null.
|
||||||
|
//
|
||||||
|
// /* No pointer arguments may be null. */
|
||||||
|
// void Function(void* arg_a, void* arg_b, int arg_c) ABSL_ATTRIBUTE_NONNULL();
|
||||||
|
//
|
||||||
|
// NOTE: The GCC nonnull attribute actually accepts a list of arguments, but
|
||||||
|
// ABSL_ATTRIBUTE_NONNULL does not.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_NONNULL(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_NORETURN
|
||||||
|
//
|
||||||
|
// Tells the compiler that a given function never returns.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn)
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_NORETURN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||||
|
//
|
||||||
|
// Tells the AddressSanitizer (or other memory testing tools) to ignore a given
|
||||||
|
// function. Useful for cases when a function reads random locations on stack,
|
||||||
|
// calls _exit from a cloned subprocess, deliberately accesses buffer
|
||||||
|
// out of bounds or does other scary things with memory.
|
||||||
|
// NOTE: GCC supports AddressSanitizer(asan) since 4.8.
|
||||||
|
// https://gcc.gnu.org/gcc-4.8/changes.html
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_address)
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
|
||||||
|
#elif defined(_MSC_VER) && _MSC_VER >= 1928
|
||||||
|
// https://docs.microsoft.com/en-us/cpp/cpp/no-sanitize-address
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __declspec(no_sanitize_address)
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
|
||||||
|
//
|
||||||
|
// Tells the MemorySanitizer to relax the handling of a given function. All "Use
|
||||||
|
// of uninitialized value" warnings from such functions will be suppressed, and
|
||||||
|
// all values loaded from memory will be considered fully initialized. This
|
||||||
|
// attribute is similar to the ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS attribute
|
||||||
|
// above, but deals with initialized-ness rather than addressability issues.
|
||||||
|
// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory)
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
|
||||||
|
//
|
||||||
|
// Tells the ThreadSanitizer to not instrument a given function.
|
||||||
|
// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
|
||||||
|
// https://gcc.gnu.org/gcc-4.8/changes.html
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread)
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
||||||
|
//
|
||||||
|
// Tells the UndefinedSanitizer to ignore a given function. Useful for cases
|
||||||
|
// where certain behavior (eg. division by zero) is being used intentionally.
|
||||||
|
// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
|
||||||
|
// https://gcc.gnu.org/gcc-4.9/changes.html
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_undefined)
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
|
||||||
|
__attribute__((no_sanitize_undefined))
|
||||||
|
#elif ABSL_HAVE_ATTRIBUTE(no_sanitize)
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
|
||||||
|
__attribute__((no_sanitize("undefined")))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_NO_SANITIZE_CFI
|
||||||
|
//
|
||||||
|
// Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
|
||||||
|
// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
|
||||||
|
//
|
||||||
|
// Tells the SafeStack to not instrument a given function.
|
||||||
|
// See https://clang.llvm.org/docs/SafeStack.html for details.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
|
||||||
|
__attribute__((no_sanitize("safe-stack")))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_RETURNS_NONNULL
|
||||||
|
//
|
||||||
|
// Tells the compiler that a particular function never returns a null pointer.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(returns_nonnull)
|
||||||
|
#define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_RETURNS_NONNULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_ATTRIBUTE_SECTION
|
||||||
|
//
|
||||||
|
// Indicates whether labeled sections are supported. Weak symbol support is
|
||||||
|
// a prerequisite. Labeled sections are not supported on Darwin/iOS.
|
||||||
|
#ifdef ABSL_HAVE_ATTRIBUTE_SECTION
|
||||||
|
#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set
|
||||||
|
#elif (ABSL_HAVE_ATTRIBUTE(section) || \
|
||||||
|
(defined(__GNUC__) && !defined(__clang__))) && \
|
||||||
|
!defined(__APPLE__) && ABSL_HAVE_ATTRIBUTE_WEAK
|
||||||
|
#define ABSL_HAVE_ATTRIBUTE_SECTION 1
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_SECTION
|
||||||
|
//
|
||||||
|
// Tells the compiler/linker to put a given function into a section and define
|
||||||
|
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
|
||||||
|
// This functionality is supported by GNU linker. Any function annotated with
|
||||||
|
// `ABSL_ATTRIBUTE_SECTION` must not be inlined, or it will be placed into
|
||||||
|
// whatever section its caller is placed into.
|
||||||
|
//
|
||||||
|
#ifndef ABSL_ATTRIBUTE_SECTION
|
||||||
|
#define ABSL_ATTRIBUTE_SECTION(name) \
|
||||||
|
__attribute__((section(#name))) __attribute__((noinline))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_SECTION_VARIABLE
|
||||||
|
//
|
||||||
|
// Tells the compiler/linker to put a given variable into a section and define
|
||||||
|
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
|
||||||
|
// This functionality is supported by GNU linker.
|
||||||
|
#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE
|
||||||
|
#ifdef _AIX
|
||||||
|
// __attribute__((section(#name))) on AIX is achived by using the `.csect` psudo
|
||||||
|
// op which includes an additional integer as part of its syntax indcating
|
||||||
|
// alignment. If data fall under different alignments then you might get a
|
||||||
|
// compilation error indicating a `Section type conflict`.
|
||||||
|
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
|
||||||
|
//
|
||||||
|
// A weak section declaration to be used as a global declaration
|
||||||
|
// for ABSL_ATTRIBUTE_SECTION_START|STOP(name) to compile and link
|
||||||
|
// even without functions with ABSL_ATTRIBUTE_SECTION(name).
|
||||||
|
// ABSL_DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's
|
||||||
|
// a no-op on ELF but not on Mach-O.
|
||||||
|
//
|
||||||
|
#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
|
||||||
|
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
|
||||||
|
extern char __start_##name[] ABSL_ATTRIBUTE_WEAK; \
|
||||||
|
extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK
|
||||||
|
#endif
|
||||||
|
#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS
|
||||||
|
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
|
||||||
|
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_SECTION_START
|
||||||
|
//
|
||||||
|
// Returns `void*` pointers to start/end of a section of code with
|
||||||
|
// functions having ABSL_ATTRIBUTE_SECTION(name).
|
||||||
|
// Returns 0 if no such functions exist.
|
||||||
|
// One must ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and
|
||||||
|
// link.
|
||||||
|
//
|
||||||
|
#define ABSL_ATTRIBUTE_SECTION_START(name) \
|
||||||
|
(reinterpret_cast<void *>(__start_##name))
|
||||||
|
#define ABSL_ATTRIBUTE_SECTION_STOP(name) \
|
||||||
|
(reinterpret_cast<void *>(__stop_##name))
|
||||||
|
|
||||||
|
#else // !ABSL_HAVE_ATTRIBUTE_SECTION
|
||||||
|
|
||||||
|
#define ABSL_HAVE_ATTRIBUTE_SECTION 0
|
||||||
|
|
||||||
|
// provide dummy definitions
|
||||||
|
#define ABSL_ATTRIBUTE_SECTION(name)
|
||||||
|
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
|
||||||
|
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
|
||||||
|
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
|
||||||
|
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name)
|
||||||
|
#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
|
||||||
|
#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
|
||||||
|
|
||||||
|
#endif // ABSL_ATTRIBUTE_SECTION
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
||||||
|
//
|
||||||
|
// Support for aligning the stack on 32-bit x86.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || \
|
||||||
|
(defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#if defined(__i386__)
|
||||||
|
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \
|
||||||
|
__attribute__((force_align_arg_pointer))
|
||||||
|
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
|
||||||
|
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
||||||
|
#else // !__i386__ && !__x86_64
|
||||||
|
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
||||||
|
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
||||||
|
#endif // __i386__
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
||||||
|
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_MUST_USE_RESULT
|
||||||
|
//
|
||||||
|
// Tells the compiler to warn about unused results.
|
||||||
|
//
|
||||||
|
// For code or headers that are assured to only build with C++17 and up, prefer
|
||||||
|
// just using the standard `[[nodiscard]]` directly over this macro.
|
||||||
|
//
|
||||||
|
// When annotating a function, it must appear as the first part of the
|
||||||
|
// declaration or definition. The compiler will warn if the return value from
|
||||||
|
// such a function is unused:
|
||||||
|
//
|
||||||
|
// ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket();
|
||||||
|
// AllocateSprocket(); // Triggers a warning.
|
||||||
|
//
|
||||||
|
// When annotating a class, it is equivalent to annotating every function which
|
||||||
|
// returns an instance.
|
||||||
|
//
|
||||||
|
// class ABSL_MUST_USE_RESULT Sprocket {};
|
||||||
|
// Sprocket(); // Triggers a warning.
|
||||||
|
//
|
||||||
|
// Sprocket MakeSprocket();
|
||||||
|
// MakeSprocket(); // Triggers a warning.
|
||||||
|
//
|
||||||
|
// Note that references and pointers are not instances:
|
||||||
|
//
|
||||||
|
// Sprocket* SprocketPointer();
|
||||||
|
// SprocketPointer(); // Does *not* trigger a warning.
|
||||||
|
//
|
||||||
|
// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result
|
||||||
|
// warning. For that, warn_unused_result is used only for clang but not for gcc.
|
||||||
|
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
|
||||||
|
//
|
||||||
|
// Note: past advice was to place the macro after the argument list.
|
||||||
|
//
|
||||||
|
// TODO(b/176172494): Use ABSL_HAVE_CPP_ATTRIBUTE(nodiscard) when all code is
|
||||||
|
// compliant with the stricter [[nodiscard]].
|
||||||
|
#if defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
|
||||||
|
#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
|
||||||
|
#else
|
||||||
|
#define ABSL_MUST_USE_RESULT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD
|
||||||
|
//
|
||||||
|
// Tells GCC that a function is hot or cold. GCC can use this information to
|
||||||
|
// improve static analysis, i.e. a conditional branch to a cold function
|
||||||
|
// is likely to be not-taken.
|
||||||
|
// This annotation is used for function declarations.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// int foo() ABSL_ATTRIBUTE_HOT;
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_ATTRIBUTE_HOT __attribute__((hot))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_HOT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_ATTRIBUTE_COLD __attribute__((cold))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_COLD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS
|
||||||
|
//
|
||||||
|
// We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT
|
||||||
|
// macro used as an attribute to mark functions that must always or never be
|
||||||
|
// instrumented by XRay. Currently, this is only supported in Clang/LLVM.
|
||||||
|
//
|
||||||
|
// For reference on the LLVM XRay instrumentation, see
|
||||||
|
// http://llvm.org/docs/XRay.html.
|
||||||
|
//
|
||||||
|
// A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration
|
||||||
|
// will always get the XRay instrumentation sleds. These sleds may introduce
|
||||||
|
// some binary size and runtime overhead and must be used sparingly.
|
||||||
|
//
|
||||||
|
// These attributes only take effect when the following conditions are met:
|
||||||
|
//
|
||||||
|
// * The file/target is built in at least C++11 mode, with a Clang compiler
|
||||||
|
// that supports XRay attributes.
|
||||||
|
// * The file/target is built with the -fxray-instrument flag set for the
|
||||||
|
// Clang/LLVM compiler.
|
||||||
|
// * The function is defined in the translation unit (the compiler honors the
|
||||||
|
// attribute in either the definition or the declaration, and must match).
|
||||||
|
//
|
||||||
|
// There are cases when, even when building with XRay instrumentation, users
|
||||||
|
// might want to control specifically which functions are instrumented for a
|
||||||
|
// particular build using special-case lists provided to the compiler. These
|
||||||
|
// special case lists are provided to Clang via the
|
||||||
|
// -fxray-always-instrument=... and -fxray-never-instrument=... flags. The
|
||||||
|
// attributes in source take precedence over these special-case lists.
|
||||||
|
//
|
||||||
|
// To disable the XRay attributes at build-time, users may define
|
||||||
|
// ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific
|
||||||
|
// packages/targets, as this may lead to conflicting definitions of functions at
|
||||||
|
// link-time.
|
||||||
|
//
|
||||||
|
// XRay isn't currently supported on Android:
|
||||||
|
// https://github.com/android/ndk/issues/368
|
||||||
|
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
|
||||||
|
!defined(ABSL_NO_XRAY_ATTRIBUTES) && !defined(__ANDROID__)
|
||||||
|
#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
|
||||||
|
#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
|
||||||
|
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
|
||||||
|
#define ABSL_XRAY_LOG_ARGS(N) \
|
||||||
|
[[clang::xray_always_instrument, clang::xray_log_args(N)]]
|
||||||
|
#else
|
||||||
|
#define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]]
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define ABSL_XRAY_ALWAYS_INSTRUMENT
|
||||||
|
#define ABSL_XRAY_NEVER_INSTRUMENT
|
||||||
|
#define ABSL_XRAY_LOG_ARGS(N)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_REINITIALIZES
|
||||||
|
//
|
||||||
|
// Indicates that a member function reinitializes the entire object to a known
|
||||||
|
// state, independent of the previous state of the object.
|
||||||
|
//
|
||||||
|
// The clang-tidy check bugprone-use-after-move allows member functions marked
|
||||||
|
// with this attribute to be called on objects that have been moved from;
|
||||||
|
// without the attribute, this would result in a use-after-move warning.
|
||||||
|
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::reinitializes)
|
||||||
|
#define ABSL_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_REINITIALIZES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Variable Attributes
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_UNUSED
|
||||||
|
//
|
||||||
|
// Prevents the compiler from complaining about variables that appear unused.
|
||||||
|
//
|
||||||
|
// For code or headers that are assured to only build with C++17 and up, prefer
|
||||||
|
// just using the standard '[[maybe_unused]]' directly over this macro.
|
||||||
|
//
|
||||||
|
// Due to differences in positioning requirements between the old, compiler
|
||||||
|
// specific __attribute__ syntax and the now standard [[maybe_unused]], this
|
||||||
|
// macro does not attempt to take advantage of '[[maybe_unused]]'.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#undef ABSL_ATTRIBUTE_UNUSED
|
||||||
|
#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_UNUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_INITIAL_EXEC
|
||||||
|
//
|
||||||
|
// Tells the compiler to use "initial-exec" mode for a thread-local variable.
|
||||||
|
// See http://people.redhat.com/drepper/tls.pdf for the gory details.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_INITIAL_EXEC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_PACKED
|
||||||
|
//
|
||||||
|
// Instructs the compiler not to use natural alignment for a tagged data
|
||||||
|
// structure, but instead to reduce its alignment to 1.
|
||||||
|
//
|
||||||
|
// Therefore, DO NOT APPLY THIS ATTRIBUTE TO STRUCTS CONTAINING ATOMICS. Doing
|
||||||
|
// so can cause atomic variables to be mis-aligned and silently violate
|
||||||
|
// atomicity on x86.
|
||||||
|
//
|
||||||
|
// This attribute can either be applied to members of a structure or to a
|
||||||
|
// structure in its entirety. Applying this attribute (judiciously) to a
|
||||||
|
// structure in its entirety to optimize the memory footprint of very
|
||||||
|
// commonly-used structs is fine. Do not apply this attribute to a structure in
|
||||||
|
// its entirety if the purpose is to control the offsets of the members in the
|
||||||
|
// structure. Instead, apply this attribute only to structure members that need
|
||||||
|
// it.
|
||||||
|
//
|
||||||
|
// When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the
|
||||||
|
// natural alignment of structure members not annotated is preserved. Aligned
|
||||||
|
// member accesses are faster than non-aligned member accesses even if the
|
||||||
|
// targeted microprocessor supports non-aligned accesses.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_PACKED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_FUNC_ALIGN
|
||||||
|
//
|
||||||
|
// Tells the compiler to align the function start at least to certain
|
||||||
|
// alignment boundary
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_FALLTHROUGH_INTENDED
|
||||||
|
//
|
||||||
|
// Annotates implicit fall-through between switch labels, allowing a case to
|
||||||
|
// indicate intentional fallthrough and turn off warnings about any lack of a
|
||||||
|
// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
|
||||||
|
// a semicolon and can be used in most places where `break` can, provided that
|
||||||
|
// no statements exist between it and the next switch label.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// switch (x) {
|
||||||
|
// case 40:
|
||||||
|
// case 41:
|
||||||
|
// if (truth_is_out_there) {
|
||||||
|
// ++x;
|
||||||
|
// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations
|
||||||
|
// // in comments
|
||||||
|
// } else {
|
||||||
|
// return x;
|
||||||
|
// }
|
||||||
|
// case 42:
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
// Notes: When supported, GCC and Clang can issue a warning on switch labels
|
||||||
|
// with unannotated fallthrough using the warning `-Wimplicit-fallthrough`. See
|
||||||
|
// clang documentation on language extensions for details:
|
||||||
|
// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
|
||||||
|
//
|
||||||
|
// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro has
|
||||||
|
// no effect on diagnostics. In any case this macro has no effect on runtime
|
||||||
|
// behavior and performance of code.
|
||||||
|
|
||||||
|
#ifdef ABSL_FALLTHROUGH_INTENDED
|
||||||
|
#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
|
||||||
|
#elif ABSL_HAVE_CPP_ATTRIBUTE(fallthrough)
|
||||||
|
#define ABSL_FALLTHROUGH_INTENDED [[fallthrough]]
|
||||||
|
#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::fallthrough)
|
||||||
|
#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
|
||||||
|
#elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::fallthrough)
|
||||||
|
#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
|
||||||
|
#else
|
||||||
|
#define ABSL_FALLTHROUGH_INTENDED \
|
||||||
|
do { \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_DEPRECATED()
|
||||||
|
//
|
||||||
|
// Marks a deprecated class, struct, enum, function, method and variable
|
||||||
|
// declarations. The macro argument is used as a custom diagnostic message (e.g.
|
||||||
|
// suggestion of a better alternative).
|
||||||
|
//
|
||||||
|
// For code or headers that are assured to only build with C++14 and up, prefer
|
||||||
|
// just using the standard `[[deprecated("message")]]` directly over this macro.
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// class ABSL_DEPRECATED("Use Bar instead") Foo {...};
|
||||||
|
//
|
||||||
|
// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
|
||||||
|
//
|
||||||
|
// template <typename T>
|
||||||
|
// ABSL_DEPRECATED("Use DoThat() instead")
|
||||||
|
// void DoThis();
|
||||||
|
//
|
||||||
|
// enum FooEnum {
|
||||||
|
// kBar ABSL_DEPRECATED("Use kBaz instead"),
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// Every usage of a deprecated entity will trigger a warning when compiled with
|
||||||
|
// GCC/Clang's `-Wdeprecated-declarations` option. Google's production toolchain
|
||||||
|
// turns this warning off by default, instead relying on clang-tidy to report
|
||||||
|
// new uses of deprecated code.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(deprecated)
|
||||||
|
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||||
|
#else
|
||||||
|
#define ABSL_DEPRECATED(message)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_CONST_INIT
|
||||||
|
//
|
||||||
|
// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
|
||||||
|
// not compile (on supported platforms) unless the variable has a constant
|
||||||
|
// initializer. This is useful for variables with static and thread storage
|
||||||
|
// duration, because it guarantees that they will not suffer from the so-called
|
||||||
|
// "static init order fiasco".
|
||||||
|
//
|
||||||
|
// This attribute must be placed on the initializing declaration of the
|
||||||
|
// variable. Some compilers will give a -Wmissing-constinit warning when this
|
||||||
|
// attribute is placed on some other declaration but missing from the
|
||||||
|
// initializing declaration.
|
||||||
|
//
|
||||||
|
// In some cases (notably with thread_local variables), `ABSL_CONST_INIT` can
|
||||||
|
// also be used in a non-initializing declaration to tell the compiler that a
|
||||||
|
// variable is already initialized, reducing overhead that would otherwise be
|
||||||
|
// incurred by a hidden guard variable. Thus annotating all declarations with
|
||||||
|
// this attribute is recommended to potentially enhance optimization.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// class MyClass {
|
||||||
|
// public:
|
||||||
|
// ABSL_CONST_INIT static MyType my_var;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// ABSL_CONST_INIT MyType MyClass::my_var = MakeMyType(...);
|
||||||
|
//
|
||||||
|
// For code or headers that are assured to only build with C++20 and up, prefer
|
||||||
|
// just using the standard `constinit` keyword directly over this macro.
|
||||||
|
//
|
||||||
|
// Note that this attribute is redundant if the variable is declared constexpr.
|
||||||
|
#if defined(__cpp_constinit) && __cpp_constinit >= 201907L
|
||||||
|
#define ABSL_CONST_INIT constinit
|
||||||
|
#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
|
||||||
|
#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
|
||||||
|
#else
|
||||||
|
#define ABSL_CONST_INIT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_PURE_FUNCTION
|
||||||
|
//
|
||||||
|
// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure"
|
||||||
|
// functions. A function is pure if its return value is only a function of its
|
||||||
|
// arguments. The pure attribute prohibits a function from modifying the state
|
||||||
|
// of the program that is observable by means other than inspecting the
|
||||||
|
// function's return value. Declaring such functions with the pure attribute
|
||||||
|
// allows the compiler to avoid emitting some calls in repeated invocations of
|
||||||
|
// the function with the same argument values.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d);
|
||||||
|
#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::pure)
|
||||||
|
#define ABSL_ATTRIBUTE_PURE_FUNCTION [[gnu::pure]]
|
||||||
|
#elif ABSL_HAVE_ATTRIBUTE(pure)
|
||||||
|
#define ABSL_ATTRIBUTE_PURE_FUNCTION __attribute__((pure))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_PURE_FUNCTION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_LIFETIME_BOUND indicates that a resource owned by a function
|
||||||
|
// parameter or implicit object parameter is retained by the return value of the
|
||||||
|
// annotated function (or, for a parameter of a constructor, in the value of the
|
||||||
|
// constructed object). This attribute causes warnings to be produced if a
|
||||||
|
// temporary object does not live long enough.
|
||||||
|
//
|
||||||
|
// When applied to a reference parameter, the referenced object is assumed to be
|
||||||
|
// retained by the return value of the function. When applied to a non-reference
|
||||||
|
// parameter (for example, a pointer or a class type), all temporaries
|
||||||
|
// referenced by the parameter are assumed to be retained by the return value of
|
||||||
|
// the function.
|
||||||
|
//
|
||||||
|
// See also the upstream documentation:
|
||||||
|
// https://clang.llvm.org/docs/AttributeReference.html#lifetimebound
|
||||||
|
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::lifetimebound)
|
||||||
|
#define ABSL_ATTRIBUTE_LIFETIME_BOUND [[clang::lifetimebound]]
|
||||||
|
#elif ABSL_HAVE_ATTRIBUTE(lifetimebound)
|
||||||
|
#define ABSL_ATTRIBUTE_LIFETIME_BOUND __attribute__((lifetimebound))
|
||||||
|
#else
|
||||||
|
#define ABSL_ATTRIBUTE_LIFETIME_BOUND
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_ATTRIBUTES_H_
|
||||||
219
include/absl/base/call_once.h
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: call_once.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header file provides an Abseil version of `std::call_once` for invoking
|
||||||
|
// a given function at most once, across all threads. This Abseil version is
|
||||||
|
// faster than the C++11 version and incorporates the C++17 argument-passing
|
||||||
|
// fix, so that (for example) non-const references may be passed to the invoked
|
||||||
|
// function.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_CALL_ONCE_H_
|
||||||
|
#define ABSL_BASE_CALL_ONCE_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "absl/base/internal/invoke.h"
|
||||||
|
#include "absl/base/internal/low_level_scheduling.h"
|
||||||
|
#include "absl/base/internal/raw_logging.h"
|
||||||
|
#include "absl/base/internal/scheduling_mode.h"
|
||||||
|
#include "absl/base/internal/spinlock_wait.h"
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/base/optimization.h"
|
||||||
|
#include "absl/base/port.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class once_flag;
|
||||||
|
|
||||||
|
namespace base_internal {
|
||||||
|
std::atomic<uint32_t>* ControlWord(absl::once_flag* flag);
|
||||||
|
} // namespace base_internal
|
||||||
|
|
||||||
|
// call_once()
|
||||||
|
//
|
||||||
|
// For all invocations using a given `once_flag`, invokes a given `fn` exactly
|
||||||
|
// once across all threads. The first call to `call_once()` with a particular
|
||||||
|
// `once_flag` argument (that does not throw an exception) will run the
|
||||||
|
// specified function with the provided `args`; other calls with the same
|
||||||
|
// `once_flag` argument will not run the function, but will wait
|
||||||
|
// for the provided function to finish running (if it is still running).
|
||||||
|
//
|
||||||
|
// This mechanism provides a safe, simple, and fast mechanism for one-time
|
||||||
|
// initialization in a multi-threaded process.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// class MyInitClass {
|
||||||
|
// public:
|
||||||
|
// ...
|
||||||
|
// mutable absl::once_flag once_;
|
||||||
|
//
|
||||||
|
// MyInitClass* init() const {
|
||||||
|
// absl::call_once(once_, &MyInitClass::Init, this);
|
||||||
|
// return ptr_;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
template <typename Callable, typename... Args>
|
||||||
|
void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args);
|
||||||
|
|
||||||
|
// once_flag
|
||||||
|
//
|
||||||
|
// Objects of this type are used to distinguish calls to `call_once()` and
|
||||||
|
// ensure the provided function is only invoked once across all threads. This
|
||||||
|
// type is not copyable or movable. However, it has a `constexpr`
|
||||||
|
// constructor, and is safe to use as a namespace-scoped global variable.
|
||||||
|
class once_flag {
|
||||||
|
public:
|
||||||
|
constexpr once_flag() : control_(0) {}
|
||||||
|
once_flag(const once_flag&) = delete;
|
||||||
|
once_flag& operator=(const once_flag&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend std::atomic<uint32_t>* base_internal::ControlWord(once_flag* flag);
|
||||||
|
std::atomic<uint32_t> control_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// End of public interfaces.
|
||||||
|
// Implementation details follow.
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
// Like call_once, but uses KERNEL_ONLY scheduling. Intended to be used to
|
||||||
|
// initialize entities used by the scheduler implementation.
|
||||||
|
template <typename Callable, typename... Args>
|
||||||
|
void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args);
|
||||||
|
|
||||||
|
// Disables scheduling while on stack when scheduling mode is non-cooperative.
|
||||||
|
// No effect for cooperative scheduling modes.
|
||||||
|
class SchedulingHelper {
|
||||||
|
public:
|
||||||
|
explicit SchedulingHelper(base_internal::SchedulingMode mode) : mode_(mode) {
|
||||||
|
if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
|
||||||
|
guard_result_ = base_internal::SchedulingGuard::DisableRescheduling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~SchedulingHelper() {
|
||||||
|
if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
|
||||||
|
base_internal::SchedulingGuard::EnableRescheduling(guard_result_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
base_internal::SchedulingMode mode_;
|
||||||
|
bool guard_result_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bit patterns for call_once state machine values. Internal implementation
|
||||||
|
// detail, not for use by clients.
|
||||||
|
//
|
||||||
|
// The bit patterns are arbitrarily chosen from unlikely values, to aid in
|
||||||
|
// debugging. However, kOnceInit must be 0, so that a zero-initialized
|
||||||
|
// once_flag will be valid for immediate use.
|
||||||
|
enum {
|
||||||
|
kOnceInit = 0,
|
||||||
|
kOnceRunning = 0x65C2937B,
|
||||||
|
kOnceWaiter = 0x05A308D2,
|
||||||
|
// A very small constant is chosen for kOnceDone so that it fit in a single
|
||||||
|
// compare with immediate instruction for most common ISAs. This is verified
|
||||||
|
// for x86, POWER and ARM.
|
||||||
|
kOnceDone = 221, // Random Number
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Callable, typename... Args>
|
||||||
|
ABSL_ATTRIBUTE_NOINLINE
|
||||||
|
void CallOnceImpl(std::atomic<uint32_t>* control,
|
||||||
|
base_internal::SchedulingMode scheduling_mode, Callable&& fn,
|
||||||
|
Args&&... args) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
{
|
||||||
|
uint32_t old_control = control->load(std::memory_order_relaxed);
|
||||||
|
if (old_control != kOnceInit &&
|
||||||
|
old_control != kOnceRunning &&
|
||||||
|
old_control != kOnceWaiter &&
|
||||||
|
old_control != kOnceDone) {
|
||||||
|
ABSL_RAW_LOG(FATAL, "Unexpected value for control word: 0x%lx",
|
||||||
|
static_cast<unsigned long>(old_control)); // NOLINT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // NDEBUG
|
||||||
|
static const base_internal::SpinLockWaitTransition trans[] = {
|
||||||
|
{kOnceInit, kOnceRunning, true},
|
||||||
|
{kOnceRunning, kOnceWaiter, false},
|
||||||
|
{kOnceDone, kOnceDone, true}};
|
||||||
|
|
||||||
|
// Must do this before potentially modifying control word's state.
|
||||||
|
base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode);
|
||||||
|
// Short circuit the simplest case to avoid procedure call overhead.
|
||||||
|
// The base_internal::SpinLockWait() call returns either kOnceInit or
|
||||||
|
// kOnceDone. If it returns kOnceDone, it must have loaded the control word
|
||||||
|
// with std::memory_order_acquire and seen a value of kOnceDone.
|
||||||
|
uint32_t old_control = kOnceInit;
|
||||||
|
if (control->compare_exchange_strong(old_control, kOnceRunning,
|
||||||
|
std::memory_order_relaxed) ||
|
||||||
|
base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
|
||||||
|
scheduling_mode) == kOnceInit) {
|
||||||
|
base_internal::invoke(std::forward<Callable>(fn),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
old_control =
|
||||||
|
control->exchange(base_internal::kOnceDone, std::memory_order_release);
|
||||||
|
if (old_control == base_internal::kOnceWaiter) {
|
||||||
|
base_internal::SpinLockWake(control, true);
|
||||||
|
}
|
||||||
|
} // else *control is already kOnceDone
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::atomic<uint32_t>* ControlWord(once_flag* flag) {
|
||||||
|
return &flag->control_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Callable, typename... Args>
|
||||||
|
void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args) {
|
||||||
|
std::atomic<uint32_t>* once = base_internal::ControlWord(flag);
|
||||||
|
uint32_t s = once->load(std::memory_order_acquire);
|
||||||
|
if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
|
||||||
|
base_internal::CallOnceImpl(once, base_internal::SCHEDULE_KERNEL_ONLY,
|
||||||
|
std::forward<Callable>(fn),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
|
||||||
|
template <typename Callable, typename... Args>
|
||||||
|
void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) {
|
||||||
|
std::atomic<uint32_t>* once = base_internal::ControlWord(&flag);
|
||||||
|
uint32_t s = once->load(std::memory_order_acquire);
|
||||||
|
if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
|
||||||
|
base_internal::CallOnceImpl(
|
||||||
|
once, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL,
|
||||||
|
std::forward<Callable>(fn), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_CALL_ONCE_H_
|
||||||
180
include/absl/base/casts.h
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: casts.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header file defines casting templates to fit use cases not covered by
|
||||||
|
// the standard casts provided in the C++ standard. As with all cast operations,
|
||||||
|
// use these with caution and only if alternatives do not exist.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_CASTS_H_
|
||||||
|
#define ABSL_BASE_CASTS_H_
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||||
|
#include <bit> // For std::bit_cast.
|
||||||
|
#endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||||
|
|
||||||
|
#include "absl/base/internal/identity.h"
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/meta/type_traits.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// implicit_cast()
|
||||||
|
//
|
||||||
|
// Performs an implicit conversion between types following the language
|
||||||
|
// rules for implicit conversion; if an implicit conversion is otherwise
|
||||||
|
// allowed by the language in the given context, this function performs such an
|
||||||
|
// implicit conversion.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // If the context allows implicit conversion:
|
||||||
|
// From from;
|
||||||
|
// To to = from;
|
||||||
|
//
|
||||||
|
// // Such code can be replaced by:
|
||||||
|
// implicit_cast<To>(from);
|
||||||
|
//
|
||||||
|
// An `implicit_cast()` may also be used to annotate numeric type conversions
|
||||||
|
// that, although safe, may produce compiler warnings (such as `long` to `int`).
|
||||||
|
// Additionally, an `implicit_cast()` is also useful within return statements to
|
||||||
|
// indicate a specific implicit conversion is being undertaken.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// return implicit_cast<double>(size_in_bytes) / capacity_;
|
||||||
|
//
|
||||||
|
// Annotating code with `implicit_cast()` allows you to explicitly select
|
||||||
|
// particular overloads and template instantiations, while providing a safer
|
||||||
|
// cast than `reinterpret_cast()` or `static_cast()`.
|
||||||
|
//
|
||||||
|
// Additionally, an `implicit_cast()` can be used to allow upcasting within a
|
||||||
|
// type hierarchy where incorrect use of `static_cast()` could accidentally
|
||||||
|
// allow downcasting.
|
||||||
|
//
|
||||||
|
// Finally, an `implicit_cast()` can be used to perform implicit conversions
|
||||||
|
// from unrelated types that otherwise couldn't be implicitly cast directly;
|
||||||
|
// C++ will normally only implicitly cast "one step" in such conversions.
|
||||||
|
//
|
||||||
|
// That is, if C is a type which can be implicitly converted to B, with B being
|
||||||
|
// a type that can be implicitly converted to A, an `implicit_cast()` can be
|
||||||
|
// used to convert C to B (which the compiler can then implicitly convert to A
|
||||||
|
// using language rules).
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // Assume an object C is convertible to B, which is implicitly convertible
|
||||||
|
// // to A
|
||||||
|
// A a = implicit_cast<B>(C);
|
||||||
|
//
|
||||||
|
// Such implicit cast chaining may be useful within template logic.
|
||||||
|
template <typename To>
|
||||||
|
constexpr To implicit_cast(typename absl::internal::identity_t<To> to) {
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bit_cast()
|
||||||
|
//
|
||||||
|
// Creates a value of the new type `Dest` whose representation is the same as
|
||||||
|
// that of the argument, which is of (deduced) type `Source` (a "bitwise cast";
|
||||||
|
// every bit in the value representation of the result is equal to the
|
||||||
|
// corresponding bit in the object representation of the source). Source and
|
||||||
|
// destination types must be of the same size, and both types must be trivially
|
||||||
|
// copyable.
|
||||||
|
//
|
||||||
|
// As with most casts, use with caution. A `bit_cast()` might be needed when you
|
||||||
|
// need to treat a value as the value of some other type, for example, to access
|
||||||
|
// the individual bits of an object which are not normally accessible through
|
||||||
|
// the object's type, such as for working with the binary representation of a
|
||||||
|
// floating point value:
|
||||||
|
//
|
||||||
|
// float f = 3.14159265358979;
|
||||||
|
// int i = bit_cast<int>(f);
|
||||||
|
// // i = 0x40490fdb
|
||||||
|
//
|
||||||
|
// Reinterpreting and accessing a value directly as a different type (as shown
|
||||||
|
// below) usually results in undefined behavior.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // WRONG
|
||||||
|
// float f = 3.14159265358979;
|
||||||
|
// int i = reinterpret_cast<int&>(f); // Wrong
|
||||||
|
// int j = *reinterpret_cast<int*>(&f); // Equally wrong
|
||||||
|
// int k = *bit_cast<int*>(&f); // Equally wrong
|
||||||
|
//
|
||||||
|
// Reinterpret-casting results in undefined behavior according to the ISO C++
|
||||||
|
// specification, section [basic.lval]. Roughly, this section says: if an object
|
||||||
|
// in memory has one type, and a program accesses it with a different type, the
|
||||||
|
// result is undefined behavior for most "different type".
|
||||||
|
//
|
||||||
|
// Using bit_cast on a pointer and then dereferencing it is no better than using
|
||||||
|
// reinterpret_cast. You should only use bit_cast on the value itself.
|
||||||
|
//
|
||||||
|
// Such casting results in type punning: holding an object in memory of one type
|
||||||
|
// and reading its bits back using a different type. A `bit_cast()` avoids this
|
||||||
|
// issue by copying the object representation to a new value, which avoids
|
||||||
|
// introducing this undefined behavior (since the original value is never
|
||||||
|
// accessed in the wrong way).
|
||||||
|
//
|
||||||
|
// The requirements of `absl::bit_cast` are more strict than that of
|
||||||
|
// `std::bit_cast` unless compiler support is available. Specifically, without
|
||||||
|
// compiler support, this implementation also requires `Dest` to be
|
||||||
|
// default-constructible. In C++20, `absl::bit_cast` is replaced by
|
||||||
|
// `std::bit_cast`.
|
||||||
|
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||||
|
|
||||||
|
using std::bit_cast;
|
||||||
|
|
||||||
|
#else // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||||
|
|
||||||
|
template <typename Dest, typename Source,
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(Dest) == sizeof(Source) &&
|
||||||
|
type_traits_internal::is_trivially_copyable<Source>::value &&
|
||||||
|
type_traits_internal::is_trivially_copyable<Dest>::value
|
||||||
|
#if !ABSL_HAVE_BUILTIN(__builtin_bit_cast)
|
||||||
|
&& std::is_default_constructible<Dest>::value
|
||||||
|
#endif // !ABSL_HAVE_BUILTIN(__builtin_bit_cast)
|
||||||
|
,
|
||||||
|
int>::type = 0>
|
||||||
|
#if ABSL_HAVE_BUILTIN(__builtin_bit_cast)
|
||||||
|
inline constexpr Dest bit_cast(const Source& source) {
|
||||||
|
return __builtin_bit_cast(Dest, source);
|
||||||
|
}
|
||||||
|
#else // ABSL_HAVE_BUILTIN(__builtin_bit_cast)
|
||||||
|
inline Dest bit_cast(const Source& source) {
|
||||||
|
Dest dest;
|
||||||
|
memcpy(static_cast<void*>(std::addressof(dest)),
|
||||||
|
static_cast<const void*>(std::addressof(source)), sizeof(dest));
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
#endif // ABSL_HAVE_BUILTIN(__builtin_bit_cast)
|
||||||
|
|
||||||
|
#endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_CASTS_H_
|
||||||
913
include/absl/base/config.h
Normal file
@ -0,0 +1,913 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: config.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header file defines a set of macros for checking the presence of
|
||||||
|
// important compiler and platform features. Such macros can be used to
|
||||||
|
// produce portable code by parameterizing compilation based on the presence or
|
||||||
|
// lack of a given feature.
|
||||||
|
//
|
||||||
|
// We define a "feature" as some interface we wish to program to: for example,
|
||||||
|
// a library function or system call. A value of `1` indicates support for
|
||||||
|
// that feature; any other value indicates the feature support is undefined.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// Suppose a programmer wants to write a program that uses the 'mmap()' system
|
||||||
|
// call. The Abseil macro for that feature (`ABSL_HAVE_MMAP`) allows you to
|
||||||
|
// selectively include the `mmap.h` header and bracket code using that feature
|
||||||
|
// in the macro:
|
||||||
|
//
|
||||||
|
// #include "absl/base/config.h"
|
||||||
|
//
|
||||||
|
// #ifdef ABSL_HAVE_MMAP
|
||||||
|
// #include "sys/mman.h"
|
||||||
|
// #endif //ABSL_HAVE_MMAP
|
||||||
|
//
|
||||||
|
// ...
|
||||||
|
// #ifdef ABSL_HAVE_MMAP
|
||||||
|
// void *ptr = mmap(...);
|
||||||
|
// ...
|
||||||
|
// #endif // ABSL_HAVE_MMAP
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_CONFIG_H_
|
||||||
|
#define ABSL_BASE_CONFIG_H_
|
||||||
|
|
||||||
|
// Included for the __GLIBC__ macro (or similar macros on other systems).
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
// Included for __GLIBCXX__, _LIBCPP_VERSION
|
||||||
|
#include <cstddef>
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
// ABSL_INTERNAL_CPLUSPLUS_LANG
|
||||||
|
//
|
||||||
|
// MSVC does not set the value of __cplusplus correctly, but instead uses
|
||||||
|
// _MSVC_LANG as a stand-in.
|
||||||
|
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||||
|
//
|
||||||
|
// However, there are reports that MSVC even sets _MSVC_LANG incorrectly at
|
||||||
|
// times, for example:
|
||||||
|
// https://github.com/microsoft/vscode-cpptools/issues/1770
|
||||||
|
// https://reviews.llvm.org/D70996
|
||||||
|
//
|
||||||
|
// For this reason, this symbol is considered INTERNAL and code outside of
|
||||||
|
// Abseil must not use it.
|
||||||
|
#if defined(_MSVC_LANG)
|
||||||
|
#define ABSL_INTERNAL_CPLUSPLUS_LANG _MSVC_LANG
|
||||||
|
#elif defined(__cplusplus)
|
||||||
|
#define ABSL_INTERNAL_CPLUSPLUS_LANG __cplusplus
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
|
||||||
|
// __IPHONE_8_0.
|
||||||
|
#include <Availability.h>
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "absl/base/options.h"
|
||||||
|
#include "absl/base/policy_checks.h"
|
||||||
|
|
||||||
|
// Abseil long-term support (LTS) releases will define
|
||||||
|
// `ABSL_LTS_RELEASE_VERSION` to the integer representing the date string of the
|
||||||
|
// LTS release version, and will define `ABSL_LTS_RELEASE_PATCH_LEVEL` to the
|
||||||
|
// integer representing the patch-level for that release.
|
||||||
|
//
|
||||||
|
// For example, for LTS release version "20300401.2", this would give us
|
||||||
|
// ABSL_LTS_RELEASE_VERSION == 20300401 && ABSL_LTS_RELEASE_PATCH_LEVEL == 2
|
||||||
|
//
|
||||||
|
// These symbols will not be defined in non-LTS code.
|
||||||
|
//
|
||||||
|
// Abseil recommends that clients live-at-head. Therefore, if you are using
|
||||||
|
// these symbols to assert a minimum version requirement, we recommend you do it
|
||||||
|
// as
|
||||||
|
//
|
||||||
|
// #if defined(ABSL_LTS_RELEASE_VERSION) && ABSL_LTS_RELEASE_VERSION < 20300401
|
||||||
|
// #error Project foo requires Abseil LTS version >= 20300401
|
||||||
|
// #endif
|
||||||
|
//
|
||||||
|
// The `defined(ABSL_LTS_RELEASE_VERSION)` part of the check excludes
|
||||||
|
// live-at-head clients from the minimum version assertion.
|
||||||
|
//
|
||||||
|
// See https://abseil.io/about/releases for more information on Abseil release
|
||||||
|
// management.
|
||||||
|
//
|
||||||
|
// LTS releases can be obtained from
|
||||||
|
// https://github.com/abseil/abseil-cpp/releases.
|
||||||
|
#define ABSL_LTS_RELEASE_VERSION 20220623
|
||||||
|
#define ABSL_LTS_RELEASE_PATCH_LEVEL 0
|
||||||
|
|
||||||
|
// Helper macro to convert a CPP variable to a string literal.
|
||||||
|
#define ABSL_INTERNAL_DO_TOKEN_STR(x) #x
|
||||||
|
#define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x)
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Abseil namespace annotations
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ABSL_NAMESPACE_BEGIN/ABSL_NAMESPACE_END
|
||||||
|
//
|
||||||
|
// An annotation placed at the beginning/end of each `namespace absl` scope.
|
||||||
|
// This is used to inject an inline namespace.
|
||||||
|
//
|
||||||
|
// The proper way to write Abseil code in the `absl` namespace is:
|
||||||
|
//
|
||||||
|
// namespace absl {
|
||||||
|
// ABSL_NAMESPACE_BEGIN
|
||||||
|
//
|
||||||
|
// void Foo(); // absl::Foo().
|
||||||
|
//
|
||||||
|
// ABSL_NAMESPACE_END
|
||||||
|
// } // namespace absl
|
||||||
|
//
|
||||||
|
// Users of Abseil should not use these macros, because users of Abseil should
|
||||||
|
// not write `namespace absl {` in their own code for any reason. (Abseil does
|
||||||
|
// not support forward declarations of its own types, nor does it support
|
||||||
|
// user-provided specialization of Abseil templates. Code that violates these
|
||||||
|
// rules may be broken without warning.)
|
||||||
|
#if !defined(ABSL_OPTION_USE_INLINE_NAMESPACE) || \
|
||||||
|
!defined(ABSL_OPTION_INLINE_NAMESPACE_NAME)
|
||||||
|
#error options.h is misconfigured.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check that ABSL_OPTION_INLINE_NAMESPACE_NAME is neither "head" nor ""
|
||||||
|
#if defined(__cplusplus) && ABSL_OPTION_USE_INLINE_NAMESPACE == 1
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_INLINE_NAMESPACE_STR \
|
||||||
|
ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME)
|
||||||
|
|
||||||
|
static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != '\0',
|
||||||
|
"options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
|
||||||
|
"not be empty.");
|
||||||
|
static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
||||||
|
ABSL_INTERNAL_INLINE_NAMESPACE_STR[1] != 'e' ||
|
||||||
|
ABSL_INTERNAL_INLINE_NAMESPACE_STR[2] != 'a' ||
|
||||||
|
ABSL_INTERNAL_INLINE_NAMESPACE_STR[3] != 'd' ||
|
||||||
|
ABSL_INTERNAL_INLINE_NAMESPACE_STR[4] != '\0',
|
||||||
|
"options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
|
||||||
|
"be changed to a new, unique identifier name.");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
|
||||||
|
#define ABSL_NAMESPACE_BEGIN
|
||||||
|
#define ABSL_NAMESPACE_END
|
||||||
|
#define ABSL_INTERNAL_C_SYMBOL(x) x
|
||||||
|
#elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1
|
||||||
|
#define ABSL_NAMESPACE_BEGIN \
|
||||||
|
inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME {
|
||||||
|
#define ABSL_NAMESPACE_END }
|
||||||
|
#define ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) x##_##v
|
||||||
|
#define ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, v) \
|
||||||
|
ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v)
|
||||||
|
#define ABSL_INTERNAL_C_SYMBOL(x) \
|
||||||
|
ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, ABSL_OPTION_INLINE_NAMESPACE_NAME)
|
||||||
|
#else
|
||||||
|
#error options.h is misconfigured.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Compiler Feature Checks
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ABSL_HAVE_BUILTIN()
|
||||||
|
//
|
||||||
|
// Checks whether the compiler supports a Clang Feature Checking Macro, and if
|
||||||
|
// so, checks whether it supports the provided builtin function "x" where x
|
||||||
|
// is one of the functions noted in
|
||||||
|
// https://clang.llvm.org/docs/LanguageExtensions.html
|
||||||
|
//
|
||||||
|
// Note: Use this macro to avoid an extra level of #ifdef __has_builtin check.
|
||||||
|
// http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html
|
||||||
|
#ifdef __has_builtin
|
||||||
|
#define ABSL_HAVE_BUILTIN(x) __has_builtin(x)
|
||||||
|
#else
|
||||||
|
#define ABSL_HAVE_BUILTIN(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __has_feature
|
||||||
|
#define ABSL_HAVE_FEATURE(f) __has_feature(f)
|
||||||
|
#else
|
||||||
|
#define ABSL_HAVE_FEATURE(f) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Portable check for GCC minimum version:
|
||||||
|
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
|
||||||
|
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||||
|
#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) \
|
||||||
|
(__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
|
||||||
|
#else
|
||||||
|
#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__)
|
||||||
|
#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) \
|
||||||
|
(__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y))
|
||||||
|
#else
|
||||||
|
#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
|
||||||
|
// We assume __thread is supported on Linux or Asylo when compiled with Clang or
|
||||||
|
// compiled against libstdc++ with _GLIBCXX_HAVE_TLS defined.
|
||||||
|
#ifdef ABSL_HAVE_TLS
|
||||||
|
#error ABSL_HAVE_TLS cannot be directly set
|
||||||
|
#elif (defined(__linux__) || defined(__ASYLO__)) && \
|
||||||
|
(defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
|
||||||
|
#define ABSL_HAVE_TLS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
|
||||||
|
//
|
||||||
|
// Checks whether `std::is_trivially_destructible<T>` is supported.
|
||||||
|
//
|
||||||
|
// Notes: All supported compilers using libc++ support this feature, as does
|
||||||
|
// gcc >= 4.8.1 using libstdc++, and Visual Studio.
|
||||||
|
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
|
||||||
|
#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
|
||||||
|
#elif defined(_LIBCPP_VERSION) || defined(_MSC_VER) || \
|
||||||
|
(!defined(__clang__) && defined(__GLIBCXX__) && \
|
||||||
|
ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(4, 8))
|
||||||
|
#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
|
||||||
|
//
|
||||||
|
// Checks whether `std::is_trivially_default_constructible<T>` and
|
||||||
|
// `std::is_trivially_copy_constructible<T>` are supported.
|
||||||
|
|
||||||
|
// ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
|
||||||
|
//
|
||||||
|
// Checks whether `std::is_trivially_copy_assignable<T>` is supported.
|
||||||
|
|
||||||
|
// Notes: Clang with libc++ supports these features, as does gcc >= 7.4 with
|
||||||
|
// libstdc++, or gcc >= 8.2 with libc++, and Visual Studio (but not NVCC).
|
||||||
|
#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
|
||||||
|
#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
|
||||||
|
#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
|
||||||
|
#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
|
||||||
|
#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \
|
||||||
|
(!defined(__clang__) && \
|
||||||
|
((ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(7, 4) && defined(__GLIBCXX__)) || \
|
||||||
|
(ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(8, 2) && \
|
||||||
|
defined(_LIBCPP_VERSION)))) || \
|
||||||
|
(defined(_MSC_VER) && !defined(__NVCC__))
|
||||||
|
#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
|
||||||
|
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_THREAD_LOCAL
|
||||||
|
//
|
||||||
|
// Checks whether C++11's `thread_local` storage duration specifier is
|
||||||
|
// supported.
|
||||||
|
#ifdef ABSL_HAVE_THREAD_LOCAL
|
||||||
|
#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
// Notes:
|
||||||
|
// * Xcode's clang did not support `thread_local` until version 8, and
|
||||||
|
// even then not for all iOS < 9.0.
|
||||||
|
// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
|
||||||
|
// targeting iOS 9.x.
|
||||||
|
// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
|
||||||
|
// making ABSL_HAVE_FEATURE unreliable there.
|
||||||
|
//
|
||||||
|
#if ABSL_HAVE_FEATURE(cxx_thread_local) && \
|
||||||
|
!(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
|
||||||
|
#define ABSL_HAVE_THREAD_LOCAL 1
|
||||||
|
#endif
|
||||||
|
#else // !defined(__APPLE__)
|
||||||
|
#define ABSL_HAVE_THREAD_LOCAL 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// There are platforms for which TLS should not be used even though the compiler
|
||||||
|
// makes it seem like it's supported (Android NDK < r12b for example).
|
||||||
|
// This is primarily because of linker problems and toolchain misconfiguration:
|
||||||
|
// Abseil does not intend to support this indefinitely. Currently, the newest
|
||||||
|
// toolchain that we intend to support that requires this behavior is the
|
||||||
|
// r11 NDK - allowing for a 5 year support window on that means this option
|
||||||
|
// is likely to be removed around June of 2021.
|
||||||
|
// TLS isn't supported until NDK r12b per
|
||||||
|
// https://developer.android.com/ndk/downloads/revision_history.html
|
||||||
|
// Since NDK r16, `__NDK_MAJOR__` and `__NDK_MINOR__` are defined in
|
||||||
|
// <android/ndk-version.h>. For NDK < r16, users should define these macros,
|
||||||
|
// e.g. `-D__NDK_MAJOR__=11 -D__NKD_MINOR__=0` for NDK r11.
|
||||||
|
#if defined(__ANDROID__) && defined(__clang__)
|
||||||
|
#if __has_include(<android/ndk-version.h>)
|
||||||
|
#include <android/ndk-version.h>
|
||||||
|
#endif // __has_include(<android/ndk-version.h>)
|
||||||
|
#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
|
||||||
|
defined(__NDK_MINOR__) && \
|
||||||
|
((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
|
||||||
|
#undef ABSL_HAVE_TLS
|
||||||
|
#undef ABSL_HAVE_THREAD_LOCAL
|
||||||
|
#endif
|
||||||
|
#endif // defined(__ANDROID__) && defined(__clang__)
|
||||||
|
|
||||||
|
// ABSL_HAVE_INTRINSIC_INT128
|
||||||
|
//
|
||||||
|
// Checks whether the __int128 compiler extension for a 128-bit integral type is
|
||||||
|
// supported.
|
||||||
|
//
|
||||||
|
// Note: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is
|
||||||
|
// supported, but we avoid using it in certain cases:
|
||||||
|
// * On Clang:
|
||||||
|
// * Building using Clang for Windows, where the Clang runtime library has
|
||||||
|
// 128-bit support only on LP64 architectures, but Windows is LLP64.
|
||||||
|
// * On Nvidia's nvcc:
|
||||||
|
// * nvcc also defines __GNUC__ and __SIZEOF_INT128__, but not all versions
|
||||||
|
// actually support __int128.
|
||||||
|
#ifdef ABSL_HAVE_INTRINSIC_INT128
|
||||||
|
#error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set
|
||||||
|
#elif defined(__SIZEOF_INT128__)
|
||||||
|
#if (defined(__clang__) && !defined(_WIN32)) || \
|
||||||
|
(defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \
|
||||||
|
(defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
|
||||||
|
#define ABSL_HAVE_INTRINSIC_INT128 1
|
||||||
|
#elif defined(__CUDACC__)
|
||||||
|
// __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a
|
||||||
|
// string explaining that it has been removed starting with CUDA 9. We use
|
||||||
|
// nested #ifs because there is no short-circuiting in the preprocessor.
|
||||||
|
// NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined.
|
||||||
|
#if __CUDACC_VER__ >= 70000
|
||||||
|
#define ABSL_HAVE_INTRINSIC_INT128 1
|
||||||
|
#endif // __CUDACC_VER__ >= 70000
|
||||||
|
#endif // defined(__CUDACC__)
|
||||||
|
#endif // ABSL_HAVE_INTRINSIC_INT128
|
||||||
|
|
||||||
|
// ABSL_HAVE_EXCEPTIONS
|
||||||
|
//
|
||||||
|
// Checks whether the compiler both supports and enables exceptions. Many
|
||||||
|
// compilers support a "no exceptions" mode that disables exceptions.
|
||||||
|
//
|
||||||
|
// Generally, when ABSL_HAVE_EXCEPTIONS is not defined:
|
||||||
|
//
|
||||||
|
// * Code using `throw` and `try` may not compile.
|
||||||
|
// * The `noexcept` specifier will still compile and behave as normal.
|
||||||
|
// * The `noexcept` operator may still return `false`.
|
||||||
|
//
|
||||||
|
// For further details, consult the compiler's documentation.
|
||||||
|
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||||
|
#error ABSL_HAVE_EXCEPTIONS cannot be directly set.
|
||||||
|
#elif ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(3, 6)
|
||||||
|
// Clang >= 3.6
|
||||||
|
#if ABSL_HAVE_FEATURE(cxx_exceptions)
|
||||||
|
#define ABSL_HAVE_EXCEPTIONS 1
|
||||||
|
#endif // ABSL_HAVE_FEATURE(cxx_exceptions)
|
||||||
|
#elif defined(__clang__)
|
||||||
|
// Clang < 3.6
|
||||||
|
// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
|
||||||
|
#if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
|
||||||
|
#define ABSL_HAVE_EXCEPTIONS 1
|
||||||
|
#endif // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
|
||||||
|
// Handle remaining special cases and default to exceptions being supported.
|
||||||
|
#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \
|
||||||
|
!(ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(5, 0) && \
|
||||||
|
!defined(__cpp_exceptions)) && \
|
||||||
|
!(defined(_MSC_VER) && !defined(_CPPUNWIND))
|
||||||
|
#define ABSL_HAVE_EXCEPTIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Platform Feature Checks
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Currently supported operating systems and associated preprocessor
|
||||||
|
// symbols:
|
||||||
|
//
|
||||||
|
// Linux and Linux-derived __linux__
|
||||||
|
// Android __ANDROID__ (implies __linux__)
|
||||||
|
// Linux (non-Android) __linux__ && !__ANDROID__
|
||||||
|
// Darwin (macOS and iOS) __APPLE__
|
||||||
|
// Akaros (http://akaros.org) __ros__
|
||||||
|
// Windows _WIN32
|
||||||
|
// NaCL __native_client__
|
||||||
|
// AsmJS __asmjs__
|
||||||
|
// WebAssembly __wasm__
|
||||||
|
// Fuchsia __Fuchsia__
|
||||||
|
//
|
||||||
|
// Note that since Android defines both __ANDROID__ and __linux__, one
|
||||||
|
// may probe for either Linux or Android by simply testing for __linux__.
|
||||||
|
|
||||||
|
// ABSL_HAVE_MMAP
|
||||||
|
//
|
||||||
|
// Checks whether the platform has an mmap(2) implementation as defined in
|
||||||
|
// POSIX.1-2001.
|
||||||
|
#ifdef ABSL_HAVE_MMAP
|
||||||
|
#error ABSL_HAVE_MMAP cannot be directly set
|
||||||
|
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
|
||||||
|
defined(_AIX) || defined(__ros__) || defined(__native_client__) || \
|
||||||
|
defined(__asmjs__) || defined(__wasm__) || defined(__Fuchsia__) || \
|
||||||
|
defined(__sun) || defined(__ASYLO__) || defined(__myriad2__) || \
|
||||||
|
defined(__HAIKU__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
|
||||||
|
defined(__QNX__)
|
||||||
|
#define ABSL_HAVE_MMAP 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_PTHREAD_GETSCHEDPARAM
|
||||||
|
//
|
||||||
|
// Checks whether the platform implements the pthread_(get|set)schedparam(3)
|
||||||
|
// functions as defined in POSIX.1-2001.
|
||||||
|
#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
|
||||||
|
#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set
|
||||||
|
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
|
||||||
|
defined(_AIX) || defined(__ros__) || defined(__OpenBSD__) || \
|
||||||
|
defined(__NetBSD__)
|
||||||
|
#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_SCHED_GETCPU
|
||||||
|
//
|
||||||
|
// Checks whether sched_getcpu is available.
|
||||||
|
#ifdef ABSL_HAVE_SCHED_GETCPU
|
||||||
|
#error ABSL_HAVE_SCHED_GETCPU cannot be directly set
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#define ABSL_HAVE_SCHED_GETCPU 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_SCHED_YIELD
|
||||||
|
//
|
||||||
|
// Checks whether the platform implements sched_yield(2) as defined in
|
||||||
|
// POSIX.1-2001.
|
||||||
|
#ifdef ABSL_HAVE_SCHED_YIELD
|
||||||
|
#error ABSL_HAVE_SCHED_YIELD cannot be directly set
|
||||||
|
#elif defined(__linux__) || defined(__ros__) || defined(__native_client__)
|
||||||
|
#define ABSL_HAVE_SCHED_YIELD 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_SEMAPHORE_H
|
||||||
|
//
|
||||||
|
// Checks whether the platform supports the <semaphore.h> header and sem_init(3)
|
||||||
|
// family of functions as standardized in POSIX.1-2001.
|
||||||
|
//
|
||||||
|
// Note: While Apple provides <semaphore.h> for both iOS and macOS, it is
|
||||||
|
// explicitly deprecated and will cause build failures if enabled for those
|
||||||
|
// platforms. We side-step the issue by not defining it here for Apple
|
||||||
|
// platforms.
|
||||||
|
#ifdef ABSL_HAVE_SEMAPHORE_H
|
||||||
|
#error ABSL_HAVE_SEMAPHORE_H cannot be directly set
|
||||||
|
#elif defined(__linux__) || defined(__ros__)
|
||||||
|
#define ABSL_HAVE_SEMAPHORE_H 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_ALARM
|
||||||
|
//
|
||||||
|
// Checks whether the platform supports the <signal.h> header and alarm(2)
|
||||||
|
// function as standardized in POSIX.1-2001.
|
||||||
|
#ifdef ABSL_HAVE_ALARM
|
||||||
|
#error ABSL_HAVE_ALARM cannot be directly set
|
||||||
|
#elif defined(__GOOGLE_GRTE_VERSION__)
|
||||||
|
// feature tests for Google's GRTE
|
||||||
|
#define ABSL_HAVE_ALARM 1
|
||||||
|
#elif defined(__GLIBC__)
|
||||||
|
// feature test for glibc
|
||||||
|
#define ABSL_HAVE_ALARM 1
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
// feature tests for Microsoft's library
|
||||||
|
#elif defined(__MINGW32__)
|
||||||
|
// mingw32 doesn't provide alarm(2):
|
||||||
|
// https://osdn.net/projects/mingw/scm/git/mingw-org-wsl/blobs/5.2-trunk/mingwrt/include/unistd.h
|
||||||
|
// mingw-w64 provides a no-op implementation:
|
||||||
|
// https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/misc/alarm.c
|
||||||
|
#elif defined(__EMSCRIPTEN__)
|
||||||
|
// emscripten doesn't support signals
|
||||||
|
#elif defined(__Fuchsia__)
|
||||||
|
// Signals don't exist on fuchsia.
|
||||||
|
#elif defined(__native_client__)
|
||||||
|
#else
|
||||||
|
// other standard libraries
|
||||||
|
#define ABSL_HAVE_ALARM 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_IS_LITTLE_ENDIAN
|
||||||
|
// ABSL_IS_BIG_ENDIAN
|
||||||
|
//
|
||||||
|
// Checks the endianness of the platform.
|
||||||
|
//
|
||||||
|
// Notes: uses the built in endian macros provided by GCC (since 4.6) and
|
||||||
|
// Clang (since 3.2); see
|
||||||
|
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html.
|
||||||
|
// Otherwise, if _WIN32, assume little endian. Otherwise, bail with an error.
|
||||||
|
#if defined(ABSL_IS_BIG_ENDIAN)
|
||||||
|
#error "ABSL_IS_BIG_ENDIAN cannot be directly set."
|
||||||
|
#endif
|
||||||
|
#if defined(ABSL_IS_LITTLE_ENDIAN)
|
||||||
|
#error "ABSL_IS_LITTLE_ENDIAN cannot be directly set."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
|
||||||
|
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||||
|
#define ABSL_IS_LITTLE_ENDIAN 1
|
||||||
|
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
|
||||||
|
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
|
#define ABSL_IS_BIG_ENDIAN 1
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define ABSL_IS_LITTLE_ENDIAN 1
|
||||||
|
#else
|
||||||
|
#error "absl endian detection needs to be set up for your compiler"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// macOS < 10.13 and iOS < 11 don't let you use <any>, <optional>, or <variant>
|
||||||
|
// even though the headers exist and are publicly noted to work, because the
|
||||||
|
// libc++ shared library shipped on the system doesn't have the requisite
|
||||||
|
// exported symbols. See https://github.com/abseil/abseil-cpp/issues/207 and
|
||||||
|
// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
|
||||||
|
//
|
||||||
|
// libc++ spells out the availability requirements in the file
|
||||||
|
// llvm-project/libcxx/include/__config via the #define
|
||||||
|
// _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS.
|
||||||
|
//
|
||||||
|
// Unfortunately, Apple initially mis-stated the requirements as macOS < 10.14
|
||||||
|
// and iOS < 12 in the libc++ headers. This was corrected by
|
||||||
|
// https://github.com/llvm/llvm-project/commit/7fb40e1569dd66292b647f4501b85517e9247953
|
||||||
|
// which subsequently made it into the XCode 12.5 release. We need to match the
|
||||||
|
// old (incorrect) conditions when built with old XCode, but can use the
|
||||||
|
// corrected earlier versions with new XCode.
|
||||||
|
#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \
|
||||||
|
((_LIBCPP_VERSION >= 11000 && /* XCode 12.5 or later: */ \
|
||||||
|
((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
|
||||||
|
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300) || \
|
||||||
|
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
|
||||||
|
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 110000) || \
|
||||||
|
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
|
||||||
|
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 40000) || \
|
||||||
|
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
|
||||||
|
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 110000))) || \
|
||||||
|
(_LIBCPP_VERSION < 11000 && /* Pre-XCode 12.5: */ \
|
||||||
|
((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
|
||||||
|
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400) || \
|
||||||
|
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
|
||||||
|
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
|
||||||
|
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
|
||||||
|
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
|
||||||
|
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
|
||||||
|
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))))
|
||||||
|
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
|
||||||
|
#else
|
||||||
|
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_STD_ANY
|
||||||
|
//
|
||||||
|
// Checks whether C++17 std::any is available by checking whether <any> exists.
|
||||||
|
#ifdef ABSL_HAVE_STD_ANY
|
||||||
|
#error "ABSL_HAVE_STD_ANY cannot be directly set."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
#if __has_include(<any>) && defined(__cplusplus) && __cplusplus >= 201703L && \
|
||||||
|
!ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
|
||||||
|
#define ABSL_HAVE_STD_ANY 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_STD_OPTIONAL
|
||||||
|
//
|
||||||
|
// Checks whether C++17 std::optional is available.
|
||||||
|
#ifdef ABSL_HAVE_STD_OPTIONAL
|
||||||
|
#error "ABSL_HAVE_STD_OPTIONAL cannot be directly set."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
#if __has_include(<optional>) && defined(__cplusplus) && \
|
||||||
|
__cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
|
||||||
|
#define ABSL_HAVE_STD_OPTIONAL 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_STD_VARIANT
|
||||||
|
//
|
||||||
|
// Checks whether C++17 std::variant is available.
|
||||||
|
#ifdef ABSL_HAVE_STD_VARIANT
|
||||||
|
#error "ABSL_HAVE_STD_VARIANT cannot be directly set."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
#if __has_include(<variant>) && defined(__cplusplus) && \
|
||||||
|
__cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
|
||||||
|
#define ABSL_HAVE_STD_VARIANT 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_STD_STRING_VIEW
|
||||||
|
//
|
||||||
|
// Checks whether C++17 std::string_view is available.
|
||||||
|
#ifdef ABSL_HAVE_STD_STRING_VIEW
|
||||||
|
#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
#if __has_include(<string_view>) && defined(__cplusplus) && \
|
||||||
|
__cplusplus >= 201703L
|
||||||
|
#define ABSL_HAVE_STD_STRING_VIEW 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// For MSVC, `__has_include` is supported in VS 2017 15.3, which is later than
|
||||||
|
// the support for <optional>, <any>, <string_view>, <variant>. So we use
|
||||||
|
// _MSC_VER to check whether we have VS 2017 RTM (when <optional>, <any>,
|
||||||
|
// <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is
|
||||||
|
// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
|
||||||
|
// version.
|
||||||
|
// TODO(zhangxy): fix tests before enabling aliasing for `std::any`.
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER >= 1910 && \
|
||||||
|
((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || \
|
||||||
|
(defined(__cplusplus) && __cplusplus > 201402))
|
||||||
|
// #define ABSL_HAVE_STD_ANY 1
|
||||||
|
#define ABSL_HAVE_STD_OPTIONAL 1
|
||||||
|
#define ABSL_HAVE_STD_VARIANT 1
|
||||||
|
#define ABSL_HAVE_STD_STRING_VIEW 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_USES_STD_ANY
|
||||||
|
//
|
||||||
|
// Indicates whether absl::any is an alias for std::any.
|
||||||
|
#if !defined(ABSL_OPTION_USE_STD_ANY)
|
||||||
|
#error options.h is misconfigured.
|
||||||
|
#elif ABSL_OPTION_USE_STD_ANY == 0 || \
|
||||||
|
(ABSL_OPTION_USE_STD_ANY == 2 && !defined(ABSL_HAVE_STD_ANY))
|
||||||
|
#undef ABSL_USES_STD_ANY
|
||||||
|
#elif ABSL_OPTION_USE_STD_ANY == 1 || \
|
||||||
|
(ABSL_OPTION_USE_STD_ANY == 2 && defined(ABSL_HAVE_STD_ANY))
|
||||||
|
#define ABSL_USES_STD_ANY 1
|
||||||
|
#else
|
||||||
|
#error options.h is misconfigured.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_USES_STD_OPTIONAL
|
||||||
|
//
|
||||||
|
// Indicates whether absl::optional is an alias for std::optional.
|
||||||
|
#if !defined(ABSL_OPTION_USE_STD_OPTIONAL)
|
||||||
|
#error options.h is misconfigured.
|
||||||
|
#elif ABSL_OPTION_USE_STD_OPTIONAL == 0 || \
|
||||||
|
(ABSL_OPTION_USE_STD_OPTIONAL == 2 && !defined(ABSL_HAVE_STD_OPTIONAL))
|
||||||
|
#undef ABSL_USES_STD_OPTIONAL
|
||||||
|
#elif ABSL_OPTION_USE_STD_OPTIONAL == 1 || \
|
||||||
|
(ABSL_OPTION_USE_STD_OPTIONAL == 2 && defined(ABSL_HAVE_STD_OPTIONAL))
|
||||||
|
#define ABSL_USES_STD_OPTIONAL 1
|
||||||
|
#else
|
||||||
|
#error options.h is misconfigured.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_USES_STD_VARIANT
|
||||||
|
//
|
||||||
|
// Indicates whether absl::variant is an alias for std::variant.
|
||||||
|
#if !defined(ABSL_OPTION_USE_STD_VARIANT)
|
||||||
|
#error options.h is misconfigured.
|
||||||
|
#elif ABSL_OPTION_USE_STD_VARIANT == 0 || \
|
||||||
|
(ABSL_OPTION_USE_STD_VARIANT == 2 && !defined(ABSL_HAVE_STD_VARIANT))
|
||||||
|
#undef ABSL_USES_STD_VARIANT
|
||||||
|
#elif ABSL_OPTION_USE_STD_VARIANT == 1 || \
|
||||||
|
(ABSL_OPTION_USE_STD_VARIANT == 2 && defined(ABSL_HAVE_STD_VARIANT))
|
||||||
|
#define ABSL_USES_STD_VARIANT 1
|
||||||
|
#else
|
||||||
|
#error options.h is misconfigured.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_USES_STD_STRING_VIEW
|
||||||
|
//
|
||||||
|
// Indicates whether absl::string_view is an alias for std::string_view.
|
||||||
|
#if !defined(ABSL_OPTION_USE_STD_STRING_VIEW)
|
||||||
|
#error options.h is misconfigured.
|
||||||
|
#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 || \
|
||||||
|
(ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
|
||||||
|
!defined(ABSL_HAVE_STD_STRING_VIEW))
|
||||||
|
#undef ABSL_USES_STD_STRING_VIEW
|
||||||
|
#elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \
|
||||||
|
(ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
|
||||||
|
defined(ABSL_HAVE_STD_STRING_VIEW))
|
||||||
|
#define ABSL_USES_STD_STRING_VIEW 1
|
||||||
|
#else
|
||||||
|
#error options.h is misconfigured.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
|
||||||
|
// SEH exception from emplace for variant<SomeStruct> when constructing the
|
||||||
|
// struct can throw. This defeats some of variant_test and
|
||||||
|
// variant_exception_safety_test.
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG)
|
||||||
|
#define ABSL_INTERNAL_MSVC_2017_DBG_MODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_INTERNAL_MANGLED_NS
|
||||||
|
// ABSL_INTERNAL_MANGLED_BACKREFERENCE
|
||||||
|
//
|
||||||
|
// Internal macros for building up mangled names in our internal fork of CCTZ.
|
||||||
|
// This implementation detail is only needed and provided for the MSVC build.
|
||||||
|
//
|
||||||
|
// These macros both expand to string literals. ABSL_INTERNAL_MANGLED_NS is
|
||||||
|
// the mangled spelling of the `absl` namespace, and
|
||||||
|
// ABSL_INTERNAL_MANGLED_BACKREFERENCE is a back-reference integer representing
|
||||||
|
// the proper count to skip past the CCTZ fork namespace names. (This number
|
||||||
|
// is one larger when there is an inline namespace name to skip.)
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
|
||||||
|
#define ABSL_INTERNAL_MANGLED_NS "absl"
|
||||||
|
#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "5"
|
||||||
|
#else
|
||||||
|
#define ABSL_INTERNAL_MANGLED_NS \
|
||||||
|
ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME) "@absl"
|
||||||
|
#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "6"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_DLL
|
||||||
|
//
|
||||||
|
// When building Abseil as a DLL, this macro expands to `__declspec(dllexport)`
|
||||||
|
// so we can annotate symbols appropriately as being exported. When used in
|
||||||
|
// headers consuming a DLL, this macro expands to `__declspec(dllimport)` so
|
||||||
|
// that consumers know the symbol is defined inside the DLL. In all other cases,
|
||||||
|
// the macro expands to nothing.
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#if defined(ABSL_BUILD_DLL)
|
||||||
|
#define ABSL_DLL __declspec(dllexport)
|
||||||
|
#elif defined(ABSL_CONSUME_DLL)
|
||||||
|
#define ABSL_DLL __declspec(dllimport)
|
||||||
|
#else
|
||||||
|
#define ABSL_DLL
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define ABSL_DLL
|
||||||
|
#endif // defined(_MSC_VER)
|
||||||
|
|
||||||
|
// ABSL_HAVE_MEMORY_SANITIZER
|
||||||
|
//
|
||||||
|
// MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of
|
||||||
|
// a compiler instrumentation module and a run-time library.
|
||||||
|
#ifdef ABSL_HAVE_MEMORY_SANITIZER
|
||||||
|
#error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set."
|
||||||
|
#elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer)
|
||||||
|
#define ABSL_HAVE_MEMORY_SANITIZER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_THREAD_SANITIZER
|
||||||
|
//
|
||||||
|
// ThreadSanitizer (TSan) is a fast data race detector.
|
||||||
|
#ifdef ABSL_HAVE_THREAD_SANITIZER
|
||||||
|
#error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set."
|
||||||
|
#elif defined(__SANITIZE_THREAD__)
|
||||||
|
#define ABSL_HAVE_THREAD_SANITIZER 1
|
||||||
|
#elif ABSL_HAVE_FEATURE(thread_sanitizer)
|
||||||
|
#define ABSL_HAVE_THREAD_SANITIZER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
//
|
||||||
|
// AddressSanitizer (ASan) is a fast memory error detector.
|
||||||
|
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
#error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set."
|
||||||
|
#elif defined(__SANITIZE_ADDRESS__)
|
||||||
|
#define ABSL_HAVE_ADDRESS_SANITIZER 1
|
||||||
|
#elif ABSL_HAVE_FEATURE(address_sanitizer)
|
||||||
|
#define ABSL_HAVE_ADDRESS_SANITIZER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_HWADDRESS_SANITIZER
|
||||||
|
//
|
||||||
|
// Hardware-Assisted AddressSanitizer (or HWASAN) is even faster than asan
|
||||||
|
// memory error detector which can use CPU features like ARM TBI, Intel LAM or
|
||||||
|
// AMD UAI.
|
||||||
|
#ifdef ABSL_HAVE_HWADDRESS_SANITIZER
|
||||||
|
#error "ABSL_HAVE_HWADDRESS_SANITIZER cannot be directly set."
|
||||||
|
#elif defined(__SANITIZE_HWADDRESS__)
|
||||||
|
#define ABSL_HAVE_HWADDRESS_SANITIZER 1
|
||||||
|
#elif ABSL_HAVE_FEATURE(hwaddress_sanitizer)
|
||||||
|
#define ABSL_HAVE_HWADDRESS_SANITIZER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_LEAK_SANITIZER
|
||||||
|
//
|
||||||
|
// LeakSanitizer (or lsan) is a detector of memory leaks.
|
||||||
|
// https://clang.llvm.org/docs/LeakSanitizer.html
|
||||||
|
// https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
|
||||||
|
//
|
||||||
|
// The macro ABSL_HAVE_LEAK_SANITIZER can be used to detect at compile-time
|
||||||
|
// whether the LeakSanitizer is potentially available. However, just because the
|
||||||
|
// LeakSanitizer is available does not mean it is active. Use the
|
||||||
|
// always-available run-time interface in //absl/debugging/leak_check.h for
|
||||||
|
// interacting with LeakSanitizer.
|
||||||
|
#ifdef ABSL_HAVE_LEAK_SANITIZER
|
||||||
|
#error "ABSL_HAVE_LEAK_SANITIZER cannot be directly set."
|
||||||
|
#elif defined(LEAK_SANITIZER)
|
||||||
|
// GCC provides no method for detecting the presense of the standalone
|
||||||
|
// LeakSanitizer (-fsanitize=leak), so GCC users of -fsanitize=leak should also
|
||||||
|
// use -DLEAK_SANITIZER.
|
||||||
|
#define ABSL_HAVE_LEAK_SANITIZER 1
|
||||||
|
// Clang standalone LeakSanitizer (-fsanitize=leak)
|
||||||
|
#elif ABSL_HAVE_FEATURE(leak_sanitizer)
|
||||||
|
#define ABSL_HAVE_LEAK_SANITIZER 1
|
||||||
|
#elif defined(ABSL_HAVE_ADDRESS_SANITIZER)
|
||||||
|
// GCC or Clang using the LeakSanitizer integrated into AddressSanitizer.
|
||||||
|
#define ABSL_HAVE_LEAK_SANITIZER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
|
||||||
|
//
|
||||||
|
// Class template argument deduction is a language feature added in C++17.
|
||||||
|
#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
|
||||||
|
#error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set."
|
||||||
|
#elif defined(__cpp_deduction_guides)
|
||||||
|
#define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||||
|
//
|
||||||
|
// Prior to C++17, static constexpr variables defined in classes required a
|
||||||
|
// separate definition outside of the class body, for example:
|
||||||
|
//
|
||||||
|
// class Foo {
|
||||||
|
// static constexpr int kBar = 0;
|
||||||
|
// };
|
||||||
|
// constexpr int Foo::kBar;
|
||||||
|
//
|
||||||
|
// In C++17, these variables defined in classes are considered inline variables,
|
||||||
|
// and the extra declaration is redundant. Since some compilers warn on the
|
||||||
|
// extra declarations, ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL can be used
|
||||||
|
// conditionally ignore them:
|
||||||
|
//
|
||||||
|
// #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||||
|
// constexpr int Foo::kBar;
|
||||||
|
// #endif
|
||||||
|
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
|
||||||
|
ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L
|
||||||
|
#define ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// `ABSL_INTERNAL_HAS_RTTI` determines whether abseil is being compiled with
|
||||||
|
// RTTI support.
|
||||||
|
#ifdef ABSL_INTERNAL_HAS_RTTI
|
||||||
|
#error ABSL_INTERNAL_HAS_RTTI cannot be directly set
|
||||||
|
#elif !defined(__GNUC__) || defined(__GXX_RTTI)
|
||||||
|
#define ABSL_INTERNAL_HAS_RTTI 1
|
||||||
|
#endif // !defined(__GNUC__) || defined(__GXX_RTTI)
|
||||||
|
|
||||||
|
// ABSL_INTERNAL_HAVE_SSE is used for compile-time detection of SSE support.
|
||||||
|
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
|
||||||
|
// which architectures support the various x86 instruction sets.
|
||||||
|
#ifdef ABSL_INTERNAL_HAVE_SSE
|
||||||
|
#error ABSL_INTERNAL_HAVE_SSE cannot be directly set
|
||||||
|
#elif defined(__SSE__)
|
||||||
|
#define ABSL_INTERNAL_HAVE_SSE 1
|
||||||
|
#elif defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)
|
||||||
|
// MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 1
|
||||||
|
// indicates that at least SSE was targeted with the /arch:SSE option.
|
||||||
|
// All x86-64 processors support SSE, so support can be assumed.
|
||||||
|
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||||
|
#define ABSL_INTERNAL_HAVE_SSE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_INTERNAL_HAVE_SSE2 is used for compile-time detection of SSE2 support.
|
||||||
|
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
|
||||||
|
// which architectures support the various x86 instruction sets.
|
||||||
|
#ifdef ABSL_INTERNAL_HAVE_SSE2
|
||||||
|
#error ABSL_INTERNAL_HAVE_SSE2 cannot be directly set
|
||||||
|
#elif defined(__SSE2__)
|
||||||
|
#define ABSL_INTERNAL_HAVE_SSE2 1
|
||||||
|
#elif defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
|
||||||
|
// MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 2
|
||||||
|
// indicates that at least SSE2 was targeted with the /arch:SSE2 option.
|
||||||
|
// All x86-64 processors support SSE2, so support can be assumed.
|
||||||
|
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||||
|
#define ABSL_INTERNAL_HAVE_SSE2 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_INTERNAL_HAVE_SSSE3 is used for compile-time detection of SSSE3 support.
|
||||||
|
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
|
||||||
|
// which architectures support the various x86 instruction sets.
|
||||||
|
//
|
||||||
|
// MSVC does not have a mode that targets SSSE3 at compile-time. To use SSSE3
|
||||||
|
// with MSVC requires either assuming that the code will only every run on CPUs
|
||||||
|
// that support SSSE3, otherwise __cpuid() can be used to detect support at
|
||||||
|
// runtime and fallback to a non-SSSE3 implementation when SSSE3 is unsupported
|
||||||
|
// by the CPU.
|
||||||
|
#ifdef ABSL_INTERNAL_HAVE_SSSE3
|
||||||
|
#error ABSL_INTERNAL_HAVE_SSSE3 cannot be directly set
|
||||||
|
#elif defined(__SSSE3__)
|
||||||
|
#define ABSL_INTERNAL_HAVE_SSSE3 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_INTERNAL_HAVE_ARM_NEON is used for compile-time detection of NEON (ARM
|
||||||
|
// SIMD).
|
||||||
|
#ifdef ABSL_INTERNAL_HAVE_ARM_NEON
|
||||||
|
#error ABSL_INTERNAL_HAVE_ARM_NEON cannot be directly set
|
||||||
|
#elif defined(__ARM_NEON)
|
||||||
|
#define ABSL_INTERNAL_HAVE_ARM_NEON 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_CONFIG_H_
|
||||||
76
include/absl/base/const_init.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// kConstInit
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// A constructor tag used to mark an object as safe for use as a global
|
||||||
|
// variable, avoiding the usual lifetime issues that can affect globals.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_CONST_INIT_H_
|
||||||
|
#define ABSL_BASE_CONST_INIT_H_
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
// In general, objects with static storage duration (such as global variables)
|
||||||
|
// can trigger tricky object lifetime situations. Attempting to access them
|
||||||
|
// from the constructors or destructors of other global objects can result in
|
||||||
|
// undefined behavior, unless their constructors and destructors are designed
|
||||||
|
// with this issue in mind.
|
||||||
|
//
|
||||||
|
// The normal way to deal with this issue in C++11 is to use constant
|
||||||
|
// initialization and trivial destructors.
|
||||||
|
//
|
||||||
|
// Constant initialization is guaranteed to occur before any other code
|
||||||
|
// executes. Constructors that are declared 'constexpr' are eligible for
|
||||||
|
// constant initialization. You can annotate a variable declaration with the
|
||||||
|
// ABSL_CONST_INIT macro to express this intent. For compilers that support
|
||||||
|
// it, this annotation will cause a compilation error for declarations that
|
||||||
|
// aren't subject to constant initialization (perhaps because a runtime value
|
||||||
|
// was passed as a constructor argument).
|
||||||
|
//
|
||||||
|
// On program shutdown, lifetime issues can be avoided on global objects by
|
||||||
|
// ensuring that they contain trivial destructors. A class has a trivial
|
||||||
|
// destructor unless it has a user-defined destructor, a virtual method or base
|
||||||
|
// class, or a data member or base class with a non-trivial destructor of its
|
||||||
|
// own. Objects with static storage duration and a trivial destructor are not
|
||||||
|
// cleaned up on program shutdown, and are thus safe to access from other code
|
||||||
|
// running during shutdown.
|
||||||
|
//
|
||||||
|
// For a few core Abseil classes, we make a best effort to allow for safe global
|
||||||
|
// instances, even though these classes have non-trivial destructors. These
|
||||||
|
// objects can be created with the absl::kConstInit tag. For example:
|
||||||
|
// ABSL_CONST_INIT absl::Mutex global_mutex(absl::kConstInit);
|
||||||
|
//
|
||||||
|
// The line above declares a global variable of type absl::Mutex which can be
|
||||||
|
// accessed at any point during startup or shutdown. global_mutex's destructor
|
||||||
|
// will still run, but will not invalidate the object. Note that C++ specifies
|
||||||
|
// that accessing an object after its destructor has run results in undefined
|
||||||
|
// behavior, but this pattern works on the toolchains we support.
|
||||||
|
//
|
||||||
|
// The absl::kConstInit tag should only be used to define objects with static
|
||||||
|
// or thread_local storage duration.
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
enum ConstInitType {
|
||||||
|
kConstInit,
|
||||||
|
};
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_CONST_INIT_H_
|
||||||
471
include/absl/base/dynamic_annotations.h
Normal file
@ -0,0 +1,471 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// This file defines dynamic annotations for use with dynamic analysis tool
|
||||||
|
// such as valgrind, PIN, etc.
|
||||||
|
//
|
||||||
|
// Dynamic annotation is a source code annotation that affects the generated
|
||||||
|
// code (that is, the annotation is not a comment). Each such annotation is
|
||||||
|
// attached to a particular instruction and/or to a particular object (address)
|
||||||
|
// in the program.
|
||||||
|
//
|
||||||
|
// The annotations that should be used by users are macros in all upper-case
|
||||||
|
// (e.g., ABSL_ANNOTATE_THREAD_NAME).
|
||||||
|
//
|
||||||
|
// Actual implementation of these macros may differ depending on the dynamic
|
||||||
|
// analysis tool being used.
|
||||||
|
//
|
||||||
|
// This file supports the following configurations:
|
||||||
|
// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
|
||||||
|
// In this case, macros expand to functions implemented by Thread Sanitizer,
|
||||||
|
// when building with TSan. When not provided an external implementation,
|
||||||
|
// dynamic_annotations.cc provides no-op implementations.
|
||||||
|
//
|
||||||
|
// - Static Clang thread-safety warnings enabled.
|
||||||
|
// When building with a Clang compiler that supports thread-safety warnings,
|
||||||
|
// a subset of annotations can be statically-checked at compile-time. We
|
||||||
|
// expand these macros to static-inline functions that can be analyzed for
|
||||||
|
// thread-safety, but afterwards elided when building the final binary.
|
||||||
|
//
|
||||||
|
// - All annotations are disabled.
|
||||||
|
// If neither Dynamic Annotations nor Clang thread-safety warnings are
|
||||||
|
// enabled, then all annotation-macros expand to empty.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
|
||||||
|
#define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO(rogeeff): Remove after the backward compatibility period.
|
||||||
|
#include "absl/base/internal/dynamic_annotations.h" // IWYU pragma: export
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Decide which features are enabled.
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_THREAD_SANITIZER
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
|
||||||
|
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
|
||||||
|
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
|
||||||
|
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
|
||||||
|
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
|
||||||
|
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
|
||||||
|
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
|
||||||
|
|
||||||
|
// Clang provides limited support for static thread-safety analysis through a
|
||||||
|
// feature called Annotalysis. We configure macro-definitions according to
|
||||||
|
// whether Annotalysis support is available. When running in opt-mode, GCC
|
||||||
|
// will issue a warning, if these attributes are compiled. Only include them
|
||||||
|
// when compiling using Clang.
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 1
|
||||||
|
#if !defined(SWIG)
|
||||||
|
#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
|
||||||
|
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
|
||||||
|
ABSL_INTERNAL_ANNOTALYSIS_ENABLED
|
||||||
|
|
||||||
|
#endif // ABSL_HAVE_THREAD_SANITIZER
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
|
||||||
|
#define ABSL_INTERNAL_END_EXTERN_C } // extern "C"
|
||||||
|
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
|
||||||
|
#define ABSL_INTERNAL_STATIC_INLINE inline
|
||||||
|
#else
|
||||||
|
#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty
|
||||||
|
#define ABSL_INTERNAL_END_EXTERN_C // empty
|
||||||
|
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
|
||||||
|
#define ABSL_INTERNAL_STATIC_INLINE static inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define race annotations.
|
||||||
|
|
||||||
|
#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
|
||||||
|
// Some of the symbols used in this section (e.g. AnnotateBenignRaceSized) are
|
||||||
|
// defined by the compiler-based santizer implementation, not by the Abseil
|
||||||
|
// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// Annotations that suppress errors. It is usually better to express the
|
||||||
|
// program's synchronization using the other annotations, but these can be used
|
||||||
|
// when all else fails.
|
||||||
|
|
||||||
|
// Report that we may have a benign race at `pointer`, with size
|
||||||
|
// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
|
||||||
|
// point where `pointer` has been allocated, preferably close to the point
|
||||||
|
// where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC.
|
||||||
|
#define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
|
||||||
|
(__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
|
||||||
|
|
||||||
|
// Same as ABSL_ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
|
||||||
|
// the memory range [`address`, `address`+`size`).
|
||||||
|
#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
|
||||||
|
(__FILE__, __LINE__, address, size, description)
|
||||||
|
|
||||||
|
// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
|
||||||
|
// This annotation could be useful if you want to skip expensive race analysis
|
||||||
|
// during some period of program execution, e.g. during initialization.
|
||||||
|
#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
|
||||||
|
(__FILE__, __LINE__, enable)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// Annotations useful for debugging.
|
||||||
|
|
||||||
|
// Report the current thread `name` to a race detector.
|
||||||
|
#define ABSL_ANNOTATE_THREAD_NAME(name) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// Annotations useful when implementing locks. They are not normally needed by
|
||||||
|
// modules that merely use locks. The `lock` argument is a pointer to the lock
|
||||||
|
// object.
|
||||||
|
|
||||||
|
// Report that a lock has been created at address `lock`.
|
||||||
|
#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
|
||||||
|
|
||||||
|
// Report that a linker initialized lock has been created at address `lock`.
|
||||||
|
#ifdef ABSL_HAVE_THREAD_SANITIZER
|
||||||
|
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
|
||||||
|
(__FILE__, __LINE__, lock)
|
||||||
|
#else
|
||||||
|
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
|
||||||
|
ABSL_ANNOTATE_RWLOCK_CREATE(lock)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Report that the lock at address `lock` is about to be destroyed.
|
||||||
|
#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
|
||||||
|
|
||||||
|
// Report that the lock at address `lock` has been acquired.
|
||||||
|
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
|
||||||
|
#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
|
||||||
|
(__FILE__, __LINE__, lock, is_w)
|
||||||
|
|
||||||
|
// Report that the lock at address `lock` is about to be released.
|
||||||
|
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
|
||||||
|
#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
|
||||||
|
(__FILE__, __LINE__, lock, is_w)
|
||||||
|
|
||||||
|
// Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
|
||||||
|
#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
|
||||||
|
namespace { \
|
||||||
|
class static_var##_annotator { \
|
||||||
|
public: \
|
||||||
|
static_var##_annotator() { \
|
||||||
|
ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \
|
||||||
|
#static_var ": " description); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
static static_var##_annotator the##static_var##_annotator; \
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// Function prototypes of annotations provided by the compiler-based sanitizer
|
||||||
|
// implementation.
|
||||||
|
ABSL_INTERNAL_BEGIN_EXTERN_C
|
||||||
|
void AnnotateRWLockCreate(const char* file, int line,
|
||||||
|
const volatile void* lock);
|
||||||
|
void AnnotateRWLockCreateStatic(const char* file, int line,
|
||||||
|
const volatile void* lock);
|
||||||
|
void AnnotateRWLockDestroy(const char* file, int line,
|
||||||
|
const volatile void* lock);
|
||||||
|
void AnnotateRWLockAcquired(const char* file, int line,
|
||||||
|
const volatile void* lock, long is_w); // NOLINT
|
||||||
|
void AnnotateRWLockReleased(const char* file, int line,
|
||||||
|
const volatile void* lock, long is_w); // NOLINT
|
||||||
|
void AnnotateBenignRace(const char* file, int line,
|
||||||
|
const volatile void* address, const char* description);
|
||||||
|
void AnnotateBenignRaceSized(const char* file, int line,
|
||||||
|
const volatile void* address, size_t size,
|
||||||
|
const char* description);
|
||||||
|
void AnnotateThreadName(const char* file, int line, const char* name);
|
||||||
|
void AnnotateEnableRaceDetection(const char* file, int line, int enable);
|
||||||
|
ABSL_INTERNAL_END_EXTERN_C
|
||||||
|
|
||||||
|
#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0
|
||||||
|
|
||||||
|
#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) // empty
|
||||||
|
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty
|
||||||
|
#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) // empty
|
||||||
|
#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty
|
||||||
|
#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty
|
||||||
|
#define ABSL_ANNOTATE_BENIGN_RACE(address, description) // empty
|
||||||
|
#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty
|
||||||
|
#define ABSL_ANNOTATE_THREAD_NAME(name) // empty
|
||||||
|
#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty
|
||||||
|
#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty
|
||||||
|
|
||||||
|
#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define memory annotations.
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_MEMORY_SANITIZER
|
||||||
|
|
||||||
|
#include <sanitizer/msan_interface.h>
|
||||||
|
|
||||||
|
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
|
||||||
|
__msan_unpoison(address, size)
|
||||||
|
|
||||||
|
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
|
||||||
|
__msan_allocated_memory(address, size)
|
||||||
|
|
||||||
|
#else // !defined(ABSL_HAVE_MEMORY_SANITIZER)
|
||||||
|
|
||||||
|
// TODO(rogeeff): remove this branch
|
||||||
|
#ifdef ABSL_HAVE_THREAD_SANITIZER
|
||||||
|
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
|
||||||
|
do { \
|
||||||
|
(void)(address); \
|
||||||
|
(void)(size); \
|
||||||
|
} while (0)
|
||||||
|
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
|
||||||
|
do { \
|
||||||
|
(void)(address); \
|
||||||
|
(void)(size); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty
|
||||||
|
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ABSL_HAVE_MEMORY_SANITIZER
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define IGNORE_READS_BEGIN/_END attributes.
|
||||||
|
|
||||||
|
#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
|
||||||
|
__attribute((exclusive_lock_function("*")))
|
||||||
|
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
|
||||||
|
__attribute((unlock_function("*")))
|
||||||
|
|
||||||
|
#else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty
|
||||||
|
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty
|
||||||
|
|
||||||
|
#endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define IGNORE_READS_BEGIN/_END annotations.
|
||||||
|
|
||||||
|
#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
|
||||||
|
// Some of the symbols used in this section (e.g. AnnotateIgnoreReadsBegin) are
|
||||||
|
// defined by the compiler-based implementation, not by the Abseil
|
||||||
|
// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
|
||||||
|
|
||||||
|
// Request the analysis tool to ignore all reads in the current thread until
|
||||||
|
// ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
|
||||||
|
// reads, while still checking other reads and all writes.
|
||||||
|
// See also ABSL_ANNOTATE_UNPROTECTED_READ.
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin) \
|
||||||
|
(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
// Stop ignoring reads.
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_READS_END() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd) \
|
||||||
|
(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
// Function prototypes of annotations provided by the compiler-based sanitizer
|
||||||
|
// implementation.
|
||||||
|
ABSL_INTERNAL_BEGIN_EXTERN_C
|
||||||
|
void AnnotateIgnoreReadsBegin(const char* file, int line)
|
||||||
|
ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE;
|
||||||
|
void AnnotateIgnoreReadsEnd(const char* file,
|
||||||
|
int line) ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE;
|
||||||
|
ABSL_INTERNAL_END_EXTERN_C
|
||||||
|
|
||||||
|
#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
|
||||||
|
|
||||||
|
// When Annotalysis is enabled without Dynamic Annotations, the use of
|
||||||
|
// static-inline functions allows the annotations to be read at compile-time,
|
||||||
|
// while still letting the compiler elide the functions from the final build.
|
||||||
|
//
|
||||||
|
// TODO(delesley) -- The exclusive lock here ignores writes as well, but
|
||||||
|
// allows IGNORE_READS_AND_WRITES to work properly.
|
||||||
|
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED( \
|
||||||
|
ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsBegin)) \
|
||||||
|
()
|
||||||
|
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_READS_END() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED( \
|
||||||
|
ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsEnd)) \
|
||||||
|
()
|
||||||
|
|
||||||
|
ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
|
||||||
|
AbslInternalAnnotateIgnoreReadsBegin)()
|
||||||
|
ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {}
|
||||||
|
|
||||||
|
ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
|
||||||
|
AbslInternalAnnotateIgnoreReadsEnd)()
|
||||||
|
ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() // empty
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_READS_END() // empty
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define IGNORE_WRITES_BEGIN/_END annotations.
|
||||||
|
|
||||||
|
#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
|
||||||
|
|
||||||
|
// Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
// Stop ignoring writes.
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
// Function prototypes of annotations provided by the compiler-based sanitizer
|
||||||
|
// implementation.
|
||||||
|
ABSL_INTERNAL_BEGIN_EXTERN_C
|
||||||
|
void AnnotateIgnoreWritesBegin(const char* file, int line);
|
||||||
|
void AnnotateIgnoreWritesEnd(const char* file, int line);
|
||||||
|
ABSL_INTERNAL_END_EXTERN_C
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() // empty
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_WRITES_END() // empty
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define the ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
|
||||||
|
// primitive annotations defined above.
|
||||||
|
//
|
||||||
|
// Instead of doing
|
||||||
|
// ABSL_ANNOTATE_IGNORE_READS_BEGIN();
|
||||||
|
// ... = x;
|
||||||
|
// ABSL_ANNOTATE_IGNORE_READS_END();
|
||||||
|
// one can use
|
||||||
|
// ... = ABSL_ANNOTATE_UNPROTECTED_READ(x);
|
||||||
|
|
||||||
|
#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)
|
||||||
|
|
||||||
|
// Start ignoring all memory accesses (both reads and writes).
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
|
||||||
|
do { \
|
||||||
|
ABSL_ANNOTATE_IGNORE_READS_BEGIN(); \
|
||||||
|
ABSL_ANNOTATE_IGNORE_WRITES_BEGIN(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
// Stop ignoring both reads and writes.
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \
|
||||||
|
do { \
|
||||||
|
ABSL_ANNOTATE_IGNORE_WRITES_END(); \
|
||||||
|
ABSL_ANNOTATE_IGNORE_READS_END(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
// ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
|
||||||
|
#define ABSL_ANNOTATE_UNPROTECTED_READ(x) \
|
||||||
|
absl::base_internal::AnnotateUnprotectedRead(x)
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T AnnotateUnprotectedRead(const volatile T& x) { // NOLINT
|
||||||
|
ABSL_ANNOTATE_IGNORE_READS_BEGIN();
|
||||||
|
T res = x;
|
||||||
|
ABSL_ANNOTATE_IGNORE_READS_END();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty
|
||||||
|
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty
|
||||||
|
#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Address sanitizer annotations
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
// Describe the current state of a contiguous container such as e.g.
|
||||||
|
// std::vector or std::string. For more details see
|
||||||
|
// sanitizer/common_interface_defs.h, which is provided by the compiler.
|
||||||
|
#include <sanitizer/common_interface_defs.h>
|
||||||
|
|
||||||
|
#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
|
||||||
|
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
|
||||||
|
#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \
|
||||||
|
struct { \
|
||||||
|
alignas(8) char x[8]; \
|
||||||
|
} name
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) // empty
|
||||||
|
#define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
|
||||||
|
|
||||||
|
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Undefine the macros intended only for this file.
|
||||||
|
|
||||||
|
#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
|
||||||
|
#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
|
||||||
|
#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
|
||||||
|
#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
|
||||||
|
#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
|
||||||
|
#undef ABSL_INTERNAL_BEGIN_EXTERN_C
|
||||||
|
#undef ABSL_INTERNAL_END_EXTERN_C
|
||||||
|
#undef ABSL_INTERNAL_STATIC_INLINE
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
|
||||||
200
include/absl/base/internal/atomic_hook.h
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 0
|
||||||
|
#else
|
||||||
|
#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
|
||||||
|
#else
|
||||||
|
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class AtomicHook;
|
||||||
|
|
||||||
|
// To workaround AtomicHook not being constant-initializable on some platforms,
|
||||||
|
// prefer to annotate instances with `ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES`
|
||||||
|
// instead of `ABSL_CONST_INIT`.
|
||||||
|
#if ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||||
|
#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_CONST_INIT
|
||||||
|
#else
|
||||||
|
#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// `AtomicHook` is a helper class, templatized on a raw function pointer type,
|
||||||
|
// for implementing Abseil customization hooks. It is a callable object that
|
||||||
|
// dispatches to the registered hook. Objects of type `AtomicHook` must have
|
||||||
|
// static or thread storage duration.
|
||||||
|
//
|
||||||
|
// A default constructed object performs a no-op (and returns a default
|
||||||
|
// constructed object) if no hook has been registered.
|
||||||
|
//
|
||||||
|
// Hooks can be pre-registered via constant initialization, for example:
|
||||||
|
//
|
||||||
|
// ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static AtomicHook<void(*)()>
|
||||||
|
// my_hook(DefaultAction);
|
||||||
|
//
|
||||||
|
// and then changed at runtime via a call to `Store()`.
|
||||||
|
//
|
||||||
|
// Reads and writes guarantee memory_order_acquire/memory_order_release
|
||||||
|
// semantics.
|
||||||
|
template <typename ReturnType, typename... Args>
|
||||||
|
class AtomicHook<ReturnType (*)(Args...)> {
|
||||||
|
public:
|
||||||
|
using FnPtr = ReturnType (*)(Args...);
|
||||||
|
|
||||||
|
// Constructs an object that by default performs a no-op (and
|
||||||
|
// returns a default constructed object) when no hook as been registered.
|
||||||
|
constexpr AtomicHook() : AtomicHook(DummyFunction) {}
|
||||||
|
|
||||||
|
// Constructs an object that by default dispatches to/returns the
|
||||||
|
// pre-registered default_fn when no hook has been registered at runtime.
|
||||||
|
#if ABSL_HAVE_WORKING_ATOMIC_POINTER && ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||||
|
explicit constexpr AtomicHook(FnPtr default_fn)
|
||||||
|
: hook_(default_fn), default_fn_(default_fn) {}
|
||||||
|
#elif ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||||
|
explicit constexpr AtomicHook(FnPtr default_fn)
|
||||||
|
: hook_(kUninitialized), default_fn_(default_fn) {}
|
||||||
|
#else
|
||||||
|
// As of January 2020, on all known versions of MSVC this constructor runs in
|
||||||
|
// the global constructor sequence. If `Store()` is called by a dynamic
|
||||||
|
// initializer, we want to preserve the value, even if this constructor runs
|
||||||
|
// after the call to `Store()`. If not, `hook_` will be
|
||||||
|
// zero-initialized by the linker and we have no need to set it.
|
||||||
|
// https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html
|
||||||
|
explicit constexpr AtomicHook(FnPtr default_fn)
|
||||||
|
: /* hook_(deliberately omitted), */ default_fn_(default_fn) {
|
||||||
|
static_assert(kUninitialized == 0, "here we rely on zero-initialization");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Stores the provided function pointer as the value for this hook.
|
||||||
|
//
|
||||||
|
// This is intended to be called once. Multiple calls are legal only if the
|
||||||
|
// same function pointer is provided for each call. The store is implemented
|
||||||
|
// as a memory_order_release operation, and read accesses are implemented as
|
||||||
|
// memory_order_acquire.
|
||||||
|
void Store(FnPtr fn) {
|
||||||
|
bool success = DoStore(fn);
|
||||||
|
static_cast<void>(success);
|
||||||
|
assert(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invokes the registered callback. If no callback has yet been registered, a
|
||||||
|
// default-constructed object of the appropriate type is returned instead.
|
||||||
|
template <typename... CallArgs>
|
||||||
|
ReturnType operator()(CallArgs&&... args) const {
|
||||||
|
return DoLoad()(std::forward<CallArgs>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the registered callback, or nullptr if none has been registered.
|
||||||
|
// Useful if client code needs to conditionalize behavior based on whether a
|
||||||
|
// callback was registered.
|
||||||
|
//
|
||||||
|
// Note that atomic_hook.Load()() and atomic_hook() have different semantics:
|
||||||
|
// operator()() will perform a no-op if no callback was registered, while
|
||||||
|
// Load()() will dereference a null function pointer. Prefer operator()() to
|
||||||
|
// Load()() unless you must conditionalize behavior on whether a hook was
|
||||||
|
// registered.
|
||||||
|
FnPtr Load() const {
|
||||||
|
FnPtr ptr = DoLoad();
|
||||||
|
return (ptr == DummyFunction) ? nullptr : ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static ReturnType DummyFunction(Args...) {
|
||||||
|
return ReturnType();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current versions of MSVC (as of September 2017) have a broken
|
||||||
|
// implementation of std::atomic<T*>: Its constructor attempts to do the
|
||||||
|
// equivalent of a reinterpret_cast in a constexpr context, which is not
|
||||||
|
// allowed.
|
||||||
|
//
|
||||||
|
// This causes an issue when building with LLVM under Windows. To avoid this,
|
||||||
|
// we use a less-efficient, intptr_t-based implementation on Windows.
|
||||||
|
#if ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||||
|
// Return the stored value, or DummyFunction if no value has been stored.
|
||||||
|
FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); }
|
||||||
|
|
||||||
|
// Store the given value. Returns false if a different value was already
|
||||||
|
// stored to this object.
|
||||||
|
bool DoStore(FnPtr fn) {
|
||||||
|
assert(fn);
|
||||||
|
FnPtr expected = default_fn_;
|
||||||
|
const bool store_succeeded = hook_.compare_exchange_strong(
|
||||||
|
expected, fn, std::memory_order_acq_rel, std::memory_order_acquire);
|
||||||
|
const bool same_value_already_stored = (expected == fn);
|
||||||
|
return store_succeeded || same_value_already_stored;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::atomic<FnPtr> hook_;
|
||||||
|
#else // !ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||||
|
// Use a sentinel value unlikely to be the address of an actual function.
|
||||||
|
static constexpr intptr_t kUninitialized = 0;
|
||||||
|
|
||||||
|
static_assert(sizeof(intptr_t) >= sizeof(FnPtr),
|
||||||
|
"intptr_t can't contain a function pointer");
|
||||||
|
|
||||||
|
FnPtr DoLoad() const {
|
||||||
|
const intptr_t value = hook_.load(std::memory_order_acquire);
|
||||||
|
if (value == kUninitialized) {
|
||||||
|
return default_fn_;
|
||||||
|
}
|
||||||
|
return reinterpret_cast<FnPtr>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DoStore(FnPtr fn) {
|
||||||
|
assert(fn);
|
||||||
|
const auto value = reinterpret_cast<intptr_t>(fn);
|
||||||
|
intptr_t expected = kUninitialized;
|
||||||
|
const bool store_succeeded = hook_.compare_exchange_strong(
|
||||||
|
expected, value, std::memory_order_acq_rel, std::memory_order_acquire);
|
||||||
|
const bool same_value_already_stored = (expected == value);
|
||||||
|
return store_succeeded || same_value_already_stored;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::atomic<intptr_t> hook_;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const FnPtr default_fn_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||||
|
#undef ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
|
||||||
34
include/absl/base/internal/atomic_hook_test_helper.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_
|
||||||
|
#define ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_
|
||||||
|
|
||||||
|
#include "absl/base/internal/atomic_hook.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace atomic_hook_internal {
|
||||||
|
|
||||||
|
using VoidF = void (*)();
|
||||||
|
extern absl::base_internal::AtomicHook<VoidF> func;
|
||||||
|
extern int default_func_calls;
|
||||||
|
void DefaultFunc();
|
||||||
|
void RegisterFunc(VoidF func);
|
||||||
|
|
||||||
|
} // namespace atomic_hook_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_
|
||||||
159
include/absl/base/internal/cycleclock.h
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: cycleclock.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header file defines a `CycleClock`, which yields the value and frequency
|
||||||
|
// of a cycle counter that increments at a rate that is approximately constant.
|
||||||
|
//
|
||||||
|
// NOTE:
|
||||||
|
//
|
||||||
|
// The cycle counter frequency is not necessarily related to the core clock
|
||||||
|
// frequency and should not be treated as such. That is, `CycleClock` cycles are
|
||||||
|
// not necessarily "CPU cycles" and code should not rely on that behavior, even
|
||||||
|
// if experimentally observed.
|
||||||
|
//
|
||||||
|
// An arbitrary offset may have been added to the counter at power on.
|
||||||
|
//
|
||||||
|
// On some platforms, the rate and offset of the counter may differ
|
||||||
|
// slightly when read from different CPUs of a multiprocessor. Usually,
|
||||||
|
// we try to ensure that the operating system adjusts values periodically
|
||||||
|
// so that values agree approximately. If you need stronger guarantees,
|
||||||
|
// consider using alternate interfaces.
|
||||||
|
//
|
||||||
|
// The CPU is not required to maintain the ordering of a cycle counter read
|
||||||
|
// with respect to surrounding instructions.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_CYCLECLOCK_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_CYCLECLOCK_H_
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
#include "absl/base/internal/unscaledcycleclock.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
using CycleClockSourceFunc = int64_t (*)();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// CycleClock
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
class CycleClock {
|
||||||
|
public:
|
||||||
|
// CycleClock::Now()
|
||||||
|
//
|
||||||
|
// Returns the value of a cycle counter that counts at a rate that is
|
||||||
|
// approximately constant.
|
||||||
|
static int64_t Now();
|
||||||
|
|
||||||
|
// CycleClock::Frequency()
|
||||||
|
//
|
||||||
|
// Returns the amount by which `CycleClock::Now()` increases per second. Note
|
||||||
|
// that this value may not necessarily match the core CPU clock frequency.
|
||||||
|
static double Frequency();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if ABSL_USE_UNSCALED_CYCLECLOCK
|
||||||
|
static CycleClockSourceFunc LoadCycleClockSource();
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#ifdef ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
|
||||||
|
// Not debug mode and the UnscaledCycleClock frequency is the CPU
|
||||||
|
// frequency. Scale the CycleClock to prevent overflow if someone
|
||||||
|
// tries to represent the time as cycles since the Unix epoch.
|
||||||
|
static constexpr int32_t kShift = 1;
|
||||||
|
#else
|
||||||
|
// Not debug mode and the UnscaledCycleClock isn't operating at the
|
||||||
|
// raw CPU frequency. There is no need to do any scaling, so don't
|
||||||
|
// needlessly sacrifice precision.
|
||||||
|
static constexpr int32_t kShift = 0;
|
||||||
|
#endif
|
||||||
|
#else // NDEBUG
|
||||||
|
// In debug mode use a different shift to discourage depending on a
|
||||||
|
// particular shift value.
|
||||||
|
static constexpr int32_t kShift = 2;
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
static constexpr double kFrequencyScale = 1.0 / (1 << kShift);
|
||||||
|
ABSL_CONST_INIT static std::atomic<CycleClockSourceFunc> cycle_clock_source_;
|
||||||
|
#endif // ABSL_USE_UNSCALED_CYCLECLOC
|
||||||
|
|
||||||
|
CycleClock() = delete; // no instances
|
||||||
|
CycleClock(const CycleClock&) = delete;
|
||||||
|
CycleClock& operator=(const CycleClock&) = delete;
|
||||||
|
|
||||||
|
friend class CycleClockSource;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CycleClockSource {
|
||||||
|
private:
|
||||||
|
// CycleClockSource::Register()
|
||||||
|
//
|
||||||
|
// Register a function that provides an alternate source for the unscaled CPU
|
||||||
|
// cycle count value. The source function must be async signal safe, must not
|
||||||
|
// call CycleClock::Now(), and must have a frequency that matches that of the
|
||||||
|
// unscaled clock used by CycleClock. A nullptr value resets CycleClock to use
|
||||||
|
// the default source.
|
||||||
|
static void Register(CycleClockSourceFunc source);
|
||||||
|
};
|
||||||
|
|
||||||
|
#if ABSL_USE_UNSCALED_CYCLECLOCK
|
||||||
|
|
||||||
|
inline CycleClockSourceFunc CycleClock::LoadCycleClockSource() {
|
||||||
|
#if !defined(__x86_64__)
|
||||||
|
// Optimize for the common case (no callback) by first doing a relaxed load;
|
||||||
|
// this is significantly faster on non-x86 platforms.
|
||||||
|
if (cycle_clock_source_.load(std::memory_order_relaxed) == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#endif // !defined(__x86_64__)
|
||||||
|
|
||||||
|
// This corresponds to the store(std::memory_order_release) in
|
||||||
|
// CycleClockSource::Register, and makes sure that any updates made prior to
|
||||||
|
// registering the callback are visible to this thread before the callback
|
||||||
|
// is invoked.
|
||||||
|
return cycle_clock_source_.load(std::memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessing globals in inlined code in Window DLLs is problematic.
|
||||||
|
#ifndef _WIN32
|
||||||
|
inline int64_t CycleClock::Now() {
|
||||||
|
auto fn = LoadCycleClockSource();
|
||||||
|
if (fn == nullptr) {
|
||||||
|
return base_internal::UnscaledCycleClock::Now() >> kShift;
|
||||||
|
}
|
||||||
|
return fn() >> kShift;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline double CycleClock::Frequency() {
|
||||||
|
return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_
|
||||||
169
include/absl/base/internal/direct_mmap.h
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Functions for directly invoking mmap() via syscall, avoiding the case where
|
||||||
|
// mmap() has been locally overridden.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_MMAP
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#ifdef __BIONIC__
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#else
|
||||||
|
#include <syscall.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <linux/unistd.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#ifdef __mips__
|
||||||
|
// Include definitions of the ABI currently in use.
|
||||||
|
#if defined(__BIONIC__) || !defined(__GLIBC__)
|
||||||
|
// Android doesn't have sgidefs.h, but does have asm/sgidefs.h, which has the
|
||||||
|
// definitions we need.
|
||||||
|
#include <asm/sgidefs.h>
|
||||||
|
#else
|
||||||
|
#include <sgidefs.h>
|
||||||
|
#endif // __BIONIC__ || !__GLIBC__
|
||||||
|
#endif // __mips__
|
||||||
|
|
||||||
|
// SYS_mmap and SYS_munmap are not defined in Android.
|
||||||
|
#ifdef __BIONIC__
|
||||||
|
extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
|
||||||
|
#if defined(__NR_mmap) && !defined(SYS_mmap)
|
||||||
|
#define SYS_mmap __NR_mmap
|
||||||
|
#endif
|
||||||
|
#ifndef SYS_munmap
|
||||||
|
#define SYS_munmap __NR_munmap
|
||||||
|
#endif
|
||||||
|
#endif // __BIONIC__
|
||||||
|
|
||||||
|
#if defined(__NR_mmap2) && !defined(SYS_mmap2)
|
||||||
|
#define SYS_mmap2 __NR_mmap2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
// Platform specific logic extracted from
|
||||||
|
// https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h
|
||||||
|
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
|
||||||
|
off64_t offset) noexcept {
|
||||||
|
#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
|
||||||
|
defined(__m68k__) || defined(__sh__) || \
|
||||||
|
(defined(__hppa__) && !defined(__LP64__)) || \
|
||||||
|
(defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \
|
||||||
|
(defined(__PPC__) && !defined(__PPC64__)) || \
|
||||||
|
(defined(__riscv) && __riscv_xlen == 32) || \
|
||||||
|
(defined(__s390__) && !defined(__s390x__)) || \
|
||||||
|
(defined(__sparc__) && !defined(__arch64__))
|
||||||
|
// On these architectures, implement mmap with mmap2.
|
||||||
|
static int pagesize = 0;
|
||||||
|
if (pagesize == 0) {
|
||||||
|
#if defined(__wasm__) || defined(__asmjs__)
|
||||||
|
pagesize = getpagesize();
|
||||||
|
#else
|
||||||
|
pagesize = sysconf(_SC_PAGESIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (offset < 0 || offset % pagesize != 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return MAP_FAILED;
|
||||||
|
}
|
||||||
|
#ifdef __BIONIC__
|
||||||
|
// SYS_mmap2 has problems on Android API level <= 16.
|
||||||
|
// Workaround by invoking __mmap2() instead.
|
||||||
|
return __mmap2(start, length, prot, flags, fd, offset / pagesize);
|
||||||
|
#else
|
||||||
|
return reinterpret_cast<void*>(
|
||||||
|
syscall(SYS_mmap2, start, length, prot, flags, fd,
|
||||||
|
static_cast<off_t>(offset / pagesize)));
|
||||||
|
#endif
|
||||||
|
#elif defined(__s390x__)
|
||||||
|
// On s390x, mmap() arguments are passed in memory.
|
||||||
|
unsigned long buf[6] = {reinterpret_cast<unsigned long>(start), // NOLINT
|
||||||
|
static_cast<unsigned long>(length), // NOLINT
|
||||||
|
static_cast<unsigned long>(prot), // NOLINT
|
||||||
|
static_cast<unsigned long>(flags), // NOLINT
|
||||||
|
static_cast<unsigned long>(fd), // NOLINT
|
||||||
|
static_cast<unsigned long>(offset)}; // NOLINT
|
||||||
|
return reinterpret_cast<void*>(syscall(SYS_mmap, buf));
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
// The x32 ABI has 32 bit longs, but the syscall interface is 64 bit.
|
||||||
|
// We need to explicitly cast to an unsigned 64 bit type to avoid implicit
|
||||||
|
// sign extension. We can't cast pointers directly because those are
|
||||||
|
// 32 bits, and gcc will dump ugly warnings about casting from a pointer
|
||||||
|
// to an integer of a different size. We also need to make sure __off64_t
|
||||||
|
// isn't truncated to 32-bits under x32.
|
||||||
|
#define MMAP_SYSCALL_ARG(x) ((uint64_t)(uintptr_t)(x))
|
||||||
|
return reinterpret_cast<void*>(
|
||||||
|
syscall(SYS_mmap, MMAP_SYSCALL_ARG(start), MMAP_SYSCALL_ARG(length),
|
||||||
|
MMAP_SYSCALL_ARG(prot), MMAP_SYSCALL_ARG(flags),
|
||||||
|
MMAP_SYSCALL_ARG(fd), static_cast<uint64_t>(offset)));
|
||||||
|
#undef MMAP_SYSCALL_ARG
|
||||||
|
#else // Remaining 64-bit aritectures.
|
||||||
|
static_assert(sizeof(unsigned long) == 8, "Platform is not 64-bit");
|
||||||
|
return reinterpret_cast<void*>(
|
||||||
|
syscall(SYS_mmap, start, length, prot, flags, fd, offset));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int DirectMunmap(void* start, size_t length) {
|
||||||
|
return static_cast<int>(syscall(SYS_munmap, start, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#else // !__linux__
|
||||||
|
|
||||||
|
// For non-linux platforms where we have mmap, just dispatch directly to the
|
||||||
|
// actual mmap()/munmap() methods.
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
|
||||||
|
off_t offset) {
|
||||||
|
return mmap(start, length, prot, flags, fd, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int DirectMunmap(void* start, size_t length) {
|
||||||
|
return munmap(start, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
|
#endif // ABSL_HAVE_MMAP
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
|
||||||
398
include/absl/base/internal/dynamic_annotations.h
Normal file
@ -0,0 +1,398 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// This file defines dynamic annotations for use with dynamic analysis tool
|
||||||
|
// such as valgrind, PIN, etc.
|
||||||
|
//
|
||||||
|
// Dynamic annotation is a source code annotation that affects the generated
|
||||||
|
// code (that is, the annotation is not a comment). Each such annotation is
|
||||||
|
// attached to a particular instruction and/or to a particular object (address)
|
||||||
|
// in the program.
|
||||||
|
//
|
||||||
|
// The annotations that should be used by users are macros in all upper-case
|
||||||
|
// (e.g., ANNOTATE_THREAD_NAME).
|
||||||
|
//
|
||||||
|
// Actual implementation of these macros may differ depending on the dynamic
|
||||||
|
// analysis tool being used.
|
||||||
|
//
|
||||||
|
// This file supports the following configurations:
|
||||||
|
// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
|
||||||
|
// In this case, macros expand to functions implemented by Thread Sanitizer,
|
||||||
|
// when building with TSan. When not provided an external implementation,
|
||||||
|
// dynamic_annotations.cc provides no-op implementations.
|
||||||
|
//
|
||||||
|
// - Static Clang thread-safety warnings enabled.
|
||||||
|
// When building with a Clang compiler that supports thread-safety warnings,
|
||||||
|
// a subset of annotations can be statically-checked at compile-time. We
|
||||||
|
// expand these macros to static-inline functions that can be analyzed for
|
||||||
|
// thread-safety, but afterwards elided when building the final binary.
|
||||||
|
//
|
||||||
|
// - All annotations are disabled.
|
||||||
|
// If neither Dynamic Annotations nor Clang thread-safety warnings are
|
||||||
|
// enabled, then all annotation-macros expand to empty.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Decide which features are enabled
|
||||||
|
|
||||||
|
#ifndef DYNAMIC_ANNOTATIONS_ENABLED
|
||||||
|
#define DYNAMIC_ANNOTATIONS_ENABLED 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__) && !defined(SWIG)
|
||||||
|
#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DYNAMIC_ANNOTATIONS_ENABLED != 0
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
|
||||||
|
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
|
||||||
|
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
|
||||||
|
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
|
||||||
|
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
|
||||||
|
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
|
||||||
|
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
|
||||||
|
|
||||||
|
// Clang provides limited support for static thread-safety analysis through a
|
||||||
|
// feature called Annotalysis. We configure macro-definitions according to
|
||||||
|
// whether Annotalysis support is available. When running in opt-mode, GCC
|
||||||
|
// will issue a warning, if these attributes are compiled. Only include them
|
||||||
|
// when compiling using Clang.
|
||||||
|
|
||||||
|
// ANNOTALYSIS_ENABLED == 1 when IGNORE_READ_ATTRIBUTE_ENABLED == 1
|
||||||
|
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED \
|
||||||
|
defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||||
|
// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
|
||||||
|
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
|
||||||
|
ABSL_INTERNAL_ANNOTALYSIS_ENABLED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Memory annotations are also made available to LLVM's Memory Sanitizer
|
||||||
|
#if defined(ABSL_HAVE_MEMORY_SANITIZER) && !defined(__native_client__)
|
||||||
|
#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
|
||||||
|
#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
|
||||||
|
#define ABSL_INTERNAL_END_EXTERN_C } // extern "C"
|
||||||
|
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
|
||||||
|
#define ABSL_INTERNAL_STATIC_INLINE inline
|
||||||
|
#else
|
||||||
|
#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty
|
||||||
|
#define ABSL_INTERNAL_END_EXTERN_C // empty
|
||||||
|
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
|
||||||
|
#define ABSL_INTERNAL_STATIC_INLINE static inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define race annotations.
|
||||||
|
|
||||||
|
#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// Annotations that suppress errors. It is usually better to express the
|
||||||
|
// program's synchronization using the other annotations, but these can be used
|
||||||
|
// when all else fails.
|
||||||
|
|
||||||
|
// Report that we may have a benign race at `pointer`, with size
|
||||||
|
// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
|
||||||
|
// point where `pointer` has been allocated, preferably close to the point
|
||||||
|
// where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC.
|
||||||
|
#define ANNOTATE_BENIGN_RACE(pointer, description) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
|
||||||
|
(__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
|
||||||
|
|
||||||
|
// Same as ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
|
||||||
|
// the memory range [`address`, `address`+`size`).
|
||||||
|
#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
|
||||||
|
(__FILE__, __LINE__, address, size, description)
|
||||||
|
|
||||||
|
// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
|
||||||
|
// This annotation could be useful if you want to skip expensive race analysis
|
||||||
|
// during some period of program execution, e.g. during initialization.
|
||||||
|
#define ANNOTATE_ENABLE_RACE_DETECTION(enable) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
|
||||||
|
(__FILE__, __LINE__, enable)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// Annotations useful for debugging.
|
||||||
|
|
||||||
|
// Report the current thread `name` to a race detector.
|
||||||
|
#define ANNOTATE_THREAD_NAME(name) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// Annotations useful when implementing locks. They are not normally needed by
|
||||||
|
// modules that merely use locks. The `lock` argument is a pointer to the lock
|
||||||
|
// object.
|
||||||
|
|
||||||
|
// Report that a lock has been created at address `lock`.
|
||||||
|
#define ANNOTATE_RWLOCK_CREATE(lock) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
|
||||||
|
|
||||||
|
// Report that a linker initialized lock has been created at address `lock`.
|
||||||
|
#ifdef ABSL_HAVE_THREAD_SANITIZER
|
||||||
|
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
|
||||||
|
(__FILE__, __LINE__, lock)
|
||||||
|
#else
|
||||||
|
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Report that the lock at address `lock` is about to be destroyed.
|
||||||
|
#define ANNOTATE_RWLOCK_DESTROY(lock) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
|
||||||
|
|
||||||
|
// Report that the lock at address `lock` has been acquired.
|
||||||
|
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
|
||||||
|
#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
|
||||||
|
(__FILE__, __LINE__, lock, is_w)
|
||||||
|
|
||||||
|
// Report that the lock at address `lock` is about to be released.
|
||||||
|
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
|
||||||
|
#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
|
||||||
|
(__FILE__, __LINE__, lock, is_w)
|
||||||
|
|
||||||
|
// Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
|
||||||
|
#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
|
||||||
|
namespace { \
|
||||||
|
class static_var##_annotator { \
|
||||||
|
public: \
|
||||||
|
static_var##_annotator() { \
|
||||||
|
ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \
|
||||||
|
#static_var ": " description); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
static static_var##_annotator the##static_var##_annotator; \
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0
|
||||||
|
|
||||||
|
#define ANNOTATE_RWLOCK_CREATE(lock) // empty
|
||||||
|
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty
|
||||||
|
#define ANNOTATE_RWLOCK_DESTROY(lock) // empty
|
||||||
|
#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty
|
||||||
|
#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty
|
||||||
|
#define ANNOTATE_BENIGN_RACE(address, description) // empty
|
||||||
|
#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty
|
||||||
|
#define ANNOTATE_THREAD_NAME(name) // empty
|
||||||
|
#define ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty
|
||||||
|
#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty
|
||||||
|
|
||||||
|
#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define memory annotations.
|
||||||
|
|
||||||
|
#if ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 1
|
||||||
|
|
||||||
|
#include <sanitizer/msan_interface.h>
|
||||||
|
|
||||||
|
#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
|
||||||
|
__msan_unpoison(address, size)
|
||||||
|
|
||||||
|
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
|
||||||
|
__msan_allocated_memory(address, size)
|
||||||
|
|
||||||
|
#else // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 0
|
||||||
|
|
||||||
|
#if DYNAMIC_ANNOTATIONS_ENABLED == 1
|
||||||
|
#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
|
||||||
|
do { \
|
||||||
|
(void)(address); \
|
||||||
|
(void)(size); \
|
||||||
|
} while (0)
|
||||||
|
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
|
||||||
|
do { \
|
||||||
|
(void)(address); \
|
||||||
|
(void)(size); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty
|
||||||
|
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define IGNORE_READS_BEGIN/_END attributes.
|
||||||
|
|
||||||
|
#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
|
||||||
|
__attribute((exclusive_lock_function("*")))
|
||||||
|
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
|
||||||
|
__attribute((unlock_function("*")))
|
||||||
|
|
||||||
|
#else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty
|
||||||
|
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty
|
||||||
|
|
||||||
|
#endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define IGNORE_READS_BEGIN/_END annotations.
|
||||||
|
|
||||||
|
#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
|
||||||
|
|
||||||
|
// Request the analysis tool to ignore all reads in the current thread until
|
||||||
|
// ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
|
||||||
|
// reads, while still checking other reads and all writes.
|
||||||
|
// See also ANNOTATE_UNPROTECTED_READ.
|
||||||
|
#define ANNOTATE_IGNORE_READS_BEGIN() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
// Stop ignoring reads.
|
||||||
|
#define ANNOTATE_IGNORE_READS_END() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
|
||||||
|
|
||||||
|
// When Annotalysis is enabled without Dynamic Annotations, the use of
|
||||||
|
// static-inline functions allows the annotations to be read at compile-time,
|
||||||
|
// while still letting the compiler elide the functions from the final build.
|
||||||
|
//
|
||||||
|
// TODO(delesley) -- The exclusive lock here ignores writes as well, but
|
||||||
|
// allows IGNORE_READS_AND_WRITES to work properly.
|
||||||
|
|
||||||
|
#define ANNOTATE_IGNORE_READS_BEGIN() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)()
|
||||||
|
|
||||||
|
#define ANNOTATE_IGNORE_READS_END() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)()
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ANNOTATE_IGNORE_READS_BEGIN() // empty
|
||||||
|
#define ANNOTATE_IGNORE_READS_END() // empty
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define IGNORE_WRITES_BEGIN/_END annotations.
|
||||||
|
|
||||||
|
#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
|
||||||
|
|
||||||
|
// Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
|
||||||
|
#define ANNOTATE_IGNORE_WRITES_BEGIN() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
// Stop ignoring writes.
|
||||||
|
#define ANNOTATE_IGNORE_WRITES_END() \
|
||||||
|
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ANNOTATE_IGNORE_WRITES_BEGIN() // empty
|
||||||
|
#define ANNOTATE_IGNORE_WRITES_END() // empty
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Define the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
|
||||||
|
// primitive annotations defined above.
|
||||||
|
//
|
||||||
|
// Instead of doing
|
||||||
|
// ANNOTATE_IGNORE_READS_BEGIN();
|
||||||
|
// ... = x;
|
||||||
|
// ANNOTATE_IGNORE_READS_END();
|
||||||
|
// one can use
|
||||||
|
// ... = ANNOTATE_UNPROTECTED_READ(x);
|
||||||
|
|
||||||
|
#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)
|
||||||
|
|
||||||
|
// Start ignoring all memory accesses (both reads and writes).
|
||||||
|
#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
|
||||||
|
do { \
|
||||||
|
ANNOTATE_IGNORE_READS_BEGIN(); \
|
||||||
|
ANNOTATE_IGNORE_WRITES_BEGIN(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
// Stop ignoring both reads and writes.
|
||||||
|
#define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
|
||||||
|
do { \
|
||||||
|
ANNOTATE_IGNORE_WRITES_END(); \
|
||||||
|
ANNOTATE_IGNORE_READS_END(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
// ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
|
||||||
|
#define ANNOTATE_UNPROTECTED_READ(x) \
|
||||||
|
absl::base_internal::AnnotateUnprotectedRead(x)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty
|
||||||
|
#define ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty
|
||||||
|
#define ANNOTATE_UNPROTECTED_READ(x) (x)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Address sanitizer annotations
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
// Describe the current state of a contiguous container such as e.g.
|
||||||
|
// std::vector or std::string. For more details see
|
||||||
|
// sanitizer/common_interface_defs.h, which is provided by the compiler.
|
||||||
|
#include <sanitizer/common_interface_defs.h>
|
||||||
|
|
||||||
|
#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
|
||||||
|
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
|
||||||
|
#define ADDRESS_SANITIZER_REDZONE(name) \
|
||||||
|
struct { \
|
||||||
|
char x[8] __attribute__((aligned(8))); \
|
||||||
|
} name
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
|
||||||
|
#define ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
|
||||||
|
|
||||||
|
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Undefine the macros intended only for this file.
|
||||||
|
|
||||||
|
#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
|
||||||
|
#undef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
|
||||||
|
#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
|
||||||
|
#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
|
||||||
|
#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
|
||||||
|
#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
|
||||||
|
#undef ABSL_INTERNAL_BEGIN_EXTERN_C
|
||||||
|
#undef ABSL_INTERNAL_END_EXTERN_C
|
||||||
|
#undef ABSL_INTERNAL_STATIC_INLINE
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
|
||||||
282
include/absl/base/internal/endian.h
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_ENDIAN_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_ENDIAN_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include "absl/base/casts.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
#include "absl/base/internal/unaligned_access.h"
|
||||||
|
#include "absl/base/port.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
inline uint64_t gbswap_64(uint64_t host_int) {
|
||||||
|
#if ABSL_HAVE_BUILTIN(__builtin_bswap64) || defined(__GNUC__)
|
||||||
|
return __builtin_bswap64(host_int);
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
return _byteswap_uint64(host_int);
|
||||||
|
#else
|
||||||
|
return (((host_int & uint64_t{0xFF}) << 56) |
|
||||||
|
((host_int & uint64_t{0xFF00}) << 40) |
|
||||||
|
((host_int & uint64_t{0xFF0000}) << 24) |
|
||||||
|
((host_int & uint64_t{0xFF000000}) << 8) |
|
||||||
|
((host_int & uint64_t{0xFF00000000}) >> 8) |
|
||||||
|
((host_int & uint64_t{0xFF0000000000}) >> 24) |
|
||||||
|
((host_int & uint64_t{0xFF000000000000}) >> 40) |
|
||||||
|
((host_int & uint64_t{0xFF00000000000000}) >> 56));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t gbswap_32(uint32_t host_int) {
|
||||||
|
#if ABSL_HAVE_BUILTIN(__builtin_bswap32) || defined(__GNUC__)
|
||||||
|
return __builtin_bswap32(host_int);
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
return _byteswap_ulong(host_int);
|
||||||
|
#else
|
||||||
|
return (((host_int & uint32_t{0xFF}) << 24) |
|
||||||
|
((host_int & uint32_t{0xFF00}) << 8) |
|
||||||
|
((host_int & uint32_t{0xFF0000}) >> 8) |
|
||||||
|
((host_int & uint32_t{0xFF000000}) >> 24));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t gbswap_16(uint16_t host_int) {
|
||||||
|
#if ABSL_HAVE_BUILTIN(__builtin_bswap16) || defined(__GNUC__)
|
||||||
|
return __builtin_bswap16(host_int);
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
return _byteswap_ushort(host_int);
|
||||||
|
#else
|
||||||
|
return (((host_int & uint16_t{0xFF}) << 8) |
|
||||||
|
((host_int & uint16_t{0xFF00}) >> 8));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ABSL_IS_LITTLE_ENDIAN
|
||||||
|
|
||||||
|
// Portable definitions for htonl (host-to-network) and friends on little-endian
|
||||||
|
// architectures.
|
||||||
|
inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); }
|
||||||
|
inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); }
|
||||||
|
inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); }
|
||||||
|
|
||||||
|
#elif defined ABSL_IS_BIG_ENDIAN
|
||||||
|
|
||||||
|
// Portable definitions for htonl (host-to-network) etc on big-endian
|
||||||
|
// architectures. These definitions are simpler since the host byte order is the
|
||||||
|
// same as network byte order.
|
||||||
|
inline uint16_t ghtons(uint16_t x) { return x; }
|
||||||
|
inline uint32_t ghtonl(uint32_t x) { return x; }
|
||||||
|
inline uint64_t ghtonll(uint64_t x) { return x; }
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error \
|
||||||
|
"Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \
|
||||||
|
"ABSL_IS_LITTLE_ENDIAN must be defined"
|
||||||
|
#endif // byte order
|
||||||
|
|
||||||
|
inline uint16_t gntohs(uint16_t x) { return ghtons(x); }
|
||||||
|
inline uint32_t gntohl(uint32_t x) { return ghtonl(x); }
|
||||||
|
inline uint64_t gntohll(uint64_t x) { return ghtonll(x); }
|
||||||
|
|
||||||
|
// Utilities to convert numbers between the current hosts's native byte
|
||||||
|
// order and little-endian byte order
|
||||||
|
//
|
||||||
|
// Load/Store methods are alignment safe
|
||||||
|
namespace little_endian {
|
||||||
|
// Conversion functions.
|
||||||
|
#ifdef ABSL_IS_LITTLE_ENDIAN
|
||||||
|
|
||||||
|
inline uint16_t FromHost16(uint16_t x) { return x; }
|
||||||
|
inline uint16_t ToHost16(uint16_t x) { return x; }
|
||||||
|
|
||||||
|
inline uint32_t FromHost32(uint32_t x) { return x; }
|
||||||
|
inline uint32_t ToHost32(uint32_t x) { return x; }
|
||||||
|
|
||||||
|
inline uint64_t FromHost64(uint64_t x) { return x; }
|
||||||
|
inline uint64_t ToHost64(uint64_t x) { return x; }
|
||||||
|
|
||||||
|
inline constexpr bool IsLittleEndian() { return true; }
|
||||||
|
|
||||||
|
#elif defined ABSL_IS_BIG_ENDIAN
|
||||||
|
|
||||||
|
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
|
||||||
|
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
|
||||||
|
|
||||||
|
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
|
||||||
|
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
|
||||||
|
|
||||||
|
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
|
||||||
|
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
|
||||||
|
|
||||||
|
inline constexpr bool IsLittleEndian() { return false; }
|
||||||
|
|
||||||
|
#endif /* ENDIAN */
|
||||||
|
|
||||||
|
inline uint8_t FromHost(uint8_t x) { return x; }
|
||||||
|
inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
|
||||||
|
inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
|
||||||
|
inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
|
||||||
|
inline uint8_t ToHost(uint8_t x) { return x; }
|
||||||
|
inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
|
||||||
|
inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
|
||||||
|
inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
|
||||||
|
|
||||||
|
inline int8_t FromHost(int8_t x) { return x; }
|
||||||
|
inline int16_t FromHost(int16_t x) {
|
||||||
|
return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
|
||||||
|
}
|
||||||
|
inline int32_t FromHost(int32_t x) {
|
||||||
|
return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
|
||||||
|
}
|
||||||
|
inline int64_t FromHost(int64_t x) {
|
||||||
|
return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
|
||||||
|
}
|
||||||
|
inline int8_t ToHost(int8_t x) { return x; }
|
||||||
|
inline int16_t ToHost(int16_t x) {
|
||||||
|
return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
|
||||||
|
}
|
||||||
|
inline int32_t ToHost(int32_t x) {
|
||||||
|
return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
|
||||||
|
}
|
||||||
|
inline int64_t ToHost(int64_t x) {
|
||||||
|
return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions to do unaligned loads and stores in little-endian order.
|
||||||
|
inline uint16_t Load16(const void *p) {
|
||||||
|
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Store16(void *p, uint16_t v) {
|
||||||
|
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t Load32(const void *p) {
|
||||||
|
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Store32(void *p, uint32_t v) {
|
||||||
|
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t Load64(const void *p) {
|
||||||
|
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Store64(void *p, uint64_t v) {
|
||||||
|
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace little_endian
|
||||||
|
|
||||||
|
// Utilities to convert numbers between the current hosts's native byte
|
||||||
|
// order and big-endian byte order (same as network byte order)
|
||||||
|
//
|
||||||
|
// Load/Store methods are alignment safe
|
||||||
|
namespace big_endian {
|
||||||
|
#ifdef ABSL_IS_LITTLE_ENDIAN
|
||||||
|
|
||||||
|
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
|
||||||
|
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
|
||||||
|
|
||||||
|
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
|
||||||
|
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
|
||||||
|
|
||||||
|
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
|
||||||
|
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
|
||||||
|
|
||||||
|
inline constexpr bool IsLittleEndian() { return true; }
|
||||||
|
|
||||||
|
#elif defined ABSL_IS_BIG_ENDIAN
|
||||||
|
|
||||||
|
inline uint16_t FromHost16(uint16_t x) { return x; }
|
||||||
|
inline uint16_t ToHost16(uint16_t x) { return x; }
|
||||||
|
|
||||||
|
inline uint32_t FromHost32(uint32_t x) { return x; }
|
||||||
|
inline uint32_t ToHost32(uint32_t x) { return x; }
|
||||||
|
|
||||||
|
inline uint64_t FromHost64(uint64_t x) { return x; }
|
||||||
|
inline uint64_t ToHost64(uint64_t x) { return x; }
|
||||||
|
|
||||||
|
inline constexpr bool IsLittleEndian() { return false; }
|
||||||
|
|
||||||
|
#endif /* ENDIAN */
|
||||||
|
|
||||||
|
inline uint8_t FromHost(uint8_t x) { return x; }
|
||||||
|
inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
|
||||||
|
inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
|
||||||
|
inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
|
||||||
|
inline uint8_t ToHost(uint8_t x) { return x; }
|
||||||
|
inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
|
||||||
|
inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
|
||||||
|
inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
|
||||||
|
|
||||||
|
inline int8_t FromHost(int8_t x) { return x; }
|
||||||
|
inline int16_t FromHost(int16_t x) {
|
||||||
|
return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
|
||||||
|
}
|
||||||
|
inline int32_t FromHost(int32_t x) {
|
||||||
|
return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
|
||||||
|
}
|
||||||
|
inline int64_t FromHost(int64_t x) {
|
||||||
|
return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
|
||||||
|
}
|
||||||
|
inline int8_t ToHost(int8_t x) { return x; }
|
||||||
|
inline int16_t ToHost(int16_t x) {
|
||||||
|
return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
|
||||||
|
}
|
||||||
|
inline int32_t ToHost(int32_t x) {
|
||||||
|
return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
|
||||||
|
}
|
||||||
|
inline int64_t ToHost(int64_t x) {
|
||||||
|
return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions to do unaligned loads and stores in big-endian order.
|
||||||
|
inline uint16_t Load16(const void *p) {
|
||||||
|
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Store16(void *p, uint16_t v) {
|
||||||
|
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t Load32(const void *p) {
|
||||||
|
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Store32(void *p, uint32_t v) {
|
||||||
|
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t Load64(const void *p) {
|
||||||
|
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Store64(void *p, uint64_t v) {
|
||||||
|
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace big_endian
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_ENDIAN_H_
|
||||||
43
include/absl/base/internal/errno_saver.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
// `ErrnoSaver` captures the value of `errno` upon construction and restores it
|
||||||
|
// upon deletion. It is used in low-level code and must be super fast. Do not
|
||||||
|
// add instrumentation, even in debug modes.
|
||||||
|
class ErrnoSaver {
|
||||||
|
public:
|
||||||
|
ErrnoSaver() : saved_errno_(errno) {}
|
||||||
|
~ErrnoSaver() { errno = saved_errno_; }
|
||||||
|
int operator()() const { return saved_errno_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int saved_errno_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
|
||||||
1109
include/absl/base/internal/exception_safety_testing.h
Normal file
42
include/absl/base/internal/exception_testing.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Testing utilities for ABSL types which throw exceptions.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
// ABSL_BASE_INTERNAL_EXPECT_FAIL tests either for a specified thrown exception
|
||||||
|
// if exceptions are enabled, or for death with a specified text in the error
|
||||||
|
// message
|
||||||
|
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||||
|
|
||||||
|
#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
|
||||||
|
EXPECT_THROW(expr, exception_t)
|
||||||
|
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
// Android asserts do not log anywhere that gtest can currently inspect.
|
||||||
|
// So we expect exit, but cannot match the message.
|
||||||
|
#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
|
||||||
|
EXPECT_DEATH(expr, ".*")
|
||||||
|
#else
|
||||||
|
#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
|
||||||
|
EXPECT_DEATH_IF_SUPPORTED(expr, text)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_
|
||||||
50
include/absl/base/internal/fast_type_id.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2020 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
struct FastTypeTag {
|
||||||
|
constexpr static char dummy_var = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||||
|
template <typename Type>
|
||||||
|
constexpr char FastTypeTag<Type>::dummy_var;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
|
||||||
|
// passed-in type. These are meant to be good match for keys into maps or
|
||||||
|
// straight up comparisons.
|
||||||
|
using FastTypeIdType = const void*;
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
constexpr inline FastTypeIdType FastTypeId() {
|
||||||
|
return &FastTypeTag<Type>::dummy_var;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
|
||||||
51
include/absl/base/internal/hide_ptr.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2018 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_HIDE_PTR_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_HIDE_PTR_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
// Arbitrary value with high bits set. Xor'ing with it is unlikely
|
||||||
|
// to map one valid pointer to another valid pointer.
|
||||||
|
constexpr uintptr_t HideMask() {
|
||||||
|
return (uintptr_t{0xF03A5F7BU} << (sizeof(uintptr_t) - 4) * 8) | 0xF03A5F7BU;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide a pointer from the leak checker. For internal use only.
|
||||||
|
// Differs from absl::IgnoreLeak(ptr) in that absl::IgnoreLeak(ptr) causes ptr
|
||||||
|
// and all objects reachable from ptr to be ignored by the leak checker.
|
||||||
|
template <class T>
|
||||||
|
inline uintptr_t HidePtr(T* ptr) {
|
||||||
|
return reinterpret_cast<uintptr_t>(ptr) ^ HideMask();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a pointer that has been hidden from the leak checker.
|
||||||
|
// For internal use only.
|
||||||
|
template <class T>
|
||||||
|
inline T* UnhidePtr(uintptr_t hidden) {
|
||||||
|
return reinterpret_cast<T*>(hidden ^ HideMask());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_HIDE_PTR_H_
|
||||||
37
include/absl/base/internal/identity.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_IDENTITY_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_IDENTITY_H_
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct identity {
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using identity_t = typename identity<T>::type;
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_IDENTITY_H_
|
||||||
107
include/absl/base/internal/inline_variable.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "absl/base/internal/identity.h"
|
||||||
|
|
||||||
|
// File:
|
||||||
|
// This file define a macro that allows the creation of or emulation of C++17
|
||||||
|
// inline variables based on whether or not the feature is supported.
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Macro: ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init)
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
// Expands to the equivalent of an inline constexpr instance of the specified
|
||||||
|
// `type` and `name`, initialized to the value `init`. If the compiler being
|
||||||
|
// used is detected as supporting actual inline variables as a language
|
||||||
|
// feature, then the macro expands to an actual inline variable definition.
|
||||||
|
//
|
||||||
|
// Requires:
|
||||||
|
// `type` is a type that is usable in an extern variable declaration.
|
||||||
|
//
|
||||||
|
// Requires: `name` is a valid identifier
|
||||||
|
//
|
||||||
|
// Requires:
|
||||||
|
// `init` is an expression that can be used in the following definition:
|
||||||
|
// constexpr type name = init;
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// // Equivalent to: `inline constexpr size_t variant_npos = -1;`
|
||||||
|
// ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
|
||||||
|
//
|
||||||
|
// Differences in implementation:
|
||||||
|
// For a direct, language-level inline variable, decltype(name) will be the
|
||||||
|
// type that was specified along with const qualification, whereas for
|
||||||
|
// emulated inline variables, decltype(name) may be different (in practice
|
||||||
|
// it will likely be a reference type).
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifdef __cpp_inline_variables
|
||||||
|
|
||||||
|
// Clang's -Wmissing-variable-declarations option erroneously warned that
|
||||||
|
// inline constexpr objects need to be pre-declared. This has now been fixed,
|
||||||
|
// but we will need to support this workaround for people building with older
|
||||||
|
// versions of clang.
|
||||||
|
//
|
||||||
|
// Bug: https://bugs.llvm.org/show_bug.cgi?id=35862
|
||||||
|
//
|
||||||
|
// Note:
|
||||||
|
// identity_t is used here so that the const and name are in the
|
||||||
|
// appropriate place for pointer types, reference types, function pointer
|
||||||
|
// types, etc..
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define ABSL_INTERNAL_EXTERN_DECL(type, name) \
|
||||||
|
extern const ::absl::internal::identity_t<type> name;
|
||||||
|
#else // Otherwise, just define the macro to do nothing.
|
||||||
|
#define ABSL_INTERNAL_EXTERN_DECL(type, name)
|
||||||
|
#endif // defined(__clang__)
|
||||||
|
|
||||||
|
// See above comment at top of file for details.
|
||||||
|
#define ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) \
|
||||||
|
ABSL_INTERNAL_EXTERN_DECL(type, name) \
|
||||||
|
inline constexpr ::absl::internal::identity_t<type> name = init
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// See above comment at top of file for details.
|
||||||
|
//
|
||||||
|
// Note:
|
||||||
|
// identity_t is used here so that the const and name are in the
|
||||||
|
// appropriate place for pointer types, reference types, function pointer
|
||||||
|
// types, etc..
|
||||||
|
#define ABSL_INTERNAL_INLINE_CONSTEXPR(var_type, name, init) \
|
||||||
|
template <class /*AbslInternalDummy*/ = void> \
|
||||||
|
struct AbslInternalInlineVariableHolder##name { \
|
||||||
|
static constexpr ::absl::internal::identity_t<var_type> kInstance = init; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
template <class AbslInternalDummy> \
|
||||||
|
constexpr ::absl::internal::identity_t<var_type> \
|
||||||
|
AbslInternalInlineVariableHolder##name<AbslInternalDummy>::kInstance; \
|
||||||
|
\
|
||||||
|
static constexpr const ::absl::internal::identity_t<var_type>& \
|
||||||
|
name = /* NOLINT */ \
|
||||||
|
AbslInternalInlineVariableHolder##name<>::kInstance; \
|
||||||
|
static_assert(sizeof(void (*)(decltype(name))) != 0, \
|
||||||
|
"Silence unused variable warnings.")
|
||||||
|
|
||||||
|
#endif // __cpp_inline_variables
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
|
||||||
46
include/absl/base/internal/inline_variable_testing.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INLINE_VARIABLE_TESTING_H_
|
||||||
|
#define ABSL_BASE_INLINE_VARIABLE_TESTING_H_
|
||||||
|
|
||||||
|
#include "absl/base/internal/inline_variable.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace inline_variable_testing_internal {
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
int value = 5;
|
||||||
|
};
|
||||||
|
|
||||||
|
ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, inline_variable_foo, {});
|
||||||
|
ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, other_inline_variable_foo, {});
|
||||||
|
|
||||||
|
ABSL_INTERNAL_INLINE_CONSTEXPR(int, inline_variable_int, 5);
|
||||||
|
ABSL_INTERNAL_INLINE_CONSTEXPR(int, other_inline_variable_int, 5);
|
||||||
|
|
||||||
|
ABSL_INTERNAL_INLINE_CONSTEXPR(void(*)(), inline_variable_fun_ptr, nullptr);
|
||||||
|
|
||||||
|
const Foo& get_foo_a();
|
||||||
|
const Foo& get_foo_b();
|
||||||
|
|
||||||
|
const int& get_int_a();
|
||||||
|
const int& get_int_b();
|
||||||
|
|
||||||
|
} // namespace inline_variable_testing_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_
|
||||||
241
include/absl/base/internal/invoke.h
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// absl::base_internal::invoke(f, args...) is an implementation of
|
||||||
|
// INVOKE(f, args...) from section [func.require] of the C++ standard.
|
||||||
|
// When compiled as C++17 and later versions, it is implemented as an alias of
|
||||||
|
// std::invoke.
|
||||||
|
//
|
||||||
|
// [func.require]
|
||||||
|
// Define INVOKE (f, t1, t2, ..., tN) as follows:
|
||||||
|
// 1. (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
|
||||||
|
// and t1 is an object of type T or a reference to an object of type T or a
|
||||||
|
// reference to an object of a type derived from T;
|
||||||
|
// 2. ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
|
||||||
|
// class T and t1 is not one of the types described in the previous item;
|
||||||
|
// 3. t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
|
||||||
|
// an object of type T or a reference to an object of type T or a reference
|
||||||
|
// to an object of a type derived from T;
|
||||||
|
// 4. (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
|
||||||
|
// is not one of the types described in the previous item;
|
||||||
|
// 5. f(t1, t2, ..., tN) in all other cases.
|
||||||
|
//
|
||||||
|
// The implementation is SFINAE-friendly: substitution failure within invoke()
|
||||||
|
// isn't an error.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_INVOKE_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_INVOKE_H_
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
using std::invoke;
|
||||||
|
using std::invoke_result_t;
|
||||||
|
using std::is_invocable_r;
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#else // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "absl/meta/type_traits.h"
|
||||||
|
|
||||||
|
// The following code is internal implementation detail. See the comment at the
|
||||||
|
// top of this file for the API documentation.
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
// The five classes below each implement one of the clauses from the definition
|
||||||
|
// of INVOKE. The inner class template Accept<F, Args...> checks whether the
|
||||||
|
// clause is applicable; static function template Invoke(f, args...) does the
|
||||||
|
// invocation.
|
||||||
|
//
|
||||||
|
// By separating the clause selection logic from invocation we make sure that
|
||||||
|
// Invoke() does exactly what the standard says.
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
struct StrippedAccept {
|
||||||
|
template <typename... Args>
|
||||||
|
struct Accept : Derived::template AcceptImpl<typename std::remove_cv<
|
||||||
|
typename std::remove_reference<Args>::type>::type...> {};
|
||||||
|
};
|
||||||
|
|
||||||
|
// (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
|
||||||
|
// and t1 is an object of type T or a reference to an object of type T or a
|
||||||
|
// reference to an object of a type derived from T.
|
||||||
|
struct MemFunAndRef : StrippedAccept<MemFunAndRef> {
|
||||||
|
template <typename... Args>
|
||||||
|
struct AcceptImpl : std::false_type {};
|
||||||
|
|
||||||
|
template <typename MemFunType, typename C, typename Obj, typename... Args>
|
||||||
|
struct AcceptImpl<MemFunType C::*, Obj, Args...>
|
||||||
|
: std::integral_constant<bool, std::is_base_of<C, Obj>::value &&
|
||||||
|
absl::is_function<MemFunType>::value> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename MemFun, typename Obj, typename... Args>
|
||||||
|
static decltype((std::declval<Obj>().*
|
||||||
|
std::declval<MemFun>())(std::declval<Args>()...))
|
||||||
|
Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) {
|
||||||
|
// Ignore bogus GCC warnings on this line.
|
||||||
|
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101436 for similar example.
|
||||||
|
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||||
|
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||||
|
#endif
|
||||||
|
return (std::forward<Obj>(obj).*
|
||||||
|
std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
|
||||||
|
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
|
||||||
|
// class T and t1 is not one of the types described in the previous item.
|
||||||
|
struct MemFunAndPtr : StrippedAccept<MemFunAndPtr> {
|
||||||
|
template <typename... Args>
|
||||||
|
struct AcceptImpl : std::false_type {};
|
||||||
|
|
||||||
|
template <typename MemFunType, typename C, typename Ptr, typename... Args>
|
||||||
|
struct AcceptImpl<MemFunType C::*, Ptr, Args...>
|
||||||
|
: std::integral_constant<bool, !std::is_base_of<C, Ptr>::value &&
|
||||||
|
absl::is_function<MemFunType>::value> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename MemFun, typename Ptr, typename... Args>
|
||||||
|
static decltype(((*std::declval<Ptr>()).*
|
||||||
|
std::declval<MemFun>())(std::declval<Args>()...))
|
||||||
|
Invoke(MemFun&& mem_fun, Ptr&& ptr, Args&&... args) {
|
||||||
|
return ((*std::forward<Ptr>(ptr)).*
|
||||||
|
std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
|
||||||
|
// an object of type T or a reference to an object of type T or a reference
|
||||||
|
// to an object of a type derived from T.
|
||||||
|
struct DataMemAndRef : StrippedAccept<DataMemAndRef> {
|
||||||
|
template <typename... Args>
|
||||||
|
struct AcceptImpl : std::false_type {};
|
||||||
|
|
||||||
|
template <typename R, typename C, typename Obj>
|
||||||
|
struct AcceptImpl<R C::*, Obj>
|
||||||
|
: std::integral_constant<bool, std::is_base_of<C, Obj>::value &&
|
||||||
|
!absl::is_function<R>::value> {};
|
||||||
|
|
||||||
|
template <typename DataMem, typename Ref>
|
||||||
|
static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke(
|
||||||
|
DataMem&& data_mem, Ref&& ref) {
|
||||||
|
return std::forward<Ref>(ref).*std::forward<DataMem>(data_mem);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
|
||||||
|
// is not one of the types described in the previous item.
|
||||||
|
struct DataMemAndPtr : StrippedAccept<DataMemAndPtr> {
|
||||||
|
template <typename... Args>
|
||||||
|
struct AcceptImpl : std::false_type {};
|
||||||
|
|
||||||
|
template <typename R, typename C, typename Ptr>
|
||||||
|
struct AcceptImpl<R C::*, Ptr>
|
||||||
|
: std::integral_constant<bool, !std::is_base_of<C, Ptr>::value &&
|
||||||
|
!absl::is_function<R>::value> {};
|
||||||
|
|
||||||
|
template <typename DataMem, typename Ptr>
|
||||||
|
static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke(
|
||||||
|
DataMem&& data_mem, Ptr&& ptr) {
|
||||||
|
return (*std::forward<Ptr>(ptr)).*std::forward<DataMem>(data_mem);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// f(t1, t2, ..., tN) in all other cases.
|
||||||
|
struct Callable {
|
||||||
|
// Callable doesn't have Accept because it's the last clause that gets picked
|
||||||
|
// when none of the previous clauses are applicable.
|
||||||
|
template <typename F, typename... Args>
|
||||||
|
static decltype(std::declval<F>()(std::declval<Args>()...)) Invoke(
|
||||||
|
F&& f, Args&&... args) {
|
||||||
|
return std::forward<F>(f)(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolves to the first matching clause.
|
||||||
|
template <typename... Args>
|
||||||
|
struct Invoker {
|
||||||
|
typedef typename std::conditional<
|
||||||
|
MemFunAndRef::Accept<Args...>::value, MemFunAndRef,
|
||||||
|
typename std::conditional<
|
||||||
|
MemFunAndPtr::Accept<Args...>::value, MemFunAndPtr,
|
||||||
|
typename std::conditional<
|
||||||
|
DataMemAndRef::Accept<Args...>::value, DataMemAndRef,
|
||||||
|
typename std::conditional<DataMemAndPtr::Accept<Args...>::value,
|
||||||
|
DataMemAndPtr, Callable>::type>::type>::
|
||||||
|
type>::type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The result type of Invoke<F, Args...>.
|
||||||
|
template <typename F, typename... Args>
|
||||||
|
using invoke_result_t = decltype(Invoker<F, Args...>::type::Invoke(
|
||||||
|
std::declval<F>(), std::declval<Args>()...));
|
||||||
|
|
||||||
|
// Invoke(f, args...) is an implementation of INVOKE(f, args...) from section
|
||||||
|
// [func.require] of the C++ standard.
|
||||||
|
template <typename F, typename... Args>
|
||||||
|
invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) {
|
||||||
|
return Invoker<F, Args...>::type::Invoke(std::forward<F>(f),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename AlwaysVoid, typename, typename, typename...>
|
||||||
|
struct IsInvocableRImpl : std::false_type {};
|
||||||
|
|
||||||
|
template <typename R, typename F, typename... Args>
|
||||||
|
struct IsInvocableRImpl<
|
||||||
|
absl::void_t<absl::base_internal::invoke_result_t<F, Args...> >, R, F,
|
||||||
|
Args...>
|
||||||
|
: std::integral_constant<
|
||||||
|
bool,
|
||||||
|
std::is_convertible<absl::base_internal::invoke_result_t<F, Args...>,
|
||||||
|
R>::value ||
|
||||||
|
std::is_void<R>::value> {};
|
||||||
|
|
||||||
|
// Type trait whose member `value` is true if invoking `F` with `Args` is valid,
|
||||||
|
// and either the return type is convertible to `R`, or `R` is void.
|
||||||
|
// C++11-compatible version of `std::is_invocable_r`.
|
||||||
|
template <typename R, typename F, typename... Args>
|
||||||
|
using is_invocable_r = IsInvocableRImpl<void, R, F, Args...>;
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_INVOKE_H_
|
||||||
126
include/absl/base/internal/low_level_alloc.h
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
|
||||||
|
|
||||||
|
// A simple thread-safe memory allocator that does not depend on
|
||||||
|
// mutexes or thread-specific data. It is intended to be used
|
||||||
|
// sparingly, and only when malloc() would introduce an unwanted
|
||||||
|
// dependency, such as inside the heap-checker, or the Mutex
|
||||||
|
// implementation.
|
||||||
|
|
||||||
|
// IWYU pragma: private, include "base/low_level_alloc.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
// LowLevelAlloc requires that the platform support low-level
|
||||||
|
// allocation of virtual memory. Platforms lacking this cannot use
|
||||||
|
// LowLevelAlloc.
|
||||||
|
#ifdef ABSL_LOW_LEVEL_ALLOC_MISSING
|
||||||
|
#error ABSL_LOW_LEVEL_ALLOC_MISSING cannot be directly set
|
||||||
|
#elif !defined(ABSL_HAVE_MMAP) && !defined(_WIN32)
|
||||||
|
#define ABSL_LOW_LEVEL_ALLOC_MISSING 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows or
|
||||||
|
// asm.js / WebAssembly.
|
||||||
|
// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
|
||||||
|
// for more information.
|
||||||
|
#ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
|
||||||
|
#error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set
|
||||||
|
#elif defined(_WIN32) || defined(__asmjs__) || defined(__wasm__)
|
||||||
|
#define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include "absl/base/port.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
class LowLevelAlloc {
|
||||||
|
public:
|
||||||
|
struct Arena; // an arena from which memory may be allocated
|
||||||
|
|
||||||
|
// Returns a pointer to a block of at least "request" bytes
|
||||||
|
// that have been newly allocated from the specific arena.
|
||||||
|
// for Alloc() call the DefaultArena() is used.
|
||||||
|
// Returns 0 if passed request==0.
|
||||||
|
// Does not return 0 under other circumstances; it crashes if memory
|
||||||
|
// is not available.
|
||||||
|
static void *Alloc(size_t request) ABSL_ATTRIBUTE_SECTION(malloc_hook);
|
||||||
|
static void *AllocWithArena(size_t request, Arena *arena)
|
||||||
|
ABSL_ATTRIBUTE_SECTION(malloc_hook);
|
||||||
|
|
||||||
|
// Deallocates a region of memory that was previously allocated with
|
||||||
|
// Alloc(). Does nothing if passed 0. "s" must be either 0,
|
||||||
|
// or must have been returned from a call to Alloc() and not yet passed to
|
||||||
|
// Free() since that call to Alloc(). The space is returned to the arena
|
||||||
|
// from which it was allocated.
|
||||||
|
static void Free(void *s) ABSL_ATTRIBUTE_SECTION(malloc_hook);
|
||||||
|
|
||||||
|
// ABSL_ATTRIBUTE_SECTION(malloc_hook) for Alloc* and Free
|
||||||
|
// are to put all callers of MallocHook::Invoke* in this module
|
||||||
|
// into special section,
|
||||||
|
// so that MallocHook::GetCallerStackTrace can function accurately.
|
||||||
|
|
||||||
|
// Create a new arena.
|
||||||
|
// The root metadata for the new arena is allocated in the
|
||||||
|
// meta_data_arena; the DefaultArena() can be passed for meta_data_arena.
|
||||||
|
// These values may be ored into flags:
|
||||||
|
enum {
|
||||||
|
// Report calls to Alloc() and Free() via the MallocHook interface.
|
||||||
|
// Set in the DefaultArena.
|
||||||
|
kCallMallocHook = 0x0001,
|
||||||
|
|
||||||
|
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
|
||||||
|
// Make calls to Alloc(), Free() be async-signal-safe. Not set in
|
||||||
|
// DefaultArena(). Not supported on all platforms.
|
||||||
|
kAsyncSignalSafe = 0x0002,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
// Construct a new arena. The allocation of the underlying metadata honors
|
||||||
|
// the provided flags. For example, the call NewArena(kAsyncSignalSafe)
|
||||||
|
// is itself async-signal-safe, as well as generatating an arena that provides
|
||||||
|
// async-signal-safe Alloc/Free.
|
||||||
|
static Arena *NewArena(int32_t flags);
|
||||||
|
|
||||||
|
// Destroys an arena allocated by NewArena and returns true,
|
||||||
|
// provided no allocated blocks remain in the arena.
|
||||||
|
// If allocated blocks remain in the arena, does nothing and
|
||||||
|
// returns false.
|
||||||
|
// It is illegal to attempt to destroy the DefaultArena().
|
||||||
|
static bool DeleteArena(Arena *arena);
|
||||||
|
|
||||||
|
// The default arena that always exists.
|
||||||
|
static Arena *DefaultArena();
|
||||||
|
|
||||||
|
private:
|
||||||
|
LowLevelAlloc(); // no instances
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
|
||||||
134
include/absl/base/internal/low_level_scheduling.h
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Core interfaces and definitions used by by low-level interfaces such as
|
||||||
|
// SpinLock.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
|
||||||
|
|
||||||
|
#include "absl/base/internal/raw_logging.h"
|
||||||
|
#include "absl/base/internal/scheduling_mode.h"
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
|
||||||
|
// The following two declarations exist so SchedulingGuard may friend them with
|
||||||
|
// the appropriate language linkage. These callbacks allow libc internals, such
|
||||||
|
// as function level statics, to schedule cooperatively when locking.
|
||||||
|
extern "C" bool __google_disable_rescheduling(void);
|
||||||
|
extern "C" void __google_enable_rescheduling(bool disable_result);
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
class CondVar;
|
||||||
|
class Mutex;
|
||||||
|
|
||||||
|
namespace synchronization_internal {
|
||||||
|
int MutexDelay(int32_t c, int mode);
|
||||||
|
} // namespace synchronization_internal
|
||||||
|
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
class SchedulingHelper; // To allow use of SchedulingGuard.
|
||||||
|
class SpinLock; // To allow use of SchedulingGuard.
|
||||||
|
|
||||||
|
// SchedulingGuard
|
||||||
|
// Provides guard semantics that may be used to disable cooperative rescheduling
|
||||||
|
// of the calling thread within specific program blocks. This is used to
|
||||||
|
// protect resources (e.g. low-level SpinLocks or Domain code) that cooperative
|
||||||
|
// scheduling depends on.
|
||||||
|
//
|
||||||
|
// Domain implementations capable of rescheduling in reaction to involuntary
|
||||||
|
// kernel thread actions (e.g blocking due to a pagefault or syscall) must
|
||||||
|
// guarantee that an annotated thread is not allowed to (cooperatively)
|
||||||
|
// reschedule until the annotated region is complete.
|
||||||
|
//
|
||||||
|
// It is an error to attempt to use a cooperatively scheduled resource (e.g.
|
||||||
|
// Mutex) within a rescheduling-disabled region.
|
||||||
|
//
|
||||||
|
// All methods are async-signal safe.
|
||||||
|
class SchedulingGuard {
|
||||||
|
public:
|
||||||
|
// Returns true iff the calling thread may be cooperatively rescheduled.
|
||||||
|
static bool ReschedulingIsAllowed();
|
||||||
|
SchedulingGuard(const SchedulingGuard&) = delete;
|
||||||
|
SchedulingGuard& operator=(const SchedulingGuard&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Disable cooperative rescheduling of the calling thread. It may still
|
||||||
|
// initiate scheduling operations (e.g. wake-ups), however, it may not itself
|
||||||
|
// reschedule. Nestable. The returned result is opaque, clients should not
|
||||||
|
// attempt to interpret it.
|
||||||
|
// REQUIRES: Result must be passed to a pairing EnableScheduling().
|
||||||
|
static bool DisableRescheduling();
|
||||||
|
|
||||||
|
// Marks the end of a rescheduling disabled region, previously started by
|
||||||
|
// DisableRescheduling().
|
||||||
|
// REQUIRES: Pairs with innermost call (and result) of DisableRescheduling().
|
||||||
|
static void EnableRescheduling(bool disable_result);
|
||||||
|
|
||||||
|
// A scoped helper for {Disable, Enable}Rescheduling().
|
||||||
|
// REQUIRES: destructor must run in same thread as constructor.
|
||||||
|
struct ScopedDisable {
|
||||||
|
ScopedDisable() { disabled = SchedulingGuard::DisableRescheduling(); }
|
||||||
|
~ScopedDisable() { SchedulingGuard::EnableRescheduling(disabled); }
|
||||||
|
|
||||||
|
bool disabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A scoped helper to enable rescheduling temporarily.
|
||||||
|
// REQUIRES: destructor must run in same thread as constructor.
|
||||||
|
class ScopedEnable {
|
||||||
|
public:
|
||||||
|
ScopedEnable();
|
||||||
|
~ScopedEnable();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int scheduling_disabled_depth_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Access to SchedulingGuard is explicitly permitted.
|
||||||
|
friend class absl::CondVar;
|
||||||
|
friend class absl::Mutex;
|
||||||
|
friend class SchedulingHelper;
|
||||||
|
friend class SpinLock;
|
||||||
|
friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// End of public interfaces.
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
inline bool SchedulingGuard::ReschedulingIsAllowed() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool SchedulingGuard::DisableRescheduling() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SchedulingGuard::ScopedEnable::ScopedEnable()
|
||||||
|
: scheduling_disabled_depth_(0) {}
|
||||||
|
inline SchedulingGuard::ScopedEnable::~ScopedEnable() {
|
||||||
|
ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
|
||||||
52
include/absl/base/internal/per_thread_tls.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
|
||||||
|
|
||||||
|
// This header defines two macros:
|
||||||
|
//
|
||||||
|
// If the platform supports thread-local storage:
|
||||||
|
//
|
||||||
|
// * ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a
|
||||||
|
// thread-local variable
|
||||||
|
// * ABSL_PER_THREAD_TLS is 1
|
||||||
|
//
|
||||||
|
// Otherwise:
|
||||||
|
//
|
||||||
|
// * ABSL_PER_THREAD_TLS_KEYWORD is empty
|
||||||
|
// * ABSL_PER_THREAD_TLS is 0
|
||||||
|
//
|
||||||
|
// Microsoft C supports thread-local storage.
|
||||||
|
// GCC supports it if the appropriate version of glibc is available,
|
||||||
|
// which the programmer can indicate by defining ABSL_HAVE_TLS
|
||||||
|
|
||||||
|
#include "absl/base/port.h" // For ABSL_HAVE_TLS
|
||||||
|
|
||||||
|
#if defined(ABSL_PER_THREAD_TLS)
|
||||||
|
#error ABSL_PER_THREAD_TLS cannot be directly set
|
||||||
|
#elif defined(ABSL_PER_THREAD_TLS_KEYWORD)
|
||||||
|
#error ABSL_PER_THREAD_TLS_KEYWORD cannot be directly set
|
||||||
|
#elif defined(ABSL_HAVE_TLS)
|
||||||
|
#define ABSL_PER_THREAD_TLS_KEYWORD __thread
|
||||||
|
#define ABSL_PER_THREAD_TLS 1
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define ABSL_PER_THREAD_TLS_KEYWORD __declspec(thread)
|
||||||
|
#define ABSL_PER_THREAD_TLS 1
|
||||||
|
#else
|
||||||
|
#define ABSL_PER_THREAD_TLS_KEYWORD
|
||||||
|
#define ABSL_PER_THREAD_TLS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
|
||||||
138
include/absl/base/internal/prefetch.h
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// Copyright 2022 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_PREFETCH_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_PREFETCH_H_
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
#ifdef __SSE__
|
||||||
|
#include <xmmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && defined(ABSL_INTERNAL_HAVE_SSE)
|
||||||
|
#include <intrin.h>
|
||||||
|
#pragma intrinsic(_mm_prefetch)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Compatibility wrappers around __builtin_prefetch, to prefetch data
|
||||||
|
// for read if supported by the toolchain.
|
||||||
|
|
||||||
|
// Move data into the cache before it is read, or "prefetch" it.
|
||||||
|
//
|
||||||
|
// The value of `addr` is the address of the memory to prefetch. If
|
||||||
|
// the target and compiler support it, data prefetch instructions are
|
||||||
|
// generated. If the prefetch is done some time before the memory is
|
||||||
|
// read, it may be in the cache by the time the read occurs.
|
||||||
|
//
|
||||||
|
// The function names specify the temporal locality heuristic applied,
|
||||||
|
// using the names of Intel prefetch instructions:
|
||||||
|
//
|
||||||
|
// T0 - high degree of temporal locality; data should be left in as
|
||||||
|
// many levels of the cache possible
|
||||||
|
// T1 - moderate degree of temporal locality
|
||||||
|
// T2 - low degree of temporal locality
|
||||||
|
// Nta - no temporal locality, data need not be left in the cache
|
||||||
|
// after the read
|
||||||
|
//
|
||||||
|
// Incorrect or gratuitous use of these functions can degrade
|
||||||
|
// performance, so use them only when representative benchmarks show
|
||||||
|
// an improvement.
|
||||||
|
//
|
||||||
|
// Example usage:
|
||||||
|
//
|
||||||
|
// absl::base_internal::PrefetchT0(addr);
|
||||||
|
//
|
||||||
|
// Currently, the different prefetch calls behave on some Intel
|
||||||
|
// architectures as follows:
|
||||||
|
//
|
||||||
|
// SNB..SKL SKX
|
||||||
|
// PrefetchT0() L1/L2/L3 L1/L2
|
||||||
|
// PrefetchT1() L2/L3 L2
|
||||||
|
// PrefetchT2() L2/L3 L2
|
||||||
|
// PrefetchNta() L1/--/L3 L1*
|
||||||
|
//
|
||||||
|
// * On SKX PrefetchNta() will bring the line into L1 but will evict
|
||||||
|
// from L3 cache. This might result in surprising behavior.
|
||||||
|
//
|
||||||
|
// SNB = Sandy Bridge, SKL = Skylake, SKX = Skylake Xeon.
|
||||||
|
//
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
void PrefetchT0(const void* addr);
|
||||||
|
void PrefetchT1(const void* addr);
|
||||||
|
void PrefetchT2(const void* addr);
|
||||||
|
void PrefetchNta(const void* addr);
|
||||||
|
|
||||||
|
// Implementation details follow.
|
||||||
|
|
||||||
|
#if ABSL_HAVE_BUILTIN(__builtin_prefetch) || defined(__GNUC__)
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_HAVE_PREFETCH 1
|
||||||
|
|
||||||
|
// See __builtin_prefetch:
|
||||||
|
// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html.
|
||||||
|
//
|
||||||
|
// These functions speculatively load for read only. This is
|
||||||
|
// safe for all currently supported platforms. However, prefetch for
|
||||||
|
// store may have problems depending on the target platform.
|
||||||
|
//
|
||||||
|
inline void PrefetchT0(const void* addr) {
|
||||||
|
// Note: this uses prefetcht0 on Intel.
|
||||||
|
__builtin_prefetch(addr, 0, 3);
|
||||||
|
}
|
||||||
|
inline void PrefetchT1(const void* addr) {
|
||||||
|
// Note: this uses prefetcht1 on Intel.
|
||||||
|
__builtin_prefetch(addr, 0, 2);
|
||||||
|
}
|
||||||
|
inline void PrefetchT2(const void* addr) {
|
||||||
|
// Note: this uses prefetcht2 on Intel.
|
||||||
|
__builtin_prefetch(addr, 0, 1);
|
||||||
|
}
|
||||||
|
inline void PrefetchNta(const void* addr) {
|
||||||
|
// Note: this uses prefetchtnta on Intel.
|
||||||
|
__builtin_prefetch(addr, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(ABSL_INTERNAL_HAVE_SSE)
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_HAVE_PREFETCH 1
|
||||||
|
|
||||||
|
inline void PrefetchT0(const void* addr) {
|
||||||
|
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T0);
|
||||||
|
}
|
||||||
|
inline void PrefetchT1(const void* addr) {
|
||||||
|
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T1);
|
||||||
|
}
|
||||||
|
inline void PrefetchT2(const void* addr) {
|
||||||
|
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T2);
|
||||||
|
}
|
||||||
|
inline void PrefetchNta(const void* addr) {
|
||||||
|
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_NTA);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
inline void PrefetchT0(const void*) {}
|
||||||
|
inline void PrefetchT1(const void*) {}
|
||||||
|
inline void PrefetchT2(const void*) {}
|
||||||
|
inline void PrefetchNta(const void*) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_PREFETCH_H_
|
||||||
33
include/absl/base/internal/pretty_function.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
|
||||||
|
|
||||||
|
// ABSL_PRETTY_FUNCTION
|
||||||
|
//
|
||||||
|
// In C++11, __func__ gives the undecorated name of the current function. That
|
||||||
|
// is, "main", not "int main()". Various compilers give extra macros to get the
|
||||||
|
// decorated function name, including return type and arguments, to
|
||||||
|
// differentiate between overload sets. ABSL_PRETTY_FUNCTION is a portable
|
||||||
|
// version of these macros which forwards to the correct macro on each compiler.
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define ABSL_PRETTY_FUNCTION __FUNCSIG__
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define ABSL_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||||
|
#else
|
||||||
|
#error "Unsupported compiler"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
|
||||||
196
include/absl/base/internal/raw_logging.h
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Thread-safe logging routines that do not allocate any memory or
|
||||||
|
// acquire any locks, and can therefore be used by low-level memory
|
||||||
|
// allocation, synchronization, and signal-handling code.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_RAW_LOGGING_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
#include "absl/base/internal/atomic_hook.h"
|
||||||
|
#include "absl/base/log_severity.h"
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/base/optimization.h"
|
||||||
|
#include "absl/base/port.h"
|
||||||
|
|
||||||
|
// This is similar to LOG(severity) << format..., but
|
||||||
|
// * it is to be used ONLY by low-level modules that can't use normal LOG()
|
||||||
|
// * it is designed to be a low-level logger that does not allocate any
|
||||||
|
// memory and does not need any locks, hence:
|
||||||
|
// * it logs straight and ONLY to STDERR w/o buffering
|
||||||
|
// * it uses an explicit printf-format and arguments list
|
||||||
|
// * it will silently chop off really long message strings
|
||||||
|
// Usage example:
|
||||||
|
// ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
|
||||||
|
// This will print an almost standard log line like this to stderr only:
|
||||||
|
// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
|
||||||
|
|
||||||
|
#define ABSL_RAW_LOG(severity, ...) \
|
||||||
|
do { \
|
||||||
|
constexpr const char* absl_raw_logging_internal_basename = \
|
||||||
|
::absl::raw_logging_internal::Basename(__FILE__, \
|
||||||
|
sizeof(__FILE__) - 1); \
|
||||||
|
::absl::raw_logging_internal::RawLog(ABSL_RAW_LOGGING_INTERNAL_##severity, \
|
||||||
|
absl_raw_logging_internal_basename, \
|
||||||
|
__LINE__, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
// Similar to CHECK(condition) << message, but for low-level modules:
|
||||||
|
// we use only ABSL_RAW_LOG that does not allocate memory.
|
||||||
|
// We do not want to provide args list here to encourage this usage:
|
||||||
|
// if (!cond) ABSL_RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
|
||||||
|
// so that the args are not computed when not needed.
|
||||||
|
#define ABSL_RAW_CHECK(condition, message) \
|
||||||
|
do { \
|
||||||
|
if (ABSL_PREDICT_FALSE(!(condition))) { \
|
||||||
|
ABSL_RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
// ABSL_INTERNAL_LOG and ABSL_INTERNAL_CHECK work like the RAW variants above,
|
||||||
|
// except that if the richer log library is linked into the binary, we dispatch
|
||||||
|
// to that instead. This is potentially useful for internal logging and
|
||||||
|
// assertions, where we are using RAW_LOG neither for its async-signal-safety
|
||||||
|
// nor for its non-allocating nature, but rather because raw logging has very
|
||||||
|
// few other dependencies.
|
||||||
|
//
|
||||||
|
// The API is a subset of the above: each macro only takes two arguments. Use
|
||||||
|
// StrCat if you need to build a richer message.
|
||||||
|
#define ABSL_INTERNAL_LOG(severity, message) \
|
||||||
|
do { \
|
||||||
|
constexpr const char* absl_raw_logging_internal_filename = __FILE__; \
|
||||||
|
::absl::raw_logging_internal::internal_log_function( \
|
||||||
|
ABSL_RAW_LOGGING_INTERNAL_##severity, \
|
||||||
|
absl_raw_logging_internal_filename, __LINE__, message); \
|
||||||
|
if (ABSL_RAW_LOGGING_INTERNAL_##severity == ::absl::LogSeverity::kFatal) \
|
||||||
|
ABSL_INTERNAL_UNREACHABLE; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_CHECK(condition, message) \
|
||||||
|
do { \
|
||||||
|
if (ABSL_PREDICT_FALSE(!(condition))) { \
|
||||||
|
std::string death_message = "Check " #condition " failed: "; \
|
||||||
|
death_message += std::string(message); \
|
||||||
|
ABSL_INTERNAL_LOG(FATAL, death_message); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo
|
||||||
|
#define ABSL_RAW_LOGGING_INTERNAL_WARNING ::absl::LogSeverity::kWarning
|
||||||
|
#define ABSL_RAW_LOGGING_INTERNAL_ERROR ::absl::LogSeverity::kError
|
||||||
|
#define ABSL_RAW_LOGGING_INTERNAL_FATAL ::absl::LogSeverity::kFatal
|
||||||
|
#define ABSL_RAW_LOGGING_INTERNAL_LEVEL(severity) \
|
||||||
|
::absl::NormalizeLogSeverity(severity)
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace raw_logging_internal {
|
||||||
|
|
||||||
|
// Helper function to implement ABSL_RAW_LOG
|
||||||
|
// Logs format... at "severity" level, reporting it
|
||||||
|
// as called from file:line.
|
||||||
|
// This does not allocate memory or acquire locks.
|
||||||
|
void RawLog(absl::LogSeverity severity, const char* file, int line,
|
||||||
|
const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
|
||||||
|
|
||||||
|
// Writes the provided buffer directly to stderr, in a signal-safe, low-level
|
||||||
|
// manner.
|
||||||
|
void AsyncSignalSafeWriteToStderr(const char* s, size_t len);
|
||||||
|
|
||||||
|
// compile-time function to get the "base" filename, that is, the part of
|
||||||
|
// a filename after the last "/" or "\" path separator. The search starts at
|
||||||
|
// the end of the string; the second parameter is the length of the string.
|
||||||
|
constexpr const char* Basename(const char* fname, int offset) {
|
||||||
|
return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\'
|
||||||
|
? fname + offset
|
||||||
|
: Basename(fname, offset - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For testing only.
|
||||||
|
// Returns true if raw logging is fully supported. When it is not
|
||||||
|
// fully supported, no messages will be emitted, but a log at FATAL
|
||||||
|
// severity will cause an abort.
|
||||||
|
//
|
||||||
|
// TODO(gfalcon): Come up with a better name for this method.
|
||||||
|
bool RawLoggingFullySupported();
|
||||||
|
|
||||||
|
// Function type for a raw_logging customization hook for suppressing messages
|
||||||
|
// by severity, and for writing custom prefixes on non-suppressed messages.
|
||||||
|
//
|
||||||
|
// The installed hook is called for every raw log invocation. The message will
|
||||||
|
// be logged to stderr only if the hook returns true. FATAL errors will cause
|
||||||
|
// the process to abort, even if writing to stderr is suppressed. The hook is
|
||||||
|
// also provided with an output buffer, where it can write a custom log message
|
||||||
|
// prefix.
|
||||||
|
//
|
||||||
|
// The raw_logging system does not allocate memory or grab locks. User-provided
|
||||||
|
// hooks must avoid these operations, and must not throw exceptions.
|
||||||
|
//
|
||||||
|
// 'severity' is the severity level of the message being written.
|
||||||
|
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
|
||||||
|
// was located.
|
||||||
|
// 'buf' and 'buf_size' are pointers to the buffer and buffer size. If the
|
||||||
|
// hook writes a prefix, it must increment *buf and decrement *buf_size
|
||||||
|
// accordingly.
|
||||||
|
using LogFilterAndPrefixHook = bool (*)(absl::LogSeverity severity,
|
||||||
|
const char* file, int line, char** buf,
|
||||||
|
int* buf_size);
|
||||||
|
|
||||||
|
// Function type for a raw_logging customization hook called to abort a process
|
||||||
|
// when a FATAL message is logged. If the provided AbortHook() returns, the
|
||||||
|
// logging system will call abort().
|
||||||
|
//
|
||||||
|
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
|
||||||
|
// was located.
|
||||||
|
// The NUL-terminated logged message lives in the buffer between 'buf_start'
|
||||||
|
// and 'buf_end'. 'prefix_end' points to the first non-prefix character of the
|
||||||
|
// buffer (as written by the LogFilterAndPrefixHook.)
|
||||||
|
//
|
||||||
|
// The lifetime of the filename and message buffers will not end while the
|
||||||
|
// process remains alive.
|
||||||
|
using AbortHook = void (*)(const char* file, int line, const char* buf_start,
|
||||||
|
const char* prefix_end, const char* buf_end);
|
||||||
|
|
||||||
|
// Internal logging function for ABSL_INTERNAL_LOG to dispatch to.
|
||||||
|
//
|
||||||
|
// TODO(gfalcon): When string_view no longer depends on base, change this
|
||||||
|
// interface to take its message as a string_view instead.
|
||||||
|
using InternalLogFunction = void (*)(absl::LogSeverity severity,
|
||||||
|
const char* file, int line,
|
||||||
|
const std::string& message);
|
||||||
|
|
||||||
|
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook<
|
||||||
|
InternalLogFunction>
|
||||||
|
internal_log_function;
|
||||||
|
|
||||||
|
// Registers hooks of the above types. Only a single hook of each type may be
|
||||||
|
// registered. It is an error to call these functions multiple times with
|
||||||
|
// different input arguments.
|
||||||
|
//
|
||||||
|
// These functions are safe to call at any point during initialization; they do
|
||||||
|
// not block or malloc, and are async-signal safe.
|
||||||
|
void RegisterLogFilterAndPrefixHook(LogFilterAndPrefixHook func);
|
||||||
|
void RegisterAbortHook(AbortHook func);
|
||||||
|
void RegisterInternalLogFunction(InternalLogFunction func);
|
||||||
|
|
||||||
|
} // namespace raw_logging_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_
|
||||||
58
include/absl/base/internal/scheduling_mode.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Core interfaces and definitions used by by low-level interfaces such as
|
||||||
|
// SpinLock.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
// Used to describe how a thread may be scheduled. Typically associated with
|
||||||
|
// the declaration of a resource supporting synchronized access.
|
||||||
|
//
|
||||||
|
// SCHEDULE_COOPERATIVE_AND_KERNEL:
|
||||||
|
// Specifies that when waiting, a cooperative thread (e.g. a Fiber) may
|
||||||
|
// reschedule (using base::scheduling semantics); allowing other cooperative
|
||||||
|
// threads to proceed.
|
||||||
|
//
|
||||||
|
// SCHEDULE_KERNEL_ONLY: (Also described as "non-cooperative")
|
||||||
|
// Specifies that no cooperative scheduling semantics may be used, even if the
|
||||||
|
// current thread is itself cooperatively scheduled. This means that
|
||||||
|
// cooperative threads will NOT allow other cooperative threads to execute in
|
||||||
|
// their place while waiting for a resource of this type. Host operating system
|
||||||
|
// semantics (e.g. a futex) may still be used.
|
||||||
|
//
|
||||||
|
// When optional, clients should strongly prefer SCHEDULE_COOPERATIVE_AND_KERNEL
|
||||||
|
// by default. SCHEDULE_KERNEL_ONLY should only be used for resources on which
|
||||||
|
// base::scheduling (e.g. the implementation of a Scheduler) may depend.
|
||||||
|
//
|
||||||
|
// NOTE: Cooperative resources may not be nested below non-cooperative ones.
|
||||||
|
// This means that it is invalid to to acquire a SCHEDULE_COOPERATIVE_AND_KERNEL
|
||||||
|
// resource if a SCHEDULE_KERNEL_ONLY resource is already held.
|
||||||
|
enum SchedulingMode {
|
||||||
|
SCHEDULE_KERNEL_ONLY = 0, // Allow scheduling only the host OS.
|
||||||
|
SCHEDULE_COOPERATIVE_AND_KERNEL, // Also allow cooperative scheduling.
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
|
||||||
45
include/absl/base/internal/scoped_set_env.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2019 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
class ScopedSetEnv {
|
||||||
|
public:
|
||||||
|
ScopedSetEnv(const char* var_name, const char* new_value);
|
||||||
|
~ScopedSetEnv();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string var_name_;
|
||||||
|
std::string old_value_;
|
||||||
|
|
||||||
|
// True if the environment variable was initially not set.
|
||||||
|
bool was_unset_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
|
||||||
256
include/absl/base/internal/spinlock.h
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Most users requiring mutual exclusion should use Mutex.
|
||||||
|
// SpinLock is provided for use in two situations:
|
||||||
|
// - for use by Abseil internal code that Mutex itself depends on
|
||||||
|
// - for async signal safety (see below)
|
||||||
|
|
||||||
|
// SpinLock is async signal safe. If a spinlock is used within a signal
|
||||||
|
// handler, all code that acquires the lock must ensure that the signal cannot
|
||||||
|
// arrive while they are holding the lock. Typically, this is done by blocking
|
||||||
|
// the signal.
|
||||||
|
//
|
||||||
|
// Threads waiting on a SpinLock may be woken in an arbitrary order.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_SPINLOCK_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/const_init.h"
|
||||||
|
#include "absl/base/dynamic_annotations.h"
|
||||||
|
#include "absl/base/internal/low_level_scheduling.h"
|
||||||
|
#include "absl/base/internal/raw_logging.h"
|
||||||
|
#include "absl/base/internal/scheduling_mode.h"
|
||||||
|
#include "absl/base/internal/tsan_mutex_interface.h"
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/base/port.h"
|
||||||
|
#include "absl/base/thread_annotations.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
class ABSL_LOCKABLE SpinLock {
|
||||||
|
public:
|
||||||
|
SpinLock() : lockword_(kSpinLockCooperative) {
|
||||||
|
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructors that allow non-cooperative spinlocks to be created for use
|
||||||
|
// inside thread schedulers. Normal clients should not use these.
|
||||||
|
explicit SpinLock(base_internal::SchedulingMode mode);
|
||||||
|
|
||||||
|
// Constructor for global SpinLock instances. See absl/base/const_init.h.
|
||||||
|
constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
|
||||||
|
: lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
|
||||||
|
|
||||||
|
// For global SpinLock instances prefer trivial destructor when possible.
|
||||||
|
// Default but non-trivial destructor in some build configurations causes an
|
||||||
|
// extra static initializer.
|
||||||
|
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
|
||||||
|
~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
|
||||||
|
#else
|
||||||
|
~SpinLock() = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Acquire this SpinLock.
|
||||||
|
inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
|
||||||
|
ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
|
||||||
|
if (!TryLockImpl()) {
|
||||||
|
SlowLock();
|
||||||
|
}
|
||||||
|
ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to acquire this SpinLock without blocking and return true if the
|
||||||
|
// acquisition was successful. If the lock was not acquired, false is
|
||||||
|
// returned. If this SpinLock is free at the time of the call, TryLock
|
||||||
|
// will return true with high probability.
|
||||||
|
inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
|
||||||
|
ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
|
||||||
|
bool res = TryLockImpl();
|
||||||
|
ABSL_TSAN_MUTEX_POST_LOCK(
|
||||||
|
this, __tsan_mutex_try_lock | (res ? 0 : __tsan_mutex_try_lock_failed),
|
||||||
|
0);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release this SpinLock, which must be held by the calling thread.
|
||||||
|
inline void Unlock() ABSL_UNLOCK_FUNCTION() {
|
||||||
|
ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
|
||||||
|
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
|
||||||
|
lock_value = lockword_.exchange(lock_value & kSpinLockCooperative,
|
||||||
|
std::memory_order_release);
|
||||||
|
|
||||||
|
if ((lock_value & kSpinLockDisabledScheduling) != 0) {
|
||||||
|
base_internal::SchedulingGuard::EnableRescheduling(true);
|
||||||
|
}
|
||||||
|
if ((lock_value & kWaitTimeMask) != 0) {
|
||||||
|
// Collect contentionz profile info, and speed the wakeup of any waiter.
|
||||||
|
// The wait_cycles value indicates how long this thread spent waiting
|
||||||
|
// for the lock.
|
||||||
|
SlowUnlock(lock_value);
|
||||||
|
}
|
||||||
|
ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if the lock is held. When the lock is held by the invoking
|
||||||
|
// thread, true will always be returned. Intended to be used as
|
||||||
|
// CHECK(lock.IsHeld()).
|
||||||
|
inline bool IsHeld() const {
|
||||||
|
return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return immediately if this thread holds the SpinLock exclusively.
|
||||||
|
// Otherwise, report an error by crashing with a diagnostic.
|
||||||
|
inline void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() {
|
||||||
|
if (!IsHeld()) {
|
||||||
|
ABSL_RAW_LOG(FATAL, "thread should hold the lock on SpinLock");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// These should not be exported except for testing.
|
||||||
|
|
||||||
|
// Store number of cycles between wait_start_time and wait_end_time in a
|
||||||
|
// lock value.
|
||||||
|
static uint32_t EncodeWaitCycles(int64_t wait_start_time,
|
||||||
|
int64_t wait_end_time);
|
||||||
|
|
||||||
|
// Extract number of wait cycles in a lock value.
|
||||||
|
static uint64_t DecodeWaitCycles(uint32_t lock_value);
|
||||||
|
|
||||||
|
// Provide access to protected method above. Use for testing only.
|
||||||
|
friend struct SpinLockTest;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// lockword_ is used to store the following:
|
||||||
|
//
|
||||||
|
// bit[0] encodes whether a lock is being held.
|
||||||
|
// bit[1] encodes whether a lock uses cooperative scheduling.
|
||||||
|
// bit[2] encodes whether the current lock holder disabled scheduling when
|
||||||
|
// acquiring the lock. Only set when kSpinLockHeld is also set.
|
||||||
|
// bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
|
||||||
|
// This is set by the lock holder to indicate how long it waited on
|
||||||
|
// the lock before eventually acquiring it. The number of cycles is
|
||||||
|
// encoded as a 29-bit unsigned int, or in the case that the current
|
||||||
|
// holder did not wait but another waiter is queued, the LSB
|
||||||
|
// (kSpinLockSleeper) is set. The implementation does not explicitly
|
||||||
|
// track the number of queued waiters beyond this. It must always be
|
||||||
|
// assumed that waiters may exist if the current holder was required to
|
||||||
|
// queue.
|
||||||
|
//
|
||||||
|
// Invariant: if the lock is not held, the value is either 0 or
|
||||||
|
// kSpinLockCooperative.
|
||||||
|
static constexpr uint32_t kSpinLockHeld = 1;
|
||||||
|
static constexpr uint32_t kSpinLockCooperative = 2;
|
||||||
|
static constexpr uint32_t kSpinLockDisabledScheduling = 4;
|
||||||
|
static constexpr uint32_t kSpinLockSleeper = 8;
|
||||||
|
// Includes kSpinLockSleeper.
|
||||||
|
static constexpr uint32_t kWaitTimeMask =
|
||||||
|
~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling);
|
||||||
|
|
||||||
|
// Returns true if the provided scheduling mode is cooperative.
|
||||||
|
static constexpr bool IsCooperative(
|
||||||
|
base_internal::SchedulingMode scheduling_mode) {
|
||||||
|
return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
|
||||||
|
void SlowLock() ABSL_ATTRIBUTE_COLD;
|
||||||
|
void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
|
||||||
|
uint32_t SpinLoop();
|
||||||
|
|
||||||
|
inline bool TryLockImpl() {
|
||||||
|
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
|
||||||
|
return (TryLockInternal(lock_value, 0) & kSpinLockHeld) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::atomic<uint32_t> lockword_;
|
||||||
|
|
||||||
|
SpinLock(const SpinLock&) = delete;
|
||||||
|
SpinLock& operator=(const SpinLock&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Corresponding locker object that arranges to acquire a spinlock for
|
||||||
|
// the duration of a C++ scope.
|
||||||
|
class ABSL_SCOPED_LOCKABLE SpinLockHolder {
|
||||||
|
public:
|
||||||
|
inline explicit SpinLockHolder(SpinLock* l) ABSL_EXCLUSIVE_LOCK_FUNCTION(l)
|
||||||
|
: lock_(l) {
|
||||||
|
l->Lock();
|
||||||
|
}
|
||||||
|
inline ~SpinLockHolder() ABSL_UNLOCK_FUNCTION() { lock_->Unlock(); }
|
||||||
|
|
||||||
|
SpinLockHolder(const SpinLockHolder&) = delete;
|
||||||
|
SpinLockHolder& operator=(const SpinLockHolder&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SpinLock* lock_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Register a hook for profiling support.
|
||||||
|
//
|
||||||
|
// The function pointer registered here will be called whenever a spinlock is
|
||||||
|
// contended. The callback is given an opaque handle to the contended spinlock
|
||||||
|
// and the number of wait cycles. This is thread-safe, but only a single
|
||||||
|
// profiler can be registered. It is an error to call this function multiple
|
||||||
|
// times with different arguments.
|
||||||
|
void RegisterSpinLockProfiler(void (*fn)(const void* lock,
|
||||||
|
int64_t wait_cycles));
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Public interface ends here.
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// If (result & kSpinLockHeld) == 0, then *this was successfully locked.
|
||||||
|
// Otherwise, returns last observed value for lockword_.
|
||||||
|
inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
|
||||||
|
uint32_t wait_cycles) {
|
||||||
|
if ((lock_value & kSpinLockHeld) != 0) {
|
||||||
|
return lock_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sched_disabled_bit = 0;
|
||||||
|
if ((lock_value & kSpinLockCooperative) == 0) {
|
||||||
|
// For non-cooperative locks we must make sure we mark ourselves as
|
||||||
|
// non-reschedulable before we attempt to CompareAndSwap.
|
||||||
|
if (base_internal::SchedulingGuard::DisableRescheduling()) {
|
||||||
|
sched_disabled_bit = kSpinLockDisabledScheduling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lockword_.compare_exchange_strong(
|
||||||
|
lock_value,
|
||||||
|
kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit,
|
||||||
|
std::memory_order_acquire, std::memory_order_relaxed)) {
|
||||||
|
base_internal::SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lock_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_SPINLOCK_H_
|
||||||
35
include/absl/base/internal/spinlock_akaros.inc
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// This file is an Akaros-specific part of spinlock_wait.cc
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "absl/base/internal/scheduling_mode.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
|
||||||
|
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */,
|
||||||
|
int /* loop */, absl::base_internal::SchedulingMode /* mode */) {
|
||||||
|
// In Akaros, one must take care not to call anything that could cause a
|
||||||
|
// malloc(), a blocking system call, or a uthread_yield() while holding a
|
||||||
|
// spinlock. Our callers assume will not call into libraries or other
|
||||||
|
// arbitrary code.
|
||||||
|
}
|
||||||
|
|
||||||
|
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
|
||||||
|
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
71
include/absl/base/internal/spinlock_linux.inc
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2018 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// This file is a Linux-specific part of spinlock_wait.cc
|
||||||
|
|
||||||
|
#include <linux/futex.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <climits>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/internal/errno_saver.h"
|
||||||
|
|
||||||
|
// The SpinLock lockword is `std::atomic<uint32_t>`. Here we assert that
|
||||||
|
// `std::atomic<uint32_t>` is bitwise equivalent of the `int` expected
|
||||||
|
// by SYS_futex. We also assume that reads/writes done to the lockword
|
||||||
|
// by SYS_futex have rational semantics with regard to the
|
||||||
|
// std::atomic<> API. C++ provides no guarantees of these assumptions,
|
||||||
|
// but they are believed to hold in practice.
|
||||||
|
static_assert(sizeof(std::atomic<uint32_t>) == sizeof(int),
|
||||||
|
"SpinLock lockword has the wrong size for a futex");
|
||||||
|
|
||||||
|
// Some Android headers are missing these definitions even though they
|
||||||
|
// support these futex operations.
|
||||||
|
#ifdef __BIONIC__
|
||||||
|
#ifndef SYS_futex
|
||||||
|
#define SYS_futex __NR_futex
|
||||||
|
#endif
|
||||||
|
#ifndef FUTEX_PRIVATE_FLAG
|
||||||
|
#define FUTEX_PRIVATE_FLAG 128
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
|
||||||
|
#define SYS_futex_time64 __NR_futex_time64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SYS_futex_time64) && !defined(SYS_futex)
|
||||||
|
#define SYS_futex SYS_futex_time64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
|
||||||
|
std::atomic<uint32_t> *w, uint32_t value, int,
|
||||||
|
absl::base_internal::SchedulingMode) {
|
||||||
|
absl::base_internal::ErrnoSaver errno_saver;
|
||||||
|
syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
|
||||||
|
std::atomic<uint32_t> *w, bool all) {
|
||||||
|
syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
46
include/absl/base/internal/spinlock_posix.inc
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// This file is a Posix-specific part of spinlock_wait.cc
|
||||||
|
|
||||||
|
#include <sched.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#include "absl/base/internal/errno_saver.h"
|
||||||
|
#include "absl/base/internal/scheduling_mode.h"
|
||||||
|
#include "absl/base/port.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
|
||||||
|
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
|
||||||
|
absl::base_internal::SchedulingMode /* mode */) {
|
||||||
|
absl::base_internal::ErrnoSaver errno_saver;
|
||||||
|
if (loop == 0) {
|
||||||
|
} else if (loop == 1) {
|
||||||
|
sched_yield();
|
||||||
|
} else {
|
||||||
|
struct timespec tm;
|
||||||
|
tm.tv_sec = 0;
|
||||||
|
tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
|
||||||
|
nanosleep(&tm, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
|
||||||
|
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
95
include/absl/base/internal/spinlock_wait.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
|
||||||
|
|
||||||
|
// Operations to make atomic transitions on a word, and to allow
|
||||||
|
// waiting for those transitions to become possible.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "absl/base/internal/scheduling_mode.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
// SpinLockWait() waits until it can perform one of several transitions from
|
||||||
|
// "from" to "to". It returns when it performs a transition where done==true.
|
||||||
|
struct SpinLockWaitTransition {
|
||||||
|
uint32_t from;
|
||||||
|
uint32_t to;
|
||||||
|
bool done;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wait until *w can transition from trans[i].from to trans[i].to for some i
|
||||||
|
// satisfying 0<=i<n && trans[i].done, atomically make the transition,
|
||||||
|
// then return the old value of *w. Make any other atomic transitions
|
||||||
|
// where !trans[i].done, but continue waiting.
|
||||||
|
//
|
||||||
|
// Wakeups for threads blocked on SpinLockWait do not respect priorities.
|
||||||
|
uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
|
||||||
|
const SpinLockWaitTransition trans[],
|
||||||
|
SchedulingMode scheduling_mode);
|
||||||
|
|
||||||
|
// If possible, wake some thread that has called SpinLockDelay(w, ...). If `all`
|
||||||
|
// is true, wake all such threads. On some systems, this may be a no-op; on
|
||||||
|
// those systems, threads calling SpinLockDelay() will always wake eventually
|
||||||
|
// even if SpinLockWake() is never called.
|
||||||
|
void SpinLockWake(std::atomic<uint32_t> *w, bool all);
|
||||||
|
|
||||||
|
// Wait for an appropriate spin delay on iteration "loop" of a
|
||||||
|
// spin loop on location *w, whose previously observed value was "value".
|
||||||
|
// SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick,
|
||||||
|
// or may wait for a call to SpinLockWake(w).
|
||||||
|
void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop,
|
||||||
|
base_internal::SchedulingMode scheduling_mode);
|
||||||
|
|
||||||
|
// Helper used by AbslInternalSpinLockDelay.
|
||||||
|
// Returns a suggested delay in nanoseconds for iteration number "loop".
|
||||||
|
int SpinLockSuggestedDelayNS(int loop);
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
// In some build configurations we pass --detect-odr-violations to the
|
||||||
|
// gold linker. This causes it to flag weak symbol overrides as ODR
|
||||||
|
// violations. Because ODR only applies to C++ and not C,
|
||||||
|
// --detect-odr-violations ignores symbols not mangled with C++ names.
|
||||||
|
// By changing our extension points to be extern "C", we dodge this
|
||||||
|
// check.
|
||||||
|
extern "C" {
|
||||||
|
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(std::atomic<uint32_t> *w,
|
||||||
|
bool all);
|
||||||
|
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
|
||||||
|
std::atomic<uint32_t> *w, uint32_t value, int loop,
|
||||||
|
absl::base_internal::SchedulingMode scheduling_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w,
|
||||||
|
bool all) {
|
||||||
|
ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(w, all);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void absl::base_internal::SpinLockDelay(
|
||||||
|
std::atomic<uint32_t> *w, uint32_t value, int loop,
|
||||||
|
absl::base_internal::SchedulingMode scheduling_mode) {
|
||||||
|
ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)
|
||||||
|
(w, value, loop, scheduling_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
|
||||||
37
include/absl/base/internal/spinlock_win32.inc
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// This file is a Win32-specific part of spinlock_wait.cc
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <atomic>
|
||||||
|
#include "absl/base/internal/scheduling_mode.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
|
||||||
|
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
|
||||||
|
absl::base_internal::SchedulingMode /* mode */) {
|
||||||
|
if (loop == 0) {
|
||||||
|
} else if (loop == 1) {
|
||||||
|
Sleep(0);
|
||||||
|
} else {
|
||||||
|
Sleep(absl::base_internal::SpinLockSuggestedDelayNS(loop) / 1000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
|
||||||
|
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
39
include/absl/base/internal/strerror.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2020 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_STRERROR_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_STRERROR_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
// A portable and thread-safe alternative to C89's `strerror`.
|
||||||
|
//
|
||||||
|
// The C89 specification of `strerror` is not suitable for use in a
|
||||||
|
// multi-threaded application as the returned string may be changed by calls to
|
||||||
|
// `strerror` from another thread. The many non-stdlib alternatives differ
|
||||||
|
// enough in their names, availability, and semantics to justify this wrapper
|
||||||
|
// around them. `errno` will not be modified by a call to `absl::StrError`.
|
||||||
|
std::string StrError(int errnum);
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_STRERROR_H_
|
||||||
74
include/absl/base/internal/sysinfo.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// This file includes routines to find out characteristics
|
||||||
|
// of the machine a program is running on. It is undoubtedly
|
||||||
|
// system-dependent.
|
||||||
|
|
||||||
|
// Functions listed here that accept a pid_t as an argument act on the
|
||||||
|
// current process if the pid_t argument is 0
|
||||||
|
// All functions here are thread-hostile due to file caching unless
|
||||||
|
// commented otherwise.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_SYSINFO_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_SYSINFO_H_
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
#include "absl/base/port.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
// Nominal core processor cycles per second of each processor. This is _not_
|
||||||
|
// necessarily the frequency of the CycleClock counter (see cycleclock.h)
|
||||||
|
// Thread-safe.
|
||||||
|
double NominalCPUFrequency();
|
||||||
|
|
||||||
|
// Number of logical processors (hyperthreads) in system. Thread-safe.
|
||||||
|
int NumCPUs();
|
||||||
|
|
||||||
|
// Return the thread id of the current thread, as told by the system.
|
||||||
|
// No two currently-live threads implemented by the OS shall have the same ID.
|
||||||
|
// Thread ids of exited threads may be reused. Multiple user-level threads
|
||||||
|
// may have the same thread ID if multiplexed on the same OS thread.
|
||||||
|
//
|
||||||
|
// On Linux, you may send a signal to the resulting ID with kill(). However,
|
||||||
|
// it is recommended for portability that you use pthread_kill() instead.
|
||||||
|
#ifdef _WIN32
|
||||||
|
// On Windows, process id and thread id are of the same type according to the
|
||||||
|
// return types of GetProcessId() and GetThreadId() are both DWORD, an unsigned
|
||||||
|
// 32-bit type.
|
||||||
|
using pid_t = uint32_t;
|
||||||
|
#endif
|
||||||
|
pid_t GetTID();
|
||||||
|
|
||||||
|
// Like GetTID(), but caches the result in thread-local storage in order
|
||||||
|
// to avoid unnecessary system calls. Note that there are some cases where
|
||||||
|
// one must call through to GetTID directly, which is why this exists as a
|
||||||
|
// separate function. For example, GetCachedTID() is not safe to call in
|
||||||
|
// an asynchronous signal-handling context nor right after a call to fork().
|
||||||
|
pid_t GetCachedTID();
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_SYSINFO_H_
|
||||||
271
include/absl/base/internal/thread_annotations.h
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
// Copyright 2019 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: thread_annotations.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// WARNING: This is a backwards compatible header and it will be removed after
|
||||||
|
// the migration to prefixed thread annotations is finished; please include
|
||||||
|
// "absl/base/thread_annotations.h".
|
||||||
|
//
|
||||||
|
// This header file contains macro definitions for thread safety annotations
|
||||||
|
// that allow developers to document the locking policies of multi-threaded
|
||||||
|
// code. The annotations can also help program analysis tools to identify
|
||||||
|
// potential thread safety issues.
|
||||||
|
//
|
||||||
|
// These annotations are implemented using compiler attributes. Using the macros
|
||||||
|
// defined here instead of raw attributes allow for portability and future
|
||||||
|
// compatibility.
|
||||||
|
//
|
||||||
|
// When referring to mutexes in the arguments of the attributes, you should
|
||||||
|
// use variable names or more complex expressions (e.g. my_object->mutex_)
|
||||||
|
// that evaluate to a concrete mutex object whenever possible. If the mutex
|
||||||
|
// you want to refer to is not in scope, you may use a member pointer
|
||||||
|
// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||||
|
#else
|
||||||
|
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// GUARDED_BY()
|
||||||
|
//
|
||||||
|
// Documents if a shared field or global variable needs to be protected by a
|
||||||
|
// mutex. GUARDED_BY() allows the user to specify a particular mutex that
|
||||||
|
// should be held when accessing the annotated variable.
|
||||||
|
//
|
||||||
|
// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to
|
||||||
|
// local variables, a local variable and its associated mutex can often be
|
||||||
|
// combined into a small class or struct, thereby allowing the annotation.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// class Foo {
|
||||||
|
// Mutex mu_;
|
||||||
|
// int p1_ GUARDED_BY(mu_);
|
||||||
|
// ...
|
||||||
|
// };
|
||||||
|
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
|
||||||
|
|
||||||
|
// PT_GUARDED_BY()
|
||||||
|
//
|
||||||
|
// Documents if the memory location pointed to by a pointer should be guarded
|
||||||
|
// by a mutex when dereferencing the pointer.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// class Foo {
|
||||||
|
// Mutex mu_;
|
||||||
|
// int *p1_ PT_GUARDED_BY(mu_);
|
||||||
|
// ...
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// Note that a pointer variable to a shared memory location could itself be a
|
||||||
|
// shared variable.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // `q_`, guarded by `mu1_`, points to a shared memory location that is
|
||||||
|
// // guarded by `mu2_`:
|
||||||
|
// int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
|
||||||
|
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
|
||||||
|
|
||||||
|
// ACQUIRED_AFTER() / ACQUIRED_BEFORE()
|
||||||
|
//
|
||||||
|
// Documents the acquisition order between locks that can be held
|
||||||
|
// simultaneously by a thread. For any two locks that need to be annotated
|
||||||
|
// to establish an acquisition order, only one of them needs the annotation.
|
||||||
|
// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
|
||||||
|
// and ACQUIRED_BEFORE.)
|
||||||
|
//
|
||||||
|
// As with GUARDED_BY, this is only applicable to mutexes that are shared
|
||||||
|
// fields or global variables.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// Mutex m1_;
|
||||||
|
// Mutex m2_ ACQUIRED_AFTER(m1_);
|
||||||
|
#define ACQUIRED_AFTER(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
|
||||||
|
|
||||||
|
#define ACQUIRED_BEFORE(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
|
||||||
|
|
||||||
|
// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED()
|
||||||
|
//
|
||||||
|
// Documents a function that expects a mutex to be held prior to entry.
|
||||||
|
// The mutex is expected to be held both on entry to, and exit from, the
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
// An exclusive lock allows read-write access to the guarded data member(s), and
|
||||||
|
// only one thread can acquire a lock exclusively at any one time. A shared lock
|
||||||
|
// allows read-only access, and any number of threads can acquire a shared lock
|
||||||
|
// concurrently.
|
||||||
|
//
|
||||||
|
// Generally, non-const methods should be annotated with
|
||||||
|
// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
|
||||||
|
// SHARED_LOCKS_REQUIRED.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// Mutex mu1, mu2;
|
||||||
|
// int a GUARDED_BY(mu1);
|
||||||
|
// int b GUARDED_BY(mu2);
|
||||||
|
//
|
||||||
|
// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
|
||||||
|
// void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
|
||||||
|
#define EXCLUSIVE_LOCKS_REQUIRED(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
|
||||||
|
|
||||||
|
#define SHARED_LOCKS_REQUIRED(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
|
||||||
|
|
||||||
|
// LOCKS_EXCLUDED()
|
||||||
|
//
|
||||||
|
// Documents the locks acquired in the body of the function. These locks
|
||||||
|
// cannot be held when calling this function (as Abseil's `Mutex` locks are
|
||||||
|
// non-reentrant).
|
||||||
|
#define LOCKS_EXCLUDED(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
|
||||||
|
|
||||||
|
// LOCK_RETURNED()
|
||||||
|
//
|
||||||
|
// Documents a function that returns a mutex without acquiring it. For example,
|
||||||
|
// a public getter method that returns a pointer to a private mutex should
|
||||||
|
// be annotated with LOCK_RETURNED.
|
||||||
|
#define LOCK_RETURNED(x) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
|
||||||
|
|
||||||
|
// LOCKABLE
|
||||||
|
//
|
||||||
|
// Documents if a class/type is a lockable type (such as the `Mutex` class).
|
||||||
|
#define LOCKABLE \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(lockable)
|
||||||
|
|
||||||
|
// SCOPED_LOCKABLE
|
||||||
|
//
|
||||||
|
// Documents if a class does RAII locking (such as the `MutexLock` class).
|
||||||
|
// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
|
||||||
|
// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
|
||||||
|
// arguments; the analysis will assume that the destructor unlocks whatever the
|
||||||
|
// constructor locked.
|
||||||
|
#define SCOPED_LOCKABLE \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
|
||||||
|
|
||||||
|
// EXCLUSIVE_LOCK_FUNCTION()
|
||||||
|
//
|
||||||
|
// Documents functions that acquire a lock in the body of a function, and do
|
||||||
|
// not release it.
|
||||||
|
#define EXCLUSIVE_LOCK_FUNCTION(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
|
||||||
|
|
||||||
|
// SHARED_LOCK_FUNCTION()
|
||||||
|
//
|
||||||
|
// Documents functions that acquire a shared (reader) lock in the body of a
|
||||||
|
// function, and do not release it.
|
||||||
|
#define SHARED_LOCK_FUNCTION(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
|
||||||
|
|
||||||
|
// UNLOCK_FUNCTION()
|
||||||
|
//
|
||||||
|
// Documents functions that expect a lock to be held on entry to the function,
|
||||||
|
// and release it in the body of the function.
|
||||||
|
#define UNLOCK_FUNCTION(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
|
||||||
|
|
||||||
|
// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION()
|
||||||
|
//
|
||||||
|
// Documents functions that try to acquire a lock, and return success or failure
|
||||||
|
// (or a non-boolean value that can be interpreted as a boolean).
|
||||||
|
// The first argument should be `true` for functions that return `true` on
|
||||||
|
// success, or `false` for functions that return `false` on success. The second
|
||||||
|
// argument specifies the mutex that is locked on success. If unspecified, this
|
||||||
|
// mutex is assumed to be `this`.
|
||||||
|
#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
|
||||||
|
|
||||||
|
#define SHARED_TRYLOCK_FUNCTION(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
|
||||||
|
|
||||||
|
// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK()
|
||||||
|
//
|
||||||
|
// Documents functions that dynamically check to see if a lock is held, and fail
|
||||||
|
// if it is not held.
|
||||||
|
#define ASSERT_EXCLUSIVE_LOCK(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
|
||||||
|
|
||||||
|
#define ASSERT_SHARED_LOCK(...) \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
|
||||||
|
|
||||||
|
// NO_THREAD_SAFETY_ANALYSIS
|
||||||
|
//
|
||||||
|
// Turns off thread safety checking within the body of a particular function.
|
||||||
|
// This annotation is used to mark functions that are known to be correct, but
|
||||||
|
// the locking behavior is more complicated than the analyzer can handle.
|
||||||
|
#define NO_THREAD_SAFETY_ANALYSIS \
|
||||||
|
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Tool-Supplied Annotations
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// TS_UNCHECKED should be placed around lock expressions that are not valid
|
||||||
|
// C++ syntax, but which are present for documentation purposes. These
|
||||||
|
// annotations will be ignored by the analysis.
|
||||||
|
#define TS_UNCHECKED(x) ""
|
||||||
|
|
||||||
|
// TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
|
||||||
|
// It is used by automated tools to mark and disable invalid expressions.
|
||||||
|
// The annotation should either be fixed, or changed to TS_UNCHECKED.
|
||||||
|
#define TS_FIXME(x) ""
|
||||||
|
|
||||||
|
// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
|
||||||
|
// a particular function. However, this attribute is used to mark functions
|
||||||
|
// that are incorrect and need to be fixed. It is used by automated tools to
|
||||||
|
// avoid breaking the build when the analysis is updated.
|
||||||
|
// Code owners are expected to eventually fix the routine.
|
||||||
|
#define NO_THREAD_SAFETY_ANALYSIS_FIXME NO_THREAD_SAFETY_ANALYSIS
|
||||||
|
|
||||||
|
// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY
|
||||||
|
// annotation that needs to be fixed, because it is producing thread safety
|
||||||
|
// warning. It disables the GUARDED_BY.
|
||||||
|
#define GUARDED_BY_FIXME(x)
|
||||||
|
|
||||||
|
// Disables warnings for a single read operation. This can be used to avoid
|
||||||
|
// warnings when it is known that the read is not actually involved in a race,
|
||||||
|
// but the compiler cannot confirm that.
|
||||||
|
#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x)
|
||||||
|
|
||||||
|
|
||||||
|
namespace thread_safety_analysis {
|
||||||
|
|
||||||
|
// Takes a reference to a guarded data member, and returns an unguarded
|
||||||
|
// reference.
|
||||||
|
template <typename T>
|
||||||
|
inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace thread_safety_analysis
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_
|
||||||
265
include/absl/base/internal/thread_identity.h
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Each active thread has an ThreadIdentity that may represent the thread in
|
||||||
|
// various level interfaces. ThreadIdentity objects are never deallocated.
|
||||||
|
// When a thread terminates, its ThreadIdentity object may be reused for a
|
||||||
|
// thread created later.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <pthread.h>
|
||||||
|
// Defines __GOOGLE_GRTE_VERSION__ (via glibc-specific features.h) when
|
||||||
|
// supported.
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
#include "absl/base/internal/per_thread_tls.h"
|
||||||
|
#include "absl/base/optimization.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct SynchLocksHeld;
|
||||||
|
struct SynchWaitParams;
|
||||||
|
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
class SpinLock;
|
||||||
|
struct ThreadIdentity;
|
||||||
|
|
||||||
|
// Used by the implementation of absl::Mutex and absl::CondVar.
|
||||||
|
struct PerThreadSynch {
|
||||||
|
// The internal representation of absl::Mutex and absl::CondVar rely
|
||||||
|
// on the alignment of PerThreadSynch. Both store the address of the
|
||||||
|
// PerThreadSynch in the high-order bits of their internal state,
|
||||||
|
// which means the low kLowZeroBits of the address of PerThreadSynch
|
||||||
|
// must be zero.
|
||||||
|
static constexpr int kLowZeroBits = 8;
|
||||||
|
static constexpr int kAlignment = 1 << kLowZeroBits;
|
||||||
|
|
||||||
|
// Returns the associated ThreadIdentity.
|
||||||
|
// This can be implemented as a cast because we guarantee
|
||||||
|
// PerThreadSynch is the first element of ThreadIdentity.
|
||||||
|
ThreadIdentity* thread_identity() {
|
||||||
|
return reinterpret_cast<ThreadIdentity*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
PerThreadSynch *next; // Circular waiter queue; initialized to 0.
|
||||||
|
PerThreadSynch *skip; // If non-zero, all entries in Mutex queue
|
||||||
|
// up to and including "skip" have same
|
||||||
|
// condition as this, and will be woken later
|
||||||
|
bool may_skip; // if false while on mutex queue, a mutex unlocker
|
||||||
|
// is using this PerThreadSynch as a terminator. Its
|
||||||
|
// skip field must not be filled in because the loop
|
||||||
|
// might then skip over the terminator.
|
||||||
|
bool wake; // This thread is to be woken from a Mutex.
|
||||||
|
// If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
|
||||||
|
// waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
|
||||||
|
//
|
||||||
|
// The value of "x->cond_waiter" is meaningless if "x" is not on a
|
||||||
|
// Mutex waiter list.
|
||||||
|
bool cond_waiter;
|
||||||
|
bool maybe_unlocking; // Valid at head of Mutex waiter queue;
|
||||||
|
// true if UnlockSlow could be searching
|
||||||
|
// for a waiter to wake. Used for an optimization
|
||||||
|
// in Enqueue(). true is always a valid value.
|
||||||
|
// Can be reset to false when the unlocker or any
|
||||||
|
// writer releases the lock, or a reader fully
|
||||||
|
// releases the lock. It may not be set to false
|
||||||
|
// by a reader that decrements the count to
|
||||||
|
// non-zero. protected by mutex spinlock
|
||||||
|
bool suppress_fatal_errors; // If true, try to proceed even in the face
|
||||||
|
// of broken invariants. This is used within
|
||||||
|
// fatal signal handlers to improve the
|
||||||
|
// chances of debug logging information being
|
||||||
|
// output successfully.
|
||||||
|
int priority; // Priority of thread (updated every so often).
|
||||||
|
|
||||||
|
// State values:
|
||||||
|
// kAvailable: This PerThreadSynch is available.
|
||||||
|
// kQueued: This PerThreadSynch is unavailable, it's currently queued on a
|
||||||
|
// Mutex or CondVar waistlist.
|
||||||
|
//
|
||||||
|
// Transitions from kQueued to kAvailable require a release
|
||||||
|
// barrier. This is needed as a waiter may use "state" to
|
||||||
|
// independently observe that it's no longer queued.
|
||||||
|
//
|
||||||
|
// Transitions from kAvailable to kQueued require no barrier, they
|
||||||
|
// are externally ordered by the Mutex.
|
||||||
|
enum State {
|
||||||
|
kAvailable,
|
||||||
|
kQueued
|
||||||
|
};
|
||||||
|
std::atomic<State> state;
|
||||||
|
|
||||||
|
// The wait parameters of the current wait. waitp is null if the
|
||||||
|
// thread is not waiting. Transitions from null to non-null must
|
||||||
|
// occur before the enqueue commit point (state = kQueued in
|
||||||
|
// Enqueue() and CondVarEnqueue()). Transitions from non-null to
|
||||||
|
// null must occur after the wait is finished (state = kAvailable in
|
||||||
|
// Mutex::Block() and CondVar::WaitCommon()). This field may be
|
||||||
|
// changed only by the thread that describes this PerThreadSynch. A
|
||||||
|
// special case is Fer(), which calls Enqueue() on another thread,
|
||||||
|
// but with an identical SynchWaitParams pointer, thus leaving the
|
||||||
|
// pointer unchanged.
|
||||||
|
SynchWaitParams* waitp;
|
||||||
|
|
||||||
|
intptr_t readers; // Number of readers in mutex.
|
||||||
|
|
||||||
|
// When priority will next be read (cycles).
|
||||||
|
int64_t next_priority_read_cycles;
|
||||||
|
|
||||||
|
// Locks held; used during deadlock detection.
|
||||||
|
// Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
|
||||||
|
SynchLocksHeld *all_locks;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The instances of this class are allocated in NewThreadIdentity() with an
|
||||||
|
// alignment of PerThreadSynch::kAlignment.
|
||||||
|
struct ThreadIdentity {
|
||||||
|
// Must be the first member. The Mutex implementation requires that
|
||||||
|
// the PerThreadSynch object associated with each thread is
|
||||||
|
// PerThreadSynch::kAlignment aligned. We provide this alignment on
|
||||||
|
// ThreadIdentity itself.
|
||||||
|
PerThreadSynch per_thread_synch;
|
||||||
|
|
||||||
|
// Private: Reserved for absl::synchronization_internal::Waiter.
|
||||||
|
struct WaiterState {
|
||||||
|
alignas(void*) char data[128];
|
||||||
|
} waiter_state;
|
||||||
|
|
||||||
|
// Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
|
||||||
|
std::atomic<int>* blocked_count_ptr;
|
||||||
|
|
||||||
|
// The following variables are mostly read/written just by the
|
||||||
|
// thread itself. The only exception is that these are read by
|
||||||
|
// a ticker thread as a hint.
|
||||||
|
std::atomic<int> ticker; // Tick counter, incremented once per second.
|
||||||
|
std::atomic<int> wait_start; // Ticker value when thread started waiting.
|
||||||
|
std::atomic<bool> is_idle; // Has thread become idle yet?
|
||||||
|
|
||||||
|
ThreadIdentity* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the ThreadIdentity object representing the calling thread; guaranteed
|
||||||
|
// to be unique for its lifetime. The returned object will remain valid for the
|
||||||
|
// program's lifetime; although it may be re-assigned to a subsequent thread.
|
||||||
|
// If one does not exist, return nullptr instead.
|
||||||
|
//
|
||||||
|
// Does not malloc(*), and is async-signal safe.
|
||||||
|
// [*] Technically pthread_setspecific() does malloc on first use; however this
|
||||||
|
// is handled internally within tcmalloc's initialization already.
|
||||||
|
//
|
||||||
|
// New ThreadIdentity objects can be constructed and associated with a thread
|
||||||
|
// by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h.
|
||||||
|
ThreadIdentity* CurrentThreadIdentityIfPresent();
|
||||||
|
|
||||||
|
using ThreadIdentityReclaimerFunction = void (*)(void*);
|
||||||
|
|
||||||
|
// Sets the current thread identity to the given value. 'reclaimer' is a
|
||||||
|
// pointer to the global function for cleaning up instances on thread
|
||||||
|
// destruction.
|
||||||
|
void SetCurrentThreadIdentity(ThreadIdentity* identity,
|
||||||
|
ThreadIdentityReclaimerFunction reclaimer);
|
||||||
|
|
||||||
|
// Removes the currently associated ThreadIdentity from the running thread.
|
||||||
|
// This must be called from inside the ThreadIdentityReclaimerFunction, and only
|
||||||
|
// from that function.
|
||||||
|
void ClearCurrentThreadIdentity();
|
||||||
|
|
||||||
|
// May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode
|
||||||
|
// index>
|
||||||
|
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
|
||||||
|
#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be directly set
|
||||||
|
#else
|
||||||
|
#define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS
|
||||||
|
#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be directly set
|
||||||
|
#else
|
||||||
|
#define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||||
|
#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be directly set
|
||||||
|
#else
|
||||||
|
#define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ABSL_THREAD_IDENTITY_MODE
|
||||||
|
#error ABSL_THREAD_IDENTITY_MODE cannot be directly set
|
||||||
|
#elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE)
|
||||||
|
#define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
|
||||||
|
#elif defined(_WIN32) && !defined(__MINGW32__)
|
||||||
|
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||||
|
#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL)
|
||||||
|
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||||
|
#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
|
||||||
|
(__GOOGLE_GRTE_VERSION__ >= 20140228L)
|
||||||
|
// Support for async-safe TLS was specifically added in GRTEv4. It's not
|
||||||
|
// present in the upstream eglibc.
|
||||||
|
// Note: Current default for production systems.
|
||||||
|
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS
|
||||||
|
#else
|
||||||
|
#define ABSL_THREAD_IDENTITY_MODE \
|
||||||
|
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
|
||||||
|
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||||
|
|
||||||
|
#if ABSL_PER_THREAD_TLS
|
||||||
|
ABSL_CONST_INIT extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity*
|
||||||
|
thread_identity_ptr;
|
||||||
|
#elif defined(ABSL_HAVE_THREAD_LOCAL)
|
||||||
|
ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr;
|
||||||
|
#else
|
||||||
|
#error Thread-local storage not detected on this platform
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// thread_local variables cannot be in headers exposed by DLLs or in certain
|
||||||
|
// build configurations on Apple platforms. However, it is important for
|
||||||
|
// performance reasons in general that `CurrentThreadIdentityIfPresent` be
|
||||||
|
// inlined. In the other cases we opt to have the function not be inlined. Note
|
||||||
|
// that `CurrentThreadIdentityIfPresent` is declared above so we can exclude
|
||||||
|
// this entire inline definition.
|
||||||
|
#if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL) && \
|
||||||
|
!defined(ABSL_CONSUME_DLL)
|
||||||
|
#define ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
|
||||||
|
inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
|
||||||
|
return thread_identity_ptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif ABSL_THREAD_IDENTITY_MODE != \
|
||||||
|
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
|
||||||
|
#error Unknown ABSL_THREAD_IDENTITY_MODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
|
||||||
75
include/absl/base/internal/throw_delegate.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
// Helper functions that allow throwing exceptions consistently from anywhere.
|
||||||
|
// The main use case is for header-based libraries (eg templates), as they will
|
||||||
|
// be built by many different targets with their own compiler options.
|
||||||
|
// In particular, this will allow a safe way to throw exceptions even if the
|
||||||
|
// caller is compiled with -fno-exceptions. This is intended for implementing
|
||||||
|
// things like map<>::at(), which the standard documents as throwing an
|
||||||
|
// exception on error.
|
||||||
|
//
|
||||||
|
// Using other techniques like #if tricks could lead to ODR violations.
|
||||||
|
//
|
||||||
|
// You shouldn't use it unless you're writing code that you know will be built
|
||||||
|
// both with and without exceptions and you need to conform to an interface
|
||||||
|
// that uses exceptions.
|
||||||
|
|
||||||
|
[[noreturn]] void ThrowStdLogicError(const std::string& what_arg);
|
||||||
|
[[noreturn]] void ThrowStdLogicError(const char* what_arg);
|
||||||
|
[[noreturn]] void ThrowStdInvalidArgument(const std::string& what_arg);
|
||||||
|
[[noreturn]] void ThrowStdInvalidArgument(const char* what_arg);
|
||||||
|
[[noreturn]] void ThrowStdDomainError(const std::string& what_arg);
|
||||||
|
[[noreturn]] void ThrowStdDomainError(const char* what_arg);
|
||||||
|
[[noreturn]] void ThrowStdLengthError(const std::string& what_arg);
|
||||||
|
[[noreturn]] void ThrowStdLengthError(const char* what_arg);
|
||||||
|
[[noreturn]] void ThrowStdOutOfRange(const std::string& what_arg);
|
||||||
|
[[noreturn]] void ThrowStdOutOfRange(const char* what_arg);
|
||||||
|
[[noreturn]] void ThrowStdRuntimeError(const std::string& what_arg);
|
||||||
|
[[noreturn]] void ThrowStdRuntimeError(const char* what_arg);
|
||||||
|
[[noreturn]] void ThrowStdRangeError(const std::string& what_arg);
|
||||||
|
[[noreturn]] void ThrowStdRangeError(const char* what_arg);
|
||||||
|
[[noreturn]] void ThrowStdOverflowError(const std::string& what_arg);
|
||||||
|
[[noreturn]] void ThrowStdOverflowError(const char* what_arg);
|
||||||
|
[[noreturn]] void ThrowStdUnderflowError(const std::string& what_arg);
|
||||||
|
[[noreturn]] void ThrowStdUnderflowError(const char* what_arg);
|
||||||
|
|
||||||
|
[[noreturn]] void ThrowStdBadFunctionCall();
|
||||||
|
[[noreturn]] void ThrowStdBadAlloc();
|
||||||
|
|
||||||
|
// ThrowStdBadArrayNewLength() cannot be consistently supported because
|
||||||
|
// std::bad_array_new_length is missing in libstdc++ until 4.9.0.
|
||||||
|
// https://gcc.gnu.org/onlinedocs/gcc-4.8.3/libstdc++/api/a01379_source.html
|
||||||
|
// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/libstdc++/api/a01327_source.html
|
||||||
|
// libcxx (as of 3.2) and msvc (as of 2015) both have it.
|
||||||
|
// [[noreturn]] void ThrowStdBadArrayNewLength();
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
|
||||||
68
include/absl/base/internal/tsan_mutex_interface.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// This file is intended solely for spinlock.h.
|
||||||
|
// It provides ThreadSanitizer annotations for custom mutexes.
|
||||||
|
// See <sanitizer/tsan_interface.h> for meaning of these annotations.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
// ABSL_INTERNAL_HAVE_TSAN_INTERFACE
|
||||||
|
// Macro intended only for internal use.
|
||||||
|
//
|
||||||
|
// Checks whether LLVM Thread Sanitizer interfaces are available.
|
||||||
|
// First made available in LLVM 5.0 (Sep 2017).
|
||||||
|
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
|
||||||
|
#error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ABSL_HAVE_THREAD_SANITIZER) && defined(__has_include)
|
||||||
|
#if __has_include(<sanitizer/tsan_interface.h>)
|
||||||
|
#define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
|
||||||
|
#include <sanitizer/tsan_interface.h>
|
||||||
|
|
||||||
|
#define ABSL_TSAN_MUTEX_CREATE __tsan_mutex_create
|
||||||
|
#define ABSL_TSAN_MUTEX_DESTROY __tsan_mutex_destroy
|
||||||
|
#define ABSL_TSAN_MUTEX_PRE_LOCK __tsan_mutex_pre_lock
|
||||||
|
#define ABSL_TSAN_MUTEX_POST_LOCK __tsan_mutex_post_lock
|
||||||
|
#define ABSL_TSAN_MUTEX_PRE_UNLOCK __tsan_mutex_pre_unlock
|
||||||
|
#define ABSL_TSAN_MUTEX_POST_UNLOCK __tsan_mutex_post_unlock
|
||||||
|
#define ABSL_TSAN_MUTEX_PRE_SIGNAL __tsan_mutex_pre_signal
|
||||||
|
#define ABSL_TSAN_MUTEX_POST_SIGNAL __tsan_mutex_post_signal
|
||||||
|
#define ABSL_TSAN_MUTEX_PRE_DIVERT __tsan_mutex_pre_divert
|
||||||
|
#define ABSL_TSAN_MUTEX_POST_DIVERT __tsan_mutex_post_divert
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ABSL_TSAN_MUTEX_CREATE(...)
|
||||||
|
#define ABSL_TSAN_MUTEX_DESTROY(...)
|
||||||
|
#define ABSL_TSAN_MUTEX_PRE_LOCK(...)
|
||||||
|
#define ABSL_TSAN_MUTEX_POST_LOCK(...)
|
||||||
|
#define ABSL_TSAN_MUTEX_PRE_UNLOCK(...)
|
||||||
|
#define ABSL_TSAN_MUTEX_POST_UNLOCK(...)
|
||||||
|
#define ABSL_TSAN_MUTEX_PRE_SIGNAL(...)
|
||||||
|
#define ABSL_TSAN_MUTEX_POST_SIGNAL(...)
|
||||||
|
#define ABSL_TSAN_MUTEX_PRE_DIVERT(...)
|
||||||
|
#define ABSL_TSAN_MUTEX_POST_DIVERT(...)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
|
||||||
82
include/absl/base/internal/unaligned_access.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
// unaligned APIs
|
||||||
|
|
||||||
|
// Portable handling of unaligned loads, stores, and copies.
|
||||||
|
|
||||||
|
// The unaligned API is C++ only. The declarations use C++ features
|
||||||
|
// (namespaces, inline) which are absent or incompatible in C.
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
inline uint16_t UnalignedLoad16(const void *p) {
|
||||||
|
uint16_t t;
|
||||||
|
memcpy(&t, p, sizeof t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t UnalignedLoad32(const void *p) {
|
||||||
|
uint32_t t;
|
||||||
|
memcpy(&t, p, sizeof t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t UnalignedLoad64(const void *p) {
|
||||||
|
uint64_t t;
|
||||||
|
memcpy(&t, p, sizeof t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
|
||||||
|
|
||||||
|
inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
|
||||||
|
|
||||||
|
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
|
||||||
|
(absl::base_internal::UnalignedLoad16(_p))
|
||||||
|
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
|
||||||
|
(absl::base_internal::UnalignedLoad32(_p))
|
||||||
|
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
|
||||||
|
(absl::base_internal::UnalignedLoad64(_p))
|
||||||
|
|
||||||
|
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
|
||||||
|
(absl::base_internal::UnalignedStore16(_p, _val))
|
||||||
|
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
|
||||||
|
(absl::base_internal::UnalignedStore32(_p, _val))
|
||||||
|
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
|
||||||
|
(absl::base_internal::UnalignedStore64(_p, _val))
|
||||||
|
|
||||||
|
#endif // defined(__cplusplus), end of unaligned API
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
|
||||||
133
include/absl/base/internal/unscaledcycleclock.h
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// UnscaledCycleClock
|
||||||
|
// An UnscaledCycleClock yields the value and frequency of a cycle counter
|
||||||
|
// that increments at a rate that is approximately constant.
|
||||||
|
// This class is for internal use only, you should consider using CycleClock
|
||||||
|
// instead.
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// The cycle counter frequency is not necessarily the core clock frequency.
|
||||||
|
// That is, CycleCounter cycles are not necessarily "CPU cycles".
|
||||||
|
//
|
||||||
|
// An arbitrary offset may have been added to the counter at power on.
|
||||||
|
//
|
||||||
|
// On some platforms, the rate and offset of the counter may differ
|
||||||
|
// slightly when read from different CPUs of a multiprocessor. Usually,
|
||||||
|
// we try to ensure that the operating system adjusts values periodically
|
||||||
|
// so that values agree approximately. If you need stronger guarantees,
|
||||||
|
// consider using alternate interfaces.
|
||||||
|
//
|
||||||
|
// The CPU is not required to maintain the ordering of a cycle counter read
|
||||||
|
// with respect to surrounding instructions.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
|
||||||
|
#define ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "absl/base/port.h"
|
||||||
|
|
||||||
|
// The following platforms have an implementation of a hardware counter.
|
||||||
|
#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
|
||||||
|
defined(__powerpc__) || defined(__ppc__) || defined(__riscv) || \
|
||||||
|
defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC))
|
||||||
|
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 1
|
||||||
|
#else
|
||||||
|
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The following platforms often disable access to the hardware
|
||||||
|
// counter (through a sandbox) even if the underlying hardware has a
|
||||||
|
// usable counter. The CycleTimer interface also requires a *scaled*
|
||||||
|
// CycleClock that runs at atleast 1 MHz. We've found some Android
|
||||||
|
// ARM64 devices where this is not the case, so we disable it by
|
||||||
|
// default on Android ARM64.
|
||||||
|
#if defined(__native_client__) || (defined(__APPLE__)) || \
|
||||||
|
(defined(__ANDROID__) && defined(__aarch64__))
|
||||||
|
#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0
|
||||||
|
#else
|
||||||
|
#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// UnscaledCycleClock is an optional internal feature.
|
||||||
|
// Use "#if ABSL_USE_UNSCALED_CYCLECLOCK" to test for its presence.
|
||||||
|
// Can be overridden at compile-time via -DABSL_USE_UNSCALED_CYCLECLOCK=0|1
|
||||||
|
#if !defined(ABSL_USE_UNSCALED_CYCLECLOCK)
|
||||||
|
#define ABSL_USE_UNSCALED_CYCLECLOCK \
|
||||||
|
(ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION && \
|
||||||
|
ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ABSL_USE_UNSCALED_CYCLECLOCK
|
||||||
|
|
||||||
|
// This macro can be used to test if UnscaledCycleClock::Frequency()
|
||||||
|
// is NominalCPUFrequency() on a particular platform.
|
||||||
|
#if (defined(__i386__) || defined(__x86_64__) || defined(__riscv) || \
|
||||||
|
defined(_M_IX86) || defined(_M_X64))
|
||||||
|
#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace time_internal {
|
||||||
|
class UnscaledCycleClockWrapperForGetCurrentTime;
|
||||||
|
} // namespace time_internal
|
||||||
|
|
||||||
|
namespace base_internal {
|
||||||
|
class CycleClock;
|
||||||
|
class UnscaledCycleClockWrapperForInitializeFrequency;
|
||||||
|
|
||||||
|
class UnscaledCycleClock {
|
||||||
|
private:
|
||||||
|
UnscaledCycleClock() = delete;
|
||||||
|
|
||||||
|
// Return the value of a cycle counter that counts at a rate that is
|
||||||
|
// approximately constant.
|
||||||
|
static int64_t Now();
|
||||||
|
|
||||||
|
// Return the how much UnscaledCycleClock::Now() increases per second.
|
||||||
|
// This is not necessarily the core CPU clock frequency.
|
||||||
|
// It may be the nominal value report by the kernel, rather than a measured
|
||||||
|
// value.
|
||||||
|
static double Frequency();
|
||||||
|
|
||||||
|
// Allowed users
|
||||||
|
friend class base_internal::CycleClock;
|
||||||
|
friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime;
|
||||||
|
friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
|
||||||
|
inline int64_t UnscaledCycleClock::Now() {
|
||||||
|
uint64_t low, high;
|
||||||
|
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
|
||||||
|
return (high << 32) | low;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
|
||||||
172
include/absl/base/log_severity.h
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_LOG_SEVERITY_H_
|
||||||
|
#define ABSL_BASE_LOG_SEVERITY_H_
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// absl::LogSeverity
|
||||||
|
//
|
||||||
|
// Four severity levels are defined. Logging APIs should terminate the program
|
||||||
|
// when a message is logged at severity `kFatal`; the other levels have no
|
||||||
|
// special semantics.
|
||||||
|
//
|
||||||
|
// Values other than the four defined levels (e.g. produced by `static_cast`)
|
||||||
|
// are valid, but their semantics when passed to a function, macro, or flag
|
||||||
|
// depend on the function, macro, or flag. The usual behavior is to normalize
|
||||||
|
// such values to a defined severity level, however in some cases values other
|
||||||
|
// than the defined levels are useful for comparison.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // Effectively disables all logging:
|
||||||
|
// SetMinLogLevel(static_cast<absl::LogSeverity>(100));
|
||||||
|
//
|
||||||
|
// Abseil flags may be defined with type `LogSeverity`. Dependency layering
|
||||||
|
// constraints require that the `AbslParseFlag()` overload be declared and
|
||||||
|
// defined in the flags library itself rather than here. The `AbslUnparseFlag()`
|
||||||
|
// overload is defined there as well for consistency.
|
||||||
|
//
|
||||||
|
// absl::LogSeverity Flag String Representation
|
||||||
|
//
|
||||||
|
// An `absl::LogSeverity` has a string representation used for parsing
|
||||||
|
// command-line flags based on the enumerator name (e.g. `kFatal`) or
|
||||||
|
// its unprefixed name (without the `k`) in any case-insensitive form. (E.g.
|
||||||
|
// "FATAL", "fatal" or "Fatal" are all valid.) Unparsing such flags produces an
|
||||||
|
// unprefixed string representation in all caps (e.g. "FATAL") or an integer.
|
||||||
|
//
|
||||||
|
// Additionally, the parser accepts arbitrary integers (as if the type were
|
||||||
|
// `int`).
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// --my_log_level=kInfo
|
||||||
|
// --my_log_level=INFO
|
||||||
|
// --my_log_level=info
|
||||||
|
// --my_log_level=0
|
||||||
|
//
|
||||||
|
// Unparsing a flag produces the same result as `absl::LogSeverityName()` for
|
||||||
|
// the standard levels and a base-ten integer otherwise.
|
||||||
|
enum class LogSeverity : int {
|
||||||
|
kInfo = 0,
|
||||||
|
kWarning = 1,
|
||||||
|
kError = 2,
|
||||||
|
kFatal = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
// LogSeverities()
|
||||||
|
//
|
||||||
|
// Returns an iterable of all standard `absl::LogSeverity` values, ordered from
|
||||||
|
// least to most severe.
|
||||||
|
constexpr std::array<absl::LogSeverity, 4> LogSeverities() {
|
||||||
|
return {{absl::LogSeverity::kInfo, absl::LogSeverity::kWarning,
|
||||||
|
absl::LogSeverity::kError, absl::LogSeverity::kFatal}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogSeverityName()
|
||||||
|
//
|
||||||
|
// Returns the all-caps string representation (e.g. "INFO") of the specified
|
||||||
|
// severity level if it is one of the standard levels and "UNKNOWN" otherwise.
|
||||||
|
constexpr const char* LogSeverityName(absl::LogSeverity s) {
|
||||||
|
return s == absl::LogSeverity::kInfo
|
||||||
|
? "INFO"
|
||||||
|
: s == absl::LogSeverity::kWarning
|
||||||
|
? "WARNING"
|
||||||
|
: s == absl::LogSeverity::kError
|
||||||
|
? "ERROR"
|
||||||
|
: s == absl::LogSeverity::kFatal ? "FATAL" : "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
// NormalizeLogSeverity()
|
||||||
|
//
|
||||||
|
// Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal`
|
||||||
|
// normalize to `kError` (**NOT** `kFatal`).
|
||||||
|
constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) {
|
||||||
|
return s < absl::LogSeverity::kInfo
|
||||||
|
? absl::LogSeverity::kInfo
|
||||||
|
: s > absl::LogSeverity::kFatal ? absl::LogSeverity::kError : s;
|
||||||
|
}
|
||||||
|
constexpr absl::LogSeverity NormalizeLogSeverity(int s) {
|
||||||
|
return absl::NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// operator<<
|
||||||
|
//
|
||||||
|
// The exact representation of a streamed `absl::LogSeverity` is deliberately
|
||||||
|
// unspecified; do not rely on it.
|
||||||
|
std::ostream& operator<<(std::ostream& os, absl::LogSeverity s);
|
||||||
|
|
||||||
|
// Enums representing a lower bound for LogSeverity. APIs that only operate on
|
||||||
|
// messages of at least a certain level (for example, `SetMinLogLevel()`) use
|
||||||
|
// this type to specify that level. absl::LogSeverityAtLeast::kInfinity is
|
||||||
|
// a level above all threshold levels and therefore no log message will
|
||||||
|
// ever meet this threshold.
|
||||||
|
enum class LogSeverityAtLeast : int {
|
||||||
|
kInfo = static_cast<int>(absl::LogSeverity::kInfo),
|
||||||
|
kWarning = static_cast<int>(absl::LogSeverity::kWarning),
|
||||||
|
kError = static_cast<int>(absl::LogSeverity::kError),
|
||||||
|
kFatal = static_cast<int>(absl::LogSeverity::kFatal),
|
||||||
|
kInfinity = 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtLeast s);
|
||||||
|
|
||||||
|
// Enums representing an upper bound for LogSeverity. APIs that only operate on
|
||||||
|
// messages of at most a certain level (for example, buffer all messages at or
|
||||||
|
// below a certain level) use this type to specify that level.
|
||||||
|
// absl::LogSeverityAtMost::kNegativeInfinity is a level below all threshold
|
||||||
|
// levels and therefore will exclude all log messages.
|
||||||
|
enum class LogSeverityAtMost : int {
|
||||||
|
kNegativeInfinity = -1000,
|
||||||
|
kInfo = static_cast<int>(absl::LogSeverity::kInfo),
|
||||||
|
kWarning = static_cast<int>(absl::LogSeverity::kWarning),
|
||||||
|
kError = static_cast<int>(absl::LogSeverity::kError),
|
||||||
|
kFatal = static_cast<int>(absl::LogSeverity::kFatal),
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtMost s);
|
||||||
|
|
||||||
|
#define COMPOP(op1, op2, T) \
|
||||||
|
constexpr bool operator op1(absl::T lhs, absl::LogSeverity rhs) { \
|
||||||
|
return static_cast<absl::LogSeverity>(lhs) op1 rhs; \
|
||||||
|
} \
|
||||||
|
constexpr bool operator op2(absl::LogSeverity lhs, absl::T rhs) { \
|
||||||
|
return lhs op2 static_cast<absl::LogSeverity>(rhs); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparisons between `LogSeverity` and `LogSeverityAtLeast`/
|
||||||
|
// `LogSeverityAtMost` are only supported in one direction.
|
||||||
|
// Valid checks are:
|
||||||
|
// LogSeverity >= LogSeverityAtLeast
|
||||||
|
// LogSeverity < LogSeverityAtLeast
|
||||||
|
// LogSeverity <= LogSeverityAtMost
|
||||||
|
// LogSeverity > LogSeverityAtMost
|
||||||
|
COMPOP(>, <, LogSeverityAtLeast)
|
||||||
|
COMPOP(<=, >=, LogSeverityAtLeast)
|
||||||
|
COMPOP(<, >, LogSeverityAtMost)
|
||||||
|
COMPOP(>=, <=, LogSeverityAtMost)
|
||||||
|
#undef COMPOP
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_LOG_SEVERITY_H_
|
||||||
158
include/absl/base/macros.h
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: macros.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header file defines the set of language macros used within Abseil code.
|
||||||
|
// For the set of macros used to determine supported compilers and platforms,
|
||||||
|
// see absl/base/config.h instead.
|
||||||
|
//
|
||||||
|
// This code is compiled directly on many platforms, including client
|
||||||
|
// platforms like Windows, Mac, and embedded systems. Before making
|
||||||
|
// any changes here, make sure that you're not breaking any platforms.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_MACROS_H_
|
||||||
|
#define ABSL_BASE_MACROS_H_
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
#include "absl/base/optimization.h"
|
||||||
|
#include "absl/base/port.h"
|
||||||
|
|
||||||
|
// ABSL_ARRAYSIZE()
|
||||||
|
//
|
||||||
|
// Returns the number of elements in an array as a compile-time constant, which
|
||||||
|
// can be used in defining new arrays. If you use this macro on a pointer by
|
||||||
|
// mistake, you will get a compile-time error.
|
||||||
|
#define ABSL_ARRAYSIZE(array) \
|
||||||
|
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace macros_internal {
|
||||||
|
// Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
|
||||||
|
// The function doesn't need a definition, as we only use its type.
|
||||||
|
template <typename T, size_t N>
|
||||||
|
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
|
||||||
|
} // namespace macros_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
// ABSL_BAD_CALL_IF()
|
||||||
|
//
|
||||||
|
// Used on a function overload to trap bad calls: any call that matches the
|
||||||
|
// overload will cause a compile-time error. This macro uses a clang-specific
|
||||||
|
// "enable_if" attribute, as described at
|
||||||
|
// https://clang.llvm.org/docs/AttributeReference.html#enable-if
|
||||||
|
//
|
||||||
|
// Overloads which use this macro should be bracketed by
|
||||||
|
// `#ifdef ABSL_BAD_CALL_IF`.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// int isdigit(int c);
|
||||||
|
// #ifdef ABSL_BAD_CALL_IF
|
||||||
|
// int isdigit(int c)
|
||||||
|
// ABSL_BAD_CALL_IF(c <= -1 || c > 255,
|
||||||
|
// "'c' must have the value of an unsigned char or EOF");
|
||||||
|
// #endif // ABSL_BAD_CALL_IF
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(enable_if)
|
||||||
|
#define ABSL_BAD_CALL_IF(expr, msg) \
|
||||||
|
__attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ASSERT()
|
||||||
|
//
|
||||||
|
// In C++11, `assert` can't be used portably within constexpr functions.
|
||||||
|
// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr
|
||||||
|
// functions. Example:
|
||||||
|
//
|
||||||
|
// constexpr double Divide(double a, double b) {
|
||||||
|
// return ABSL_ASSERT(b != 0), a / b;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// This macro is inspired by
|
||||||
|
// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
|
||||||
|
#if defined(NDEBUG)
|
||||||
|
#define ABSL_ASSERT(expr) \
|
||||||
|
(false ? static_cast<void>(expr) : static_cast<void>(0))
|
||||||
|
#else
|
||||||
|
#define ABSL_ASSERT(expr) \
|
||||||
|
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
|
||||||
|
: [] { assert(false && #expr); }()) // NOLINT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// `ABSL_INTERNAL_HARDENING_ABORT()` controls how `ABSL_HARDENING_ASSERT()`
|
||||||
|
// aborts the program in release mode (when NDEBUG is defined). The
|
||||||
|
// implementation should abort the program as quickly as possible and ideally it
|
||||||
|
// should not be possible to ignore the abort request.
|
||||||
|
#if (ABSL_HAVE_BUILTIN(__builtin_trap) && \
|
||||||
|
ABSL_HAVE_BUILTIN(__builtin_unreachable)) || \
|
||||||
|
(defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_INTERNAL_HARDENING_ABORT() \
|
||||||
|
do { \
|
||||||
|
__builtin_trap(); \
|
||||||
|
__builtin_unreachable(); \
|
||||||
|
} while (false)
|
||||||
|
#else
|
||||||
|
#define ABSL_INTERNAL_HARDENING_ABORT() abort()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_HARDENING_ASSERT()
|
||||||
|
//
|
||||||
|
// `ABSL_HARDENING_ASSERT()` is like `ABSL_ASSERT()`, but used to implement
|
||||||
|
// runtime assertions that should be enabled in hardened builds even when
|
||||||
|
// `NDEBUG` is defined.
|
||||||
|
//
|
||||||
|
// When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT()` is identical to
|
||||||
|
// `ABSL_ASSERT()`.
|
||||||
|
//
|
||||||
|
// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
|
||||||
|
// hardened mode.
|
||||||
|
#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
|
||||||
|
#define ABSL_HARDENING_ASSERT(expr) \
|
||||||
|
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
|
||||||
|
: [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
|
||||||
|
#else
|
||||||
|
#define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||||
|
#define ABSL_INTERNAL_TRY try
|
||||||
|
#define ABSL_INTERNAL_CATCH_ANY catch (...)
|
||||||
|
#define ABSL_INTERNAL_RETHROW do { throw; } while (false)
|
||||||
|
#else // ABSL_HAVE_EXCEPTIONS
|
||||||
|
#define ABSL_INTERNAL_TRY if (true)
|
||||||
|
#define ABSL_INTERNAL_CATCH_ANY else if (false)
|
||||||
|
#define ABSL_INTERNAL_RETHROW do {} while (false)
|
||||||
|
#endif // ABSL_HAVE_EXCEPTIONS
|
||||||
|
|
||||||
|
// `ABSL_INTERNAL_UNREACHABLE` is an unreachable statement. A program which
|
||||||
|
// reaches one has undefined behavior, and the compiler may optimize
|
||||||
|
// accordingly.
|
||||||
|
#if defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
|
||||||
|
#define ABSL_INTERNAL_UNREACHABLE __builtin_unreachable()
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define ABSL_INTERNAL_UNREACHABLE __assume(0)
|
||||||
|
#else
|
||||||
|
#define ABSL_INTERNAL_UNREACHABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_MACROS_H_
|
||||||
252
include/absl/base/optimization.h
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: optimization.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header file defines portable macros for performance optimization.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_OPTIMIZATION_H_
|
||||||
|
#define ABSL_BASE_OPTIMIZATION_H_
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION
|
||||||
|
//
|
||||||
|
// Instructs the compiler to avoid optimizing tail-call recursion. This macro is
|
||||||
|
// useful when you wish to preserve the existing function order within a stack
|
||||||
|
// trace for logging, debugging, or profiling purposes.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// int f() {
|
||||||
|
// int result = g();
|
||||||
|
// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
#if defined(__pnacl__)
|
||||||
|
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
|
||||||
|
#elif defined(__clang__)
|
||||||
|
// Clang will not tail call given inline volatile assembly.
|
||||||
|
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
// GCC will not tail call given inline volatile assembly.
|
||||||
|
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#include <intrin.h>
|
||||||
|
// The __nop() intrinsic blocks the optimisation.
|
||||||
|
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
|
||||||
|
#else
|
||||||
|
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_CACHELINE_SIZE
|
||||||
|
//
|
||||||
|
// Explicitly defines the size of the L1 cache for purposes of alignment.
|
||||||
|
// Setting the cacheline size allows you to specify that certain objects be
|
||||||
|
// aligned on a cacheline boundary with `ABSL_CACHELINE_ALIGNED` declarations.
|
||||||
|
// (See below.)
|
||||||
|
//
|
||||||
|
// NOTE: this macro should be replaced with the following C++17 features, when
|
||||||
|
// those are generally available:
|
||||||
|
//
|
||||||
|
// * `std::hardware_constructive_interference_size`
|
||||||
|
// * `std::hardware_destructive_interference_size`
|
||||||
|
//
|
||||||
|
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
|
||||||
|
// for more information.
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
// Cache line alignment
|
||||||
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
|
#define ABSL_CACHELINE_SIZE 64
|
||||||
|
#elif defined(__powerpc64__)
|
||||||
|
#define ABSL_CACHELINE_SIZE 128
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
// We would need to read special register ctr_el0 to find out L1 dcache size.
|
||||||
|
// This value is a good estimate based on a real aarch64 machine.
|
||||||
|
#define ABSL_CACHELINE_SIZE 64
|
||||||
|
#elif defined(__arm__)
|
||||||
|
// Cache line sizes for ARM: These values are not strictly correct since
|
||||||
|
// cache line sizes depend on implementations, not architectures. There
|
||||||
|
// are even implementations with cache line sizes configurable at boot
|
||||||
|
// time.
|
||||||
|
#if defined(__ARM_ARCH_5T__)
|
||||||
|
#define ABSL_CACHELINE_SIZE 32
|
||||||
|
#elif defined(__ARM_ARCH_7A__)
|
||||||
|
#define ABSL_CACHELINE_SIZE 64
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ABSL_CACHELINE_SIZE
|
||||||
|
// A reasonable default guess. Note that overestimates tend to waste more
|
||||||
|
// space, while underestimates tend to waste more time.
|
||||||
|
#define ABSL_CACHELINE_SIZE 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_CACHELINE_ALIGNED
|
||||||
|
//
|
||||||
|
// Indicates that the declared object be cache aligned using
|
||||||
|
// `ABSL_CACHELINE_SIZE` (see above). Cacheline aligning objects allows you to
|
||||||
|
// load a set of related objects in the L1 cache for performance improvements.
|
||||||
|
// Cacheline aligning objects properly allows constructive memory sharing and
|
||||||
|
// prevents destructive (or "false") memory sharing.
|
||||||
|
//
|
||||||
|
// NOTE: callers should replace uses of this macro with `alignas()` using
|
||||||
|
// `std::hardware_constructive_interference_size` and/or
|
||||||
|
// `std::hardware_destructive_interference_size` when C++17 becomes available to
|
||||||
|
// them.
|
||||||
|
//
|
||||||
|
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
|
||||||
|
// for more information.
|
||||||
|
//
|
||||||
|
// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to an `__attribute__`
|
||||||
|
// or `__declspec` attribute. For compilers where this is not known to work,
|
||||||
|
// the macro expands to nothing.
|
||||||
|
//
|
||||||
|
// No further guarantees are made here. The result of applying the macro
|
||||||
|
// to variables and types is always implementation-defined.
|
||||||
|
//
|
||||||
|
// WARNING: It is easy to use this attribute incorrectly, even to the point
|
||||||
|
// of causing bugs that are difficult to diagnose, crash, etc. It does not
|
||||||
|
// of itself guarantee that objects are aligned to a cache line.
|
||||||
|
//
|
||||||
|
// NOTE: Some compilers are picky about the locations of annotations such as
|
||||||
|
// this attribute, so prefer to put it at the beginning of your declaration.
|
||||||
|
// For example,
|
||||||
|
//
|
||||||
|
// ABSL_CACHELINE_ALIGNED static Foo* foo = ...
|
||||||
|
//
|
||||||
|
// class ABSL_CACHELINE_ALIGNED Bar { ...
|
||||||
|
//
|
||||||
|
// Recommendations:
|
||||||
|
//
|
||||||
|
// 1) Consult compiler documentation; this comment is not kept in sync as
|
||||||
|
// toolchains evolve.
|
||||||
|
// 2) Verify your use has the intended effect. This often requires inspecting
|
||||||
|
// the generated machine code.
|
||||||
|
// 3) Prefer applying this attribute to individual variables. Avoid
|
||||||
|
// applying it to types. This tends to localize the effect.
|
||||||
|
#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE)))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define ABSL_CACHELINE_SIZE 64
|
||||||
|
#define ABSL_CACHELINE_ALIGNED __declspec(align(ABSL_CACHELINE_SIZE))
|
||||||
|
#else
|
||||||
|
#define ABSL_CACHELINE_SIZE 64
|
||||||
|
#define ABSL_CACHELINE_ALIGNED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_PREDICT_TRUE, ABSL_PREDICT_FALSE
|
||||||
|
//
|
||||||
|
// Enables the compiler to prioritize compilation using static analysis for
|
||||||
|
// likely paths within a boolean branch.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// if (ABSL_PREDICT_TRUE(expression)) {
|
||||||
|
// return result; // Faster if more likely
|
||||||
|
// } else {
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Compilers can use the information that a certain branch is not likely to be
|
||||||
|
// taken (for instance, a CHECK failure) to optimize for the common case in
|
||||||
|
// the absence of better information (ie. compiling gcc with `-fprofile-arcs`).
|
||||||
|
//
|
||||||
|
// Recommendation: Modern CPUs dynamically predict branch execution paths,
|
||||||
|
// typically with accuracy greater than 97%. As a result, annotating every
|
||||||
|
// branch in a codebase is likely counterproductive; however, annotating
|
||||||
|
// specific branches that are both hot and consistently mispredicted is likely
|
||||||
|
// to yield performance improvements.
|
||||||
|
#if ABSL_HAVE_BUILTIN(__builtin_expect) || \
|
||||||
|
(defined(__GNUC__) && !defined(__clang__))
|
||||||
|
#define ABSL_PREDICT_FALSE(x) (__builtin_expect(false || (x), false))
|
||||||
|
#define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
|
||||||
|
#else
|
||||||
|
#define ABSL_PREDICT_FALSE(x) (x)
|
||||||
|
#define ABSL_PREDICT_TRUE(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ASSUME(cond)
|
||||||
|
//
|
||||||
|
// Informs the compiler that a condition is always true and that it can assume
|
||||||
|
// it to be true for optimization purposes.
|
||||||
|
//
|
||||||
|
// WARNING: If the condition is false, the program can produce undefined and
|
||||||
|
// potentially dangerous behavior.
|
||||||
|
//
|
||||||
|
// In !NDEBUG mode, the condition is checked with an assert().
|
||||||
|
//
|
||||||
|
// NOTE: The expression must not have side effects, as it may only be evaluated
|
||||||
|
// in some compilation modes and not others. Some compilers may issue a warning
|
||||||
|
// if the compiler cannot prove the expression has no side effects. For example,
|
||||||
|
// the expression should not use a function call since the compiler cannot prove
|
||||||
|
// that a function call does not have side effects.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// int x = ...;
|
||||||
|
// ABSL_ASSUME(x >= 0);
|
||||||
|
// // The compiler can optimize the division to a simple right shift using the
|
||||||
|
// // assumption specified above.
|
||||||
|
// int y = x / 16;
|
||||||
|
//
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
#define ABSL_ASSUME(cond) assert(cond)
|
||||||
|
#elif ABSL_HAVE_BUILTIN(__builtin_assume)
|
||||||
|
#define ABSL_ASSUME(cond) __builtin_assume(cond)
|
||||||
|
#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
|
||||||
|
#define ABSL_ASSUME(cond) \
|
||||||
|
do { \
|
||||||
|
if (!(cond)) __builtin_unreachable(); \
|
||||||
|
} while (0)
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define ABSL_ASSUME(cond) __assume(cond)
|
||||||
|
#else
|
||||||
|
#define ABSL_ASSUME(cond) \
|
||||||
|
do { \
|
||||||
|
static_cast<void>(false && (cond)); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond)
|
||||||
|
// This macro forces small unique name on a static file level symbols like
|
||||||
|
// static local variables or static functions. This is intended to be used in
|
||||||
|
// macro definitions to optimize the cost of generated code. Do NOT use it on
|
||||||
|
// symbols exported from translation unit since it may cause a link time
|
||||||
|
// conflict.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// #define MY_MACRO(txt)
|
||||||
|
// namespace {
|
||||||
|
// char VeryVeryLongVarName[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = txt;
|
||||||
|
// const char* VeryVeryLongFuncName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
|
||||||
|
// const char* VeryVeryLongFuncName() { return txt; }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) #x
|
||||||
|
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME1(x) ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x)
|
||||||
|
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() \
|
||||||
|
asm(ABSL_INTERNAL_UNIQUE_SMALL_NAME1(.absl.__COUNTER__))
|
||||||
|
#else
|
||||||
|
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_OPTIMIZATION_H_
|
||||||
238
include/absl/base/options.h
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
// Copyright 2019 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: options.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This file contains Abseil configuration options for setting specific
|
||||||
|
// implementations instead of letting Abseil determine which implementation to
|
||||||
|
// use at compile-time. Setting these options may be useful for package or build
|
||||||
|
// managers who wish to guarantee ABI stability within binary builds (which are
|
||||||
|
// otherwise difficult to enforce).
|
||||||
|
//
|
||||||
|
// *** IMPORTANT NOTICE FOR PACKAGE MANAGERS: It is important that
|
||||||
|
// maintainers of package managers who wish to package Abseil read and
|
||||||
|
// understand this file! ***
|
||||||
|
//
|
||||||
|
// Abseil contains a number of possible configuration endpoints, based on
|
||||||
|
// parameters such as the detected platform, language version, or command-line
|
||||||
|
// flags used to invoke the underlying binary. As is the case with all
|
||||||
|
// libraries, binaries which contain Abseil code must ensure that separate
|
||||||
|
// packages use the same compiled copy of Abseil to avoid a diamond dependency
|
||||||
|
// problem, which can occur if two packages built with different Abseil
|
||||||
|
// configuration settings are linked together. Diamond dependency problems in
|
||||||
|
// C++ may manifest as violations to the One Definition Rule (ODR) (resulting in
|
||||||
|
// linker errors), or undefined behavior (resulting in crashes).
|
||||||
|
//
|
||||||
|
// Diamond dependency problems can be avoided if all packages utilize the same
|
||||||
|
// exact version of Abseil. Building from source code with the same compilation
|
||||||
|
// parameters is the easiest way to avoid such dependency problems. However, for
|
||||||
|
// package managers who cannot control such compilation parameters, we are
|
||||||
|
// providing the file to allow you to inject ABI (Application Binary Interface)
|
||||||
|
// stability across builds. Settings options in this file will neither change
|
||||||
|
// API nor ABI, providing a stable copy of Abseil between packages.
|
||||||
|
//
|
||||||
|
// Care must be taken to keep options within these configurations isolated
|
||||||
|
// from any other dynamic settings, such as command-line flags which could alter
|
||||||
|
// these options. This file is provided specifically to help build and package
|
||||||
|
// managers provide a stable copy of Abseil within their libraries and binaries;
|
||||||
|
// other developers should not have need to alter the contents of this file.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Usage
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// For any particular package release, set the appropriate definitions within
|
||||||
|
// this file to whatever value makes the most sense for your package(s). Note
|
||||||
|
// that, by default, most of these options, at the moment, affect the
|
||||||
|
// implementation of types; future options may affect other implementation
|
||||||
|
// details.
|
||||||
|
//
|
||||||
|
// NOTE: the defaults within this file all assume that Abseil can select the
|
||||||
|
// proper Abseil implementation at compile-time, which will not be sufficient
|
||||||
|
// to guarantee ABI stability to package managers.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_OPTIONS_H_
|
||||||
|
#define ABSL_BASE_OPTIONS_H_
|
||||||
|
|
||||||
|
// Include a standard library header to allow configuration based on the
|
||||||
|
// standard library in use.
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <ciso646>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Type Compatibility Options
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// ABSL_OPTION_USE_STD_ANY
|
||||||
|
//
|
||||||
|
// This option controls whether absl::any is implemented as an alias to
|
||||||
|
// std::any, or as an independent implementation.
|
||||||
|
//
|
||||||
|
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||||
|
// support, and is expected to work on every toolchain we support.
|
||||||
|
//
|
||||||
|
// A value of 1 means to use an alias to std::any. This requires that all code
|
||||||
|
// using Abseil is built in C++17 mode or later.
|
||||||
|
//
|
||||||
|
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||||
|
// and use an alias only if a working std::any is available. This option is
|
||||||
|
// useful when you are building your entire program, including all of its
|
||||||
|
// dependencies, from source. It should not be used otherwise -- for example,
|
||||||
|
// if you are distributing Abseil in a binary package manager -- since in
|
||||||
|
// mode 2, absl::any will name a different type, with a different mangled name
|
||||||
|
// and binary layout, depending on the compiler flags passed by the end user.
|
||||||
|
// For more info, see https://abseil.io/about/design/dropin-types.
|
||||||
|
//
|
||||||
|
// User code should not inspect this macro. To check in the preprocessor if
|
||||||
|
// absl::any is a typedef of std::any, use the feature macro ABSL_USES_STD_ANY.
|
||||||
|
|
||||||
|
#define ABSL_OPTION_USE_STD_ANY 2
|
||||||
|
|
||||||
|
|
||||||
|
// ABSL_OPTION_USE_STD_OPTIONAL
|
||||||
|
//
|
||||||
|
// This option controls whether absl::optional is implemented as an alias to
|
||||||
|
// std::optional, or as an independent implementation.
|
||||||
|
//
|
||||||
|
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||||
|
// support, and is expected to work on every toolchain we support.
|
||||||
|
//
|
||||||
|
// A value of 1 means to use an alias to std::optional. This requires that all
|
||||||
|
// code using Abseil is built in C++17 mode or later.
|
||||||
|
//
|
||||||
|
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||||
|
// and use an alias only if a working std::optional is available. This option
|
||||||
|
// is useful when you are building your program from source. It should not be
|
||||||
|
// used otherwise -- for example, if you are distributing Abseil in a binary
|
||||||
|
// package manager -- since in mode 2, absl::optional will name a different
|
||||||
|
// type, with a different mangled name and binary layout, depending on the
|
||||||
|
// compiler flags passed by the end user. For more info, see
|
||||||
|
// https://abseil.io/about/design/dropin-types.
|
||||||
|
|
||||||
|
// User code should not inspect this macro. To check in the preprocessor if
|
||||||
|
// absl::optional is a typedef of std::optional, use the feature macro
|
||||||
|
// ABSL_USES_STD_OPTIONAL.
|
||||||
|
|
||||||
|
#define ABSL_OPTION_USE_STD_OPTIONAL 2
|
||||||
|
|
||||||
|
|
||||||
|
// ABSL_OPTION_USE_STD_STRING_VIEW
|
||||||
|
//
|
||||||
|
// This option controls whether absl::string_view is implemented as an alias to
|
||||||
|
// std::string_view, or as an independent implementation.
|
||||||
|
//
|
||||||
|
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||||
|
// support, and is expected to work on every toolchain we support.
|
||||||
|
//
|
||||||
|
// A value of 1 means to use an alias to std::string_view. This requires that
|
||||||
|
// all code using Abseil is built in C++17 mode or later.
|
||||||
|
//
|
||||||
|
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||||
|
// and use an alias only if a working std::string_view is available. This
|
||||||
|
// option is useful when you are building your program from source. It should
|
||||||
|
// not be used otherwise -- for example, if you are distributing Abseil in a
|
||||||
|
// binary package manager -- since in mode 2, absl::string_view will name a
|
||||||
|
// different type, with a different mangled name and binary layout, depending on
|
||||||
|
// the compiler flags passed by the end user. For more info, see
|
||||||
|
// https://abseil.io/about/design/dropin-types.
|
||||||
|
//
|
||||||
|
// User code should not inspect this macro. To check in the preprocessor if
|
||||||
|
// absl::string_view is a typedef of std::string_view, use the feature macro
|
||||||
|
// ABSL_USES_STD_STRING_VIEW.
|
||||||
|
|
||||||
|
#define ABSL_OPTION_USE_STD_STRING_VIEW 2
|
||||||
|
|
||||||
|
// ABSL_OPTION_USE_STD_VARIANT
|
||||||
|
//
|
||||||
|
// This option controls whether absl::variant is implemented as an alias to
|
||||||
|
// std::variant, or as an independent implementation.
|
||||||
|
//
|
||||||
|
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||||
|
// support, and is expected to work on every toolchain we support.
|
||||||
|
//
|
||||||
|
// A value of 1 means to use an alias to std::variant. This requires that all
|
||||||
|
// code using Abseil is built in C++17 mode or later.
|
||||||
|
//
|
||||||
|
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||||
|
// and use an alias only if a working std::variant is available. This option
|
||||||
|
// is useful when you are building your program from source. It should not be
|
||||||
|
// used otherwise -- for example, if you are distributing Abseil in a binary
|
||||||
|
// package manager -- since in mode 2, absl::variant will name a different
|
||||||
|
// type, with a different mangled name and binary layout, depending on the
|
||||||
|
// compiler flags passed by the end user. For more info, see
|
||||||
|
// https://abseil.io/about/design/dropin-types.
|
||||||
|
//
|
||||||
|
// User code should not inspect this macro. To check in the preprocessor if
|
||||||
|
// absl::variant is a typedef of std::variant, use the feature macro
|
||||||
|
// ABSL_USES_STD_VARIANT.
|
||||||
|
|
||||||
|
#define ABSL_OPTION_USE_STD_VARIANT 2
|
||||||
|
|
||||||
|
|
||||||
|
// ABSL_OPTION_USE_INLINE_NAMESPACE
|
||||||
|
// ABSL_OPTION_INLINE_NAMESPACE_NAME
|
||||||
|
//
|
||||||
|
// These options controls whether all entities in the absl namespace are
|
||||||
|
// contained within an inner inline namespace. This does not affect the
|
||||||
|
// user-visible API of Abseil, but it changes the mangled names of all symbols.
|
||||||
|
//
|
||||||
|
// This can be useful as a version tag if you are distributing Abseil in
|
||||||
|
// precompiled form. This will prevent a binary library build of Abseil with
|
||||||
|
// one inline namespace being used with headers configured with a different
|
||||||
|
// inline namespace name. Binary packagers are reminded that Abseil does not
|
||||||
|
// guarantee any ABI stability in Abseil, so any update of Abseil or
|
||||||
|
// configuration change in such a binary package should be combined with a
|
||||||
|
// new, unique value for the inline namespace name.
|
||||||
|
//
|
||||||
|
// A value of 0 means not to use inline namespaces.
|
||||||
|
//
|
||||||
|
// A value of 1 means to use an inline namespace with the given name inside
|
||||||
|
// namespace absl. If this is set, ABSL_OPTION_INLINE_NAMESPACE_NAME must also
|
||||||
|
// be changed to a new, unique identifier name. In particular "head" is not
|
||||||
|
// allowed.
|
||||||
|
|
||||||
|
#define ABSL_OPTION_USE_INLINE_NAMESPACE 1
|
||||||
|
#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20220623
|
||||||
|
|
||||||
|
// ABSL_OPTION_HARDENED
|
||||||
|
//
|
||||||
|
// This option enables a "hardened" build in release mode (in this context,
|
||||||
|
// release mode is defined as a build where the `NDEBUG` macro is defined).
|
||||||
|
//
|
||||||
|
// A value of 0 means that "hardened" mode is not enabled.
|
||||||
|
//
|
||||||
|
// A value of 1 means that "hardened" mode is enabled.
|
||||||
|
//
|
||||||
|
// Hardened builds have additional security checks enabled when `NDEBUG` is
|
||||||
|
// defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a
|
||||||
|
// no-op, as well as disabling other bespoke program consistency checks. By
|
||||||
|
// defining ABSL_OPTION_HARDENED to 1, a select set of checks remain enabled in
|
||||||
|
// release mode. These checks guard against programming errors that may lead to
|
||||||
|
// security vulnerabilities. In release mode, when one of these programming
|
||||||
|
// errors is encountered, the program will immediately abort, possibly without
|
||||||
|
// any attempt at logging.
|
||||||
|
//
|
||||||
|
// The checks enabled by this option are not free; they do incur runtime cost.
|
||||||
|
//
|
||||||
|
// The checks enabled by this option are always active when `NDEBUG` is not
|
||||||
|
// defined, even in the case when ABSL_OPTION_HARDENED is defined to 0. The
|
||||||
|
// checks enabled by this option may abort the program in a different way and
|
||||||
|
// log additional information when `NDEBUG` is not defined.
|
||||||
|
|
||||||
|
#define ABSL_OPTION_HARDENED 0
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_OPTIONS_H_
|
||||||
111
include/absl/base/policy_checks.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: policy_checks.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header enforces a minimum set of policies at build time, such as the
|
||||||
|
// supported compiler and library versions. Unsupported configurations are
|
||||||
|
// reported with `#error`. This enforcement is best effort, so successfully
|
||||||
|
// compiling this header does not guarantee a supported configuration.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_POLICY_CHECKS_H_
|
||||||
|
#define ABSL_BASE_POLICY_CHECKS_H_
|
||||||
|
|
||||||
|
// Included for the __GLIBC_PREREQ macro used below.
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
// Included for the _STLPORT_VERSION macro used below.
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#include <cstddef>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Operating System Check
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(__CYGWIN__)
|
||||||
|
#error "Cygwin is not supported."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Toolchain Check
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// We support MSVC++ 14.0 update 2 and later.
|
||||||
|
// This minimum will go up.
|
||||||
|
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023918 && !defined(__clang__)
|
||||||
|
#error "This package requires Visual Studio 2015 Update 2 or higher."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// We support gcc 4.7 and later.
|
||||||
|
// This minimum will go up.
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
|
||||||
|
#error "This package requires gcc 4.7 or higher."
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later.
|
||||||
|
// This corresponds to Apple Xcode version 4.5.
|
||||||
|
// This minimum will go up.
|
||||||
|
#if defined(__apple_build_version__) && __apple_build_version__ < 4211165
|
||||||
|
#error "This package requires __apple_build_version__ of 4211165 or higher."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// C++ Version Check
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Enforce C++11 as the minimum. Note that Visual Studio has not
|
||||||
|
// advanced __cplusplus despite being good enough for our purposes, so
|
||||||
|
// so we exempt it from the check.
|
||||||
|
#if defined(__cplusplus) && !defined(_MSC_VER)
|
||||||
|
#if __cplusplus < 201103L
|
||||||
|
#error "C++ versions less than C++11 are not supported."
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Standard Library Check
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(_STLPORT_VERSION)
|
||||||
|
#error "STLPort is not supported."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// `char` Size Check
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Abseil currently assumes CHAR_BIT == 8. If you would like to use Abseil on a
|
||||||
|
// platform where this is not the case, please provide us with the details about
|
||||||
|
// your platform so we can consider relaxing this requirement.
|
||||||
|
#if CHAR_BIT != 8
|
||||||
|
#error "Abseil assumes CHAR_BIT == 8."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// `int` Size Check
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Abseil currently assumes that an int is 4 bytes. If you would like to use
|
||||||
|
// Abseil on a platform where this is not the case, please provide us with the
|
||||||
|
// details about your platform so we can consider relaxing this requirement.
|
||||||
|
#if INT_MAX < 2147483647
|
||||||
|
#error "Abseil assumes that int is at least 4 bytes. "
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_POLICY_CHECKS_H_
|
||||||
25
include/absl/base/port.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// This files is a forwarding header for other headers containing various
|
||||||
|
// portability macros and functions.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_PORT_H_
|
||||||
|
#define ABSL_BASE_PORT_H_
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
#include "absl/base/optimization.h"
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_PORT_H_
|
||||||
335
include/absl/base/thread_annotations.h
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: thread_annotations.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header file contains macro definitions for thread safety annotations
|
||||||
|
// that allow developers to document the locking policies of multi-threaded
|
||||||
|
// code. The annotations can also help program analysis tools to identify
|
||||||
|
// potential thread safety issues.
|
||||||
|
//
|
||||||
|
// These annotations are implemented using compiler attributes. Using the macros
|
||||||
|
// defined here instead of raw attributes allow for portability and future
|
||||||
|
// compatibility.
|
||||||
|
//
|
||||||
|
// When referring to mutexes in the arguments of the attributes, you should
|
||||||
|
// use variable names or more complex expressions (e.g. my_object->mutex_)
|
||||||
|
// that evaluate to a concrete mutex object whenever possible. If the mutex
|
||||||
|
// you want to refer to is not in scope, you may use a member pointer
|
||||||
|
// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.
|
||||||
|
|
||||||
|
#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
|
||||||
|
#define ABSL_BASE_THREAD_ANNOTATIONS_H_
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
// TODO(mbonadei): Remove after the backward compatibility period.
|
||||||
|
#include "absl/base/internal/thread_annotations.h" // IWYU pragma: export
|
||||||
|
|
||||||
|
// ABSL_GUARDED_BY()
|
||||||
|
//
|
||||||
|
// Documents if a shared field or global variable needs to be protected by a
|
||||||
|
// mutex. ABSL_GUARDED_BY() allows the user to specify a particular mutex that
|
||||||
|
// should be held when accessing the annotated variable.
|
||||||
|
//
|
||||||
|
// Although this annotation (and ABSL_PT_GUARDED_BY, below) cannot be applied to
|
||||||
|
// local variables, a local variable and its associated mutex can often be
|
||||||
|
// combined into a small class or struct, thereby allowing the annotation.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// class Foo {
|
||||||
|
// Mutex mu_;
|
||||||
|
// int p1_ ABSL_GUARDED_BY(mu_);
|
||||||
|
// ...
|
||||||
|
// };
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(guarded_by)
|
||||||
|
#define ABSL_GUARDED_BY(x) __attribute__((guarded_by(x)))
|
||||||
|
#else
|
||||||
|
#define ABSL_GUARDED_BY(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_PT_GUARDED_BY()
|
||||||
|
//
|
||||||
|
// Documents if the memory location pointed to by a pointer should be guarded
|
||||||
|
// by a mutex when dereferencing the pointer.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// class Foo {
|
||||||
|
// Mutex mu_;
|
||||||
|
// int *p1_ ABSL_PT_GUARDED_BY(mu_);
|
||||||
|
// ...
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// Note that a pointer variable to a shared memory location could itself be a
|
||||||
|
// shared variable.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // `q_`, guarded by `mu1_`, points to a shared memory location that is
|
||||||
|
// // guarded by `mu2_`:
|
||||||
|
// int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(pt_guarded_by)
|
||||||
|
#define ABSL_PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
|
||||||
|
#else
|
||||||
|
#define ABSL_PT_GUARDED_BY(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
|
||||||
|
//
|
||||||
|
// Documents the acquisition order between locks that can be held
|
||||||
|
// simultaneously by a thread. For any two locks that need to be annotated
|
||||||
|
// to establish an acquisition order, only one of them needs the annotation.
|
||||||
|
// (i.e. You don't have to annotate both locks with both ABSL_ACQUIRED_AFTER
|
||||||
|
// and ABSL_ACQUIRED_BEFORE.)
|
||||||
|
//
|
||||||
|
// As with ABSL_GUARDED_BY, this is only applicable to mutexes that are shared
|
||||||
|
// fields or global variables.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// Mutex m1_;
|
||||||
|
// Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(acquired_after)
|
||||||
|
#define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_ACQUIRED_AFTER(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(acquired_before)
|
||||||
|
#define ABSL_ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_ACQUIRED_BEFORE(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
|
||||||
|
//
|
||||||
|
// Documents a function that expects a mutex to be held prior to entry.
|
||||||
|
// The mutex is expected to be held both on entry to, and exit from, the
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
// An exclusive lock allows read-write access to the guarded data member(s), and
|
||||||
|
// only one thread can acquire a lock exclusively at any one time. A shared lock
|
||||||
|
// allows read-only access, and any number of threads can acquire a shared lock
|
||||||
|
// concurrently.
|
||||||
|
//
|
||||||
|
// Generally, non-const methods should be annotated with
|
||||||
|
// ABSL_EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
|
||||||
|
// ABSL_SHARED_LOCKS_REQUIRED.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// Mutex mu1, mu2;
|
||||||
|
// int a ABSL_GUARDED_BY(mu1);
|
||||||
|
// int b ABSL_GUARDED_BY(mu2);
|
||||||
|
//
|
||||||
|
// void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
|
||||||
|
// void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(exclusive_locks_required)
|
||||||
|
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
|
||||||
|
__attribute__((exclusive_locks_required(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(shared_locks_required)
|
||||||
|
#define ABSL_SHARED_LOCKS_REQUIRED(...) \
|
||||||
|
__attribute__((shared_locks_required(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_SHARED_LOCKS_REQUIRED(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_LOCKS_EXCLUDED()
|
||||||
|
//
|
||||||
|
// Documents the locks that cannot be held by callers of this function, as they
|
||||||
|
// might be acquired by this function (Abseil's `Mutex` locks are
|
||||||
|
// non-reentrant).
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(locks_excluded)
|
||||||
|
#define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_LOCKS_EXCLUDED(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_LOCK_RETURNED()
|
||||||
|
//
|
||||||
|
// Documents a function that returns a mutex without acquiring it. For example,
|
||||||
|
// a public getter method that returns a pointer to a private mutex should
|
||||||
|
// be annotated with ABSL_LOCK_RETURNED.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(lock_returned)
|
||||||
|
#define ABSL_LOCK_RETURNED(x) __attribute__((lock_returned(x)))
|
||||||
|
#else
|
||||||
|
#define ABSL_LOCK_RETURNED(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_LOCKABLE
|
||||||
|
//
|
||||||
|
// Documents if a class/type is a lockable type (such as the `Mutex` class).
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(lockable)
|
||||||
|
#define ABSL_LOCKABLE __attribute__((lockable))
|
||||||
|
#else
|
||||||
|
#define ABSL_LOCKABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_SCOPED_LOCKABLE
|
||||||
|
//
|
||||||
|
// Documents if a class does RAII locking (such as the `MutexLock` class).
|
||||||
|
// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
|
||||||
|
// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
|
||||||
|
// arguments; the analysis will assume that the destructor unlocks whatever the
|
||||||
|
// constructor locked.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(scoped_lockable)
|
||||||
|
#define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable))
|
||||||
|
#else
|
||||||
|
#define ABSL_SCOPED_LOCKABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_EXCLUSIVE_LOCK_FUNCTION()
|
||||||
|
//
|
||||||
|
// Documents functions that acquire a lock in the body of a function, and do
|
||||||
|
// not release it.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(exclusive_lock_function)
|
||||||
|
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
|
||||||
|
__attribute__((exclusive_lock_function(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_SHARED_LOCK_FUNCTION()
|
||||||
|
//
|
||||||
|
// Documents functions that acquire a shared (reader) lock in the body of a
|
||||||
|
// function, and do not release it.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(shared_lock_function)
|
||||||
|
#define ABSL_SHARED_LOCK_FUNCTION(...) \
|
||||||
|
__attribute__((shared_lock_function(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_SHARED_LOCK_FUNCTION(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_UNLOCK_FUNCTION()
|
||||||
|
//
|
||||||
|
// Documents functions that expect a lock to be held on entry to the function,
|
||||||
|
// and release it in the body of the function.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(unlock_function)
|
||||||
|
#define ABSL_UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_UNLOCK_FUNCTION(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
|
||||||
|
//
|
||||||
|
// Documents functions that try to acquire a lock, and return success or failure
|
||||||
|
// (or a non-boolean value that can be interpreted as a boolean).
|
||||||
|
// The first argument should be `true` for functions that return `true` on
|
||||||
|
// success, or `false` for functions that return `false` on success. The second
|
||||||
|
// argument specifies the mutex that is locked on success. If unspecified, this
|
||||||
|
// mutex is assumed to be `this`.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(exclusive_trylock_function)
|
||||||
|
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
|
||||||
|
__attribute__((exclusive_trylock_function(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(shared_trylock_function)
|
||||||
|
#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
|
||||||
|
__attribute__((shared_trylock_function(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_SHARED_TRYLOCK_FUNCTION(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
|
||||||
|
//
|
||||||
|
// Documents functions that dynamically check to see if a lock is held, and fail
|
||||||
|
// if it is not held.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(assert_exclusive_lock)
|
||||||
|
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
|
||||||
|
__attribute__((assert_exclusive_lock(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(assert_shared_lock)
|
||||||
|
#define ABSL_ASSERT_SHARED_LOCK(...) \
|
||||||
|
__attribute__((assert_shared_lock(__VA_ARGS__)))
|
||||||
|
#else
|
||||||
|
#define ABSL_ASSERT_SHARED_LOCK(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||||
|
//
|
||||||
|
// Turns off thread safety checking within the body of a particular function.
|
||||||
|
// This annotation is used to mark functions that are known to be correct, but
|
||||||
|
// the locking behavior is more complicated than the analyzer can handle.
|
||||||
|
#if ABSL_HAVE_ATTRIBUTE(no_thread_safety_analysis)
|
||||||
|
#define ABSL_NO_THREAD_SAFETY_ANALYSIS \
|
||||||
|
__attribute__((no_thread_safety_analysis))
|
||||||
|
#else
|
||||||
|
#define ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Tool-Supplied Annotations
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ABSL_TS_UNCHECKED should be placed around lock expressions that are not valid
|
||||||
|
// C++ syntax, but which are present for documentation purposes. These
|
||||||
|
// annotations will be ignored by the analysis.
|
||||||
|
#define ABSL_TS_UNCHECKED(x) ""
|
||||||
|
|
||||||
|
// ABSL_TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
|
||||||
|
// It is used by automated tools to mark and disable invalid expressions.
|
||||||
|
// The annotation should either be fixed, or changed to ABSL_TS_UNCHECKED.
|
||||||
|
#define ABSL_TS_FIXME(x) ""
|
||||||
|
|
||||||
|
// Like ABSL_NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body
|
||||||
|
// of a particular function. However, this attribute is used to mark functions
|
||||||
|
// that are incorrect and need to be fixed. It is used by automated tools to
|
||||||
|
// avoid breaking the build when the analysis is updated.
|
||||||
|
// Code owners are expected to eventually fix the routine.
|
||||||
|
#define ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||||
|
|
||||||
|
// Similar to ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a
|
||||||
|
// ABSL_GUARDED_BY annotation that needs to be fixed, because it is producing
|
||||||
|
// thread safety warning. It disables the ABSL_GUARDED_BY.
|
||||||
|
#define ABSL_GUARDED_BY_FIXME(x)
|
||||||
|
|
||||||
|
// Disables warnings for a single read operation. This can be used to avoid
|
||||||
|
// warnings when it is known that the read is not actually involved in a race,
|
||||||
|
// but the compiler cannot confirm that.
|
||||||
|
#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::ts_unchecked_read(x)
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace base_internal {
|
||||||
|
|
||||||
|
// Takes a reference to a guarded data member, and returns an unguarded
|
||||||
|
// reference.
|
||||||
|
// Do not use this function directly, use ABSL_TS_UNCHECKED_READ instead.
|
||||||
|
template <typename T>
|
||||||
|
inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T& ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_BASE_THREAD_ANNOTATIONS_H_
|
||||||
140
include/absl/cleanup/cleanup.h
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
// Copyright 2021 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: cleanup.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// `absl::Cleanup` implements the scope guard idiom, invoking the contained
|
||||||
|
// callback's `operator()() &&` on scope exit.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// absl::Status CopyGoodData(const char* source_path, const char* sink_path) {
|
||||||
|
// FILE* source_file = fopen(source_path, "r");
|
||||||
|
// if (source_file == nullptr) {
|
||||||
|
// return absl::NotFoundError("No source file"); // No cleanups execute
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // C++17 style cleanup using class template argument deduction
|
||||||
|
// absl::Cleanup source_closer = [source_file] { fclose(source_file); };
|
||||||
|
//
|
||||||
|
// FILE* sink_file = fopen(sink_path, "w");
|
||||||
|
// if (sink_file == nullptr) {
|
||||||
|
// return absl::NotFoundError("No sink file"); // First cleanup executes
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // C++11 style cleanup using the factory function
|
||||||
|
// auto sink_closer = absl::MakeCleanup([sink_file] { fclose(sink_file); });
|
||||||
|
//
|
||||||
|
// Data data;
|
||||||
|
// while (ReadData(source_file, &data)) {
|
||||||
|
// if (!data.IsGood()) {
|
||||||
|
// absl::Status result = absl::FailedPreconditionError("Read bad data");
|
||||||
|
// return result; // Both cleanups execute
|
||||||
|
// }
|
||||||
|
// SaveData(sink_file, &data);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return absl::OkStatus(); // Both cleanups execute
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// Methods:
|
||||||
|
//
|
||||||
|
// `std::move(cleanup).Cancel()` will prevent the callback from executing.
|
||||||
|
//
|
||||||
|
// `std::move(cleanup).Invoke()` will execute the callback early, before
|
||||||
|
// destruction, and prevent the callback from executing in the destructor.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// `absl::Cleanup` is not an interface type. It is only intended to be used
|
||||||
|
// within the body of a function. It is not a value type and instead models a
|
||||||
|
// control flow construct. Check out `defer` in Golang for something similar.
|
||||||
|
|
||||||
|
#ifndef ABSL_CLEANUP_CLEANUP_H_
|
||||||
|
#define ABSL_CLEANUP_CLEANUP_H_
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/cleanup/internal/cleanup.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
template <typename Arg, typename Callback = void()>
|
||||||
|
class ABSL_MUST_USE_RESULT Cleanup final {
|
||||||
|
static_assert(cleanup_internal::WasDeduced<Arg>(),
|
||||||
|
"Explicit template parameters are not supported.");
|
||||||
|
|
||||||
|
static_assert(cleanup_internal::ReturnsVoid<Callback>(),
|
||||||
|
"Callbacks that return values are not supported.");
|
||||||
|
|
||||||
|
public:
|
||||||
|
Cleanup(Callback callback) : storage_(std::move(callback)) {} // NOLINT
|
||||||
|
|
||||||
|
Cleanup(Cleanup&& other) = default;
|
||||||
|
|
||||||
|
void Cancel() && {
|
||||||
|
ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
|
||||||
|
storage_.DestroyCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Invoke() && {
|
||||||
|
ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
|
||||||
|
storage_.InvokeCallback();
|
||||||
|
storage_.DestroyCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Cleanup() {
|
||||||
|
if (storage_.IsCallbackEngaged()) {
|
||||||
|
storage_.InvokeCallback();
|
||||||
|
storage_.DestroyCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
cleanup_internal::Storage<Callback> storage_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// `absl::Cleanup c = /* callback */;`
|
||||||
|
//
|
||||||
|
// C++17 type deduction API for creating an instance of `absl::Cleanup`
|
||||||
|
#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
|
||||||
|
template <typename Callback>
|
||||||
|
Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>;
|
||||||
|
#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
|
||||||
|
|
||||||
|
// `auto c = absl::MakeCleanup(/* callback */);`
|
||||||
|
//
|
||||||
|
// C++11 type deduction API for creating an instance of `absl::Cleanup`
|
||||||
|
template <typename... Args, typename Callback>
|
||||||
|
absl::Cleanup<cleanup_internal::Tag, Callback> MakeCleanup(Callback callback) {
|
||||||
|
static_assert(cleanup_internal::WasDeduced<cleanup_internal::Tag, Args...>(),
|
||||||
|
"Explicit template parameters are not supported.");
|
||||||
|
|
||||||
|
static_assert(cleanup_internal::ReturnsVoid<Callback>(),
|
||||||
|
"Callbacks that return values are not supported.");
|
||||||
|
|
||||||
|
return {std::move(callback)};
|
||||||
|
}
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_CLEANUP_CLEANUP_H_
|
||||||
100
include/absl/cleanup/internal/cleanup.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// Copyright 2021 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_CLEANUP_INTERNAL_CLEANUP_H_
|
||||||
|
#define ABSL_CLEANUP_INTERNAL_CLEANUP_H_
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "absl/base/internal/invoke.h"
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/base/thread_annotations.h"
|
||||||
|
#include "absl/utility/utility.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace cleanup_internal {
|
||||||
|
|
||||||
|
struct Tag {};
|
||||||
|
|
||||||
|
template <typename Arg, typename... Args>
|
||||||
|
constexpr bool WasDeduced() {
|
||||||
|
return (std::is_same<cleanup_internal::Tag, Arg>::value) &&
|
||||||
|
(sizeof...(Args) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Callback>
|
||||||
|
constexpr bool ReturnsVoid() {
|
||||||
|
return (std::is_same<base_internal::invoke_result_t<Callback>, void>::value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Callback>
|
||||||
|
class Storage {
|
||||||
|
public:
|
||||||
|
Storage() = delete;
|
||||||
|
|
||||||
|
explicit Storage(Callback callback) {
|
||||||
|
// Placement-new into a character buffer is used for eager destruction when
|
||||||
|
// the cleanup is invoked or cancelled. To ensure this optimizes well, the
|
||||||
|
// behavior is implemented locally instead of using an absl::optional.
|
||||||
|
::new (GetCallbackBuffer()) Callback(std::move(callback));
|
||||||
|
is_callback_engaged_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Storage(Storage&& other) {
|
||||||
|
ABSL_HARDENING_ASSERT(other.IsCallbackEngaged());
|
||||||
|
|
||||||
|
::new (GetCallbackBuffer()) Callback(std::move(other.GetCallback()));
|
||||||
|
is_callback_engaged_ = true;
|
||||||
|
|
||||||
|
other.DestroyCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
Storage(const Storage& other) = delete;
|
||||||
|
|
||||||
|
Storage& operator=(Storage&& other) = delete;
|
||||||
|
|
||||||
|
Storage& operator=(const Storage& other) = delete;
|
||||||
|
|
||||||
|
void* GetCallbackBuffer() { return static_cast<void*>(+callback_buffer_); }
|
||||||
|
|
||||||
|
Callback& GetCallback() {
|
||||||
|
return *reinterpret_cast<Callback*>(GetCallbackBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsCallbackEngaged() const { return is_callback_engaged_; }
|
||||||
|
|
||||||
|
void DestroyCallback() {
|
||||||
|
is_callback_engaged_ = false;
|
||||||
|
GetCallback().~Callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvokeCallback() ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||||
|
std::move(GetCallback())();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool is_callback_engaged_;
|
||||||
|
alignas(Callback) char callback_buffer_[sizeof(Callback)];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cleanup_internal
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_CLEANUP_INTERNAL_CLEANUP_H_
|
||||||
851
include/absl/container/btree_map.h
Normal file
@ -0,0 +1,851 @@
|
|||||||
|
// Copyright 2018 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: btree_map.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header file defines B-tree maps: sorted associative containers mapping
|
||||||
|
// keys to values.
|
||||||
|
//
|
||||||
|
// * `absl::btree_map<>`
|
||||||
|
// * `absl::btree_multimap<>`
|
||||||
|
//
|
||||||
|
// These B-tree types are similar to the corresponding types in the STL
|
||||||
|
// (`std::map` and `std::multimap`) and generally conform to the STL interfaces
|
||||||
|
// of those types. However, because they are implemented using B-trees, they
|
||||||
|
// are more efficient in most situations.
|
||||||
|
//
|
||||||
|
// Unlike `std::map` and `std::multimap`, which are commonly implemented using
|
||||||
|
// red-black tree nodes, B-tree maps use more generic B-tree nodes able to hold
|
||||||
|
// multiple values per node. Holding multiple values per node often makes
|
||||||
|
// B-tree maps perform better than their `std::map` counterparts, because
|
||||||
|
// multiple entries can be checked within the same cache hit.
|
||||||
|
//
|
||||||
|
// However, these types should not be considered drop-in replacements for
|
||||||
|
// `std::map` and `std::multimap` as there are some API differences, which are
|
||||||
|
// noted in this header file. The most consequential differences with respect to
|
||||||
|
// migrating to b-tree from the STL types are listed in the next paragraph.
|
||||||
|
// Other API differences are minor.
|
||||||
|
//
|
||||||
|
// Importantly, insertions and deletions may invalidate outstanding iterators,
|
||||||
|
// pointers, and references to elements. Such invalidations are typically only
|
||||||
|
// an issue if insertion and deletion operations are interleaved with the use of
|
||||||
|
// more than one iterator, pointer, or reference simultaneously. For this
|
||||||
|
// reason, `insert()` and `erase()` return a valid iterator at the current
|
||||||
|
// position. Another important difference is that key-types must be
|
||||||
|
// copy-constructible.
|
||||||
|
|
||||||
|
#ifndef ABSL_CONTAINER_BTREE_MAP_H_
|
||||||
|
#define ABSL_CONTAINER_BTREE_MAP_H_
|
||||||
|
|
||||||
|
#include "absl/container/internal/btree.h" // IWYU pragma: export
|
||||||
|
#include "absl/container/internal/btree_container.h" // IWYU pragma: export
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace container_internal {
|
||||||
|
|
||||||
|
template <typename Key, typename Data, typename Compare, typename Alloc,
|
||||||
|
int TargetNodeSize, bool IsMulti>
|
||||||
|
struct map_params;
|
||||||
|
|
||||||
|
} // namespace container_internal
|
||||||
|
|
||||||
|
// absl::btree_map<>
|
||||||
|
//
|
||||||
|
// An `absl::btree_map<K, V>` is an ordered associative container of
|
||||||
|
// unique keys and associated values designed to be a more efficient replacement
|
||||||
|
// for `std::map` (in most cases).
|
||||||
|
//
|
||||||
|
// Keys are sorted using an (optional) comparison function, which defaults to
|
||||||
|
// `std::less<K>`.
|
||||||
|
//
|
||||||
|
// An `absl::btree_map<K, V>` uses a default allocator of
|
||||||
|
// `std::allocator<std::pair<const K, V>>` to allocate (and deallocate)
|
||||||
|
// nodes, and construct and destruct values within those nodes. You may
|
||||||
|
// instead specify a custom allocator `A` (which in turn requires specifying a
|
||||||
|
// custom comparator `C`) as in `absl::btree_map<K, V, C, A>`.
|
||||||
|
//
|
||||||
|
template <typename Key, typename Value, typename Compare = std::less<Key>,
|
||||||
|
typename Alloc = std::allocator<std::pair<const Key, Value>>>
|
||||||
|
class btree_map
|
||||||
|
: public container_internal::btree_map_container<
|
||||||
|
container_internal::btree<container_internal::map_params<
|
||||||
|
Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
|
||||||
|
/*IsMulti=*/false>>> {
|
||||||
|
using Base = typename btree_map::btree_map_container;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors and Assignment Operators
|
||||||
|
//
|
||||||
|
// A `btree_map` supports the same overload set as `std::map`
|
||||||
|
// for construction and assignment:
|
||||||
|
//
|
||||||
|
// * Default constructor
|
||||||
|
//
|
||||||
|
// absl::btree_map<int, std::string> map1;
|
||||||
|
//
|
||||||
|
// * Initializer List constructor
|
||||||
|
//
|
||||||
|
// absl::btree_map<int, std::string> map2 =
|
||||||
|
// {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
|
||||||
|
//
|
||||||
|
// * Copy constructor
|
||||||
|
//
|
||||||
|
// absl::btree_map<int, std::string> map3(map2);
|
||||||
|
//
|
||||||
|
// * Copy assignment operator
|
||||||
|
//
|
||||||
|
// absl::btree_map<int, std::string> map4;
|
||||||
|
// map4 = map3;
|
||||||
|
//
|
||||||
|
// * Move constructor
|
||||||
|
//
|
||||||
|
// // Move is guaranteed efficient
|
||||||
|
// absl::btree_map<int, std::string> map5(std::move(map4));
|
||||||
|
//
|
||||||
|
// * Move assignment operator
|
||||||
|
//
|
||||||
|
// // May be efficient if allocators are compatible
|
||||||
|
// absl::btree_map<int, std::string> map6;
|
||||||
|
// map6 = std::move(map5);
|
||||||
|
//
|
||||||
|
// * Range constructor
|
||||||
|
//
|
||||||
|
// std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
|
||||||
|
// absl::btree_map<int, std::string> map7(v.begin(), v.end());
|
||||||
|
btree_map() {}
|
||||||
|
using Base::Base;
|
||||||
|
|
||||||
|
// btree_map::begin()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the beginning of the `btree_map`.
|
||||||
|
using Base::begin;
|
||||||
|
|
||||||
|
// btree_map::cbegin()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the beginning of the `btree_map`.
|
||||||
|
using Base::cbegin;
|
||||||
|
|
||||||
|
// btree_map::end()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the end of the `btree_map`.
|
||||||
|
using Base::end;
|
||||||
|
|
||||||
|
// btree_map::cend()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the end of the `btree_map`.
|
||||||
|
using Base::cend;
|
||||||
|
|
||||||
|
// btree_map::empty()
|
||||||
|
//
|
||||||
|
// Returns whether or not the `btree_map` is empty.
|
||||||
|
using Base::empty;
|
||||||
|
|
||||||
|
// btree_map::max_size()
|
||||||
|
//
|
||||||
|
// Returns the largest theoretical possible number of elements within a
|
||||||
|
// `btree_map` under current memory constraints. This value can be thought
|
||||||
|
// of as the largest value of `std::distance(begin(), end())` for a
|
||||||
|
// `btree_map<Key, T>`.
|
||||||
|
using Base::max_size;
|
||||||
|
|
||||||
|
// btree_map::size()
|
||||||
|
//
|
||||||
|
// Returns the number of elements currently within the `btree_map`.
|
||||||
|
using Base::size;
|
||||||
|
|
||||||
|
// btree_map::clear()
|
||||||
|
//
|
||||||
|
// Removes all elements from the `btree_map`. Invalidates any references,
|
||||||
|
// pointers, or iterators referring to contained elements.
|
||||||
|
using Base::clear;
|
||||||
|
|
||||||
|
// btree_map::erase()
|
||||||
|
//
|
||||||
|
// Erases elements within the `btree_map`. If an erase occurs, any references,
|
||||||
|
// pointers, or iterators are invalidated.
|
||||||
|
// Overloads are listed below.
|
||||||
|
//
|
||||||
|
// iterator erase(iterator position):
|
||||||
|
// iterator erase(const_iterator position):
|
||||||
|
//
|
||||||
|
// Erases the element at `position` of the `btree_map`, returning
|
||||||
|
// the iterator pointing to the element after the one that was erased
|
||||||
|
// (or end() if none exists).
|
||||||
|
//
|
||||||
|
// iterator erase(const_iterator first, const_iterator last):
|
||||||
|
//
|
||||||
|
// Erases the elements in the open interval [`first`, `last`), returning
|
||||||
|
// the iterator pointing to the element after the interval that was erased
|
||||||
|
// (or end() if none exists).
|
||||||
|
//
|
||||||
|
// template <typename K> size_type erase(const K& key):
|
||||||
|
//
|
||||||
|
// Erases the element with the matching key, if it exists, returning the
|
||||||
|
// number of elements erased (0 or 1).
|
||||||
|
using Base::erase;
|
||||||
|
|
||||||
|
// btree_map::insert()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value into the `btree_map`,
|
||||||
|
// returning an iterator pointing to the newly inserted element, provided that
|
||||||
|
// an element with the given key does not already exist. If an insertion
|
||||||
|
// occurs, any references, pointers, or iterators are invalidated.
|
||||||
|
// Overloads are listed below.
|
||||||
|
//
|
||||||
|
// std::pair<iterator,bool> insert(const value_type& value):
|
||||||
|
//
|
||||||
|
// Inserts a value into the `btree_map`. Returns a pair consisting of an
|
||||||
|
// iterator to the inserted element (or to the element that prevented the
|
||||||
|
// insertion) and a bool denoting whether the insertion took place.
|
||||||
|
//
|
||||||
|
// std::pair<iterator,bool> insert(value_type&& value):
|
||||||
|
//
|
||||||
|
// Inserts a moveable value into the `btree_map`. Returns a pair
|
||||||
|
// consisting of an iterator to the inserted element (or to the element that
|
||||||
|
// prevented the insertion) and a bool denoting whether the insertion took
|
||||||
|
// place.
|
||||||
|
//
|
||||||
|
// iterator insert(const_iterator hint, const value_type& value):
|
||||||
|
// iterator insert(const_iterator hint, value_type&& value):
|
||||||
|
//
|
||||||
|
// Inserts a value, using the position of `hint` as a non-binding suggestion
|
||||||
|
// for where to begin the insertion search. Returns an iterator to the
|
||||||
|
// inserted element, or to the existing element that prevented the
|
||||||
|
// insertion.
|
||||||
|
//
|
||||||
|
// void insert(InputIterator first, InputIterator last):
|
||||||
|
//
|
||||||
|
// Inserts a range of values [`first`, `last`).
|
||||||
|
//
|
||||||
|
// void insert(std::initializer_list<init_type> ilist):
|
||||||
|
//
|
||||||
|
// Inserts the elements within the initializer list `ilist`.
|
||||||
|
using Base::insert;
|
||||||
|
|
||||||
|
// btree_map::insert_or_assign()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value into the `btree_map` provided
|
||||||
|
// that a value with the given key does not already exist, or replaces the
|
||||||
|
// corresponding mapped type with the forwarded `obj` argument if a key for
|
||||||
|
// that value already exists, returning an iterator pointing to the newly
|
||||||
|
// inserted element. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj):
|
||||||
|
// pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj):
|
||||||
|
//
|
||||||
|
// Inserts/Assigns (or moves) the element of the specified key into the
|
||||||
|
// `btree_map`. If the returned bool is true, insertion took place, and if
|
||||||
|
// it's false, assignment took place.
|
||||||
|
//
|
||||||
|
// iterator insert_or_assign(const_iterator hint,
|
||||||
|
// const key_type& k, M&& obj):
|
||||||
|
// iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj):
|
||||||
|
//
|
||||||
|
// Inserts/Assigns (or moves) the element of the specified key into the
|
||||||
|
// `btree_map` using the position of `hint` as a non-binding suggestion
|
||||||
|
// for where to begin the insertion search.
|
||||||
|
using Base::insert_or_assign;
|
||||||
|
|
||||||
|
// btree_map::emplace()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `btree_map`, provided that no element with the given key
|
||||||
|
// already exists.
|
||||||
|
//
|
||||||
|
// The element may be constructed even if there already is an element with the
|
||||||
|
// key in the container, in which case the newly constructed element will be
|
||||||
|
// destroyed immediately. Prefer `try_emplace()` unless your key is not
|
||||||
|
// copyable or moveable.
|
||||||
|
//
|
||||||
|
// If an insertion occurs, any references, pointers, or iterators are
|
||||||
|
// invalidated.
|
||||||
|
using Base::emplace;
|
||||||
|
|
||||||
|
// btree_map::emplace_hint()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `btree_map`, using the position of `hint` as a non-binding
|
||||||
|
// suggestion for where to begin the insertion search, and only inserts
|
||||||
|
// provided that no element with the given key already exists.
|
||||||
|
//
|
||||||
|
// The element may be constructed even if there already is an element with the
|
||||||
|
// key in the container, in which case the newly constructed element will be
|
||||||
|
// destroyed immediately. Prefer `try_emplace()` unless your key is not
|
||||||
|
// copyable or moveable.
|
||||||
|
//
|
||||||
|
// If an insertion occurs, any references, pointers, or iterators are
|
||||||
|
// invalidated.
|
||||||
|
using Base::emplace_hint;
|
||||||
|
|
||||||
|
// btree_map::try_emplace()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `btree_map`, provided that no element with the given key
|
||||||
|
// already exists. Unlike `emplace()`, if an element with the given key
|
||||||
|
// already exists, we guarantee that no element is constructed.
|
||||||
|
//
|
||||||
|
// If an insertion occurs, any references, pointers, or iterators are
|
||||||
|
// invalidated.
|
||||||
|
//
|
||||||
|
// Overloads are listed below.
|
||||||
|
//
|
||||||
|
// std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args):
|
||||||
|
// std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args):
|
||||||
|
//
|
||||||
|
// Inserts (via copy or move) the element of the specified key into the
|
||||||
|
// `btree_map`.
|
||||||
|
//
|
||||||
|
// iterator try_emplace(const_iterator hint,
|
||||||
|
// const key_type& k, Args&&... args):
|
||||||
|
// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args):
|
||||||
|
//
|
||||||
|
// Inserts (via copy or move) the element of the specified key into the
|
||||||
|
// `btree_map` using the position of `hint` as a non-binding suggestion
|
||||||
|
// for where to begin the insertion search.
|
||||||
|
using Base::try_emplace;
|
||||||
|
|
||||||
|
// btree_map::extract()
|
||||||
|
//
|
||||||
|
// Extracts the indicated element, erasing it in the process, and returns it
|
||||||
|
// as a C++17-compatible node handle. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// node_type extract(const_iterator position):
|
||||||
|
//
|
||||||
|
// Extracts the element at the indicated position and returns a node handle
|
||||||
|
// owning that extracted data.
|
||||||
|
//
|
||||||
|
// template <typename K> node_type extract(const K& k):
|
||||||
|
//
|
||||||
|
// Extracts the element with the key matching the passed key value and
|
||||||
|
// returns a node handle owning that extracted data. If the `btree_map`
|
||||||
|
// does not contain an element with a matching key, this function returns an
|
||||||
|
// empty node handle.
|
||||||
|
//
|
||||||
|
// NOTE: when compiled in an earlier version of C++ than C++17,
|
||||||
|
// `node_type::key()` returns a const reference to the key instead of a
|
||||||
|
// mutable reference. We cannot safely return a mutable reference without
|
||||||
|
// std::launder (which is not available before C++17).
|
||||||
|
//
|
||||||
|
// NOTE: In this context, `node_type` refers to the C++17 concept of a
|
||||||
|
// move-only type that owns and provides access to the elements in associative
|
||||||
|
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
|
||||||
|
// It does NOT refer to the data layout of the underlying btree.
|
||||||
|
using Base::extract;
|
||||||
|
|
||||||
|
// btree_map::merge()
|
||||||
|
//
|
||||||
|
// Extracts elements from a given `source` btree_map into this
|
||||||
|
// `btree_map`. If the destination `btree_map` already contains an
|
||||||
|
// element with an equivalent key, that element is not extracted.
|
||||||
|
using Base::merge;
|
||||||
|
|
||||||
|
// btree_map::swap(btree_map& other)
|
||||||
|
//
|
||||||
|
// Exchanges the contents of this `btree_map` with those of the `other`
|
||||||
|
// btree_map, avoiding invocation of any move, copy, or swap operations on
|
||||||
|
// individual elements.
|
||||||
|
//
|
||||||
|
// All iterators and references on the `btree_map` remain valid, excepting
|
||||||
|
// for the past-the-end iterator, which is invalidated.
|
||||||
|
using Base::swap;
|
||||||
|
|
||||||
|
// btree_map::at()
|
||||||
|
//
|
||||||
|
// Returns a reference to the mapped value of the element with key equivalent
|
||||||
|
// to the passed key.
|
||||||
|
using Base::at;
|
||||||
|
|
||||||
|
// btree_map::contains()
|
||||||
|
//
|
||||||
|
// template <typename K> bool contains(const K& key) const:
|
||||||
|
//
|
||||||
|
// Determines whether an element comparing equal to the given `key` exists
|
||||||
|
// within the `btree_map`, returning `true` if so or `false` otherwise.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::contains;
|
||||||
|
|
||||||
|
// btree_map::count()
|
||||||
|
//
|
||||||
|
// template <typename K> size_type count(const K& key) const:
|
||||||
|
//
|
||||||
|
// Returns the number of elements comparing equal to the given `key` within
|
||||||
|
// the `btree_map`. Note that this function will return either `1` or `0`
|
||||||
|
// since duplicate elements are not allowed within a `btree_map`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::count;
|
||||||
|
|
||||||
|
// btree_map::equal_range()
|
||||||
|
//
|
||||||
|
// Returns a half-open range [first, last), defined by a `std::pair` of two
|
||||||
|
// iterators, containing all elements with the passed key in the `btree_map`.
|
||||||
|
using Base::equal_range;
|
||||||
|
|
||||||
|
// btree_map::find()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator find(const K& key):
|
||||||
|
// template <typename K> const_iterator find(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds an element with the passed `key` within the `btree_map`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::find;
|
||||||
|
|
||||||
|
// btree_map::lower_bound()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator lower_bound(const K& key):
|
||||||
|
// template <typename K> const_iterator lower_bound(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds the first element with a key that is not less than `key` within the
|
||||||
|
// `btree_map`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::lower_bound;
|
||||||
|
|
||||||
|
// btree_map::upper_bound()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator upper_bound(const K& key):
|
||||||
|
// template <typename K> const_iterator upper_bound(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds the first element with a key that is greater than `key` within the
|
||||||
|
// `btree_map`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::upper_bound;
|
||||||
|
|
||||||
|
// btree_map::operator[]()
|
||||||
|
//
|
||||||
|
// Returns a reference to the value mapped to the passed key within the
|
||||||
|
// `btree_map`, performing an `insert()` if the key does not already
|
||||||
|
// exist.
|
||||||
|
//
|
||||||
|
// If an insertion occurs, any references, pointers, or iterators are
|
||||||
|
// invalidated. Otherwise iterators are not affected and references are not
|
||||||
|
// invalidated. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// T& operator[](key_type&& key):
|
||||||
|
// T& operator[](const key_type& key):
|
||||||
|
//
|
||||||
|
// Inserts a value_type object constructed in-place if the element with the
|
||||||
|
// given key does not exist.
|
||||||
|
using Base::operator[];
|
||||||
|
|
||||||
|
// btree_map::get_allocator()
|
||||||
|
//
|
||||||
|
// Returns the allocator function associated with this `btree_map`.
|
||||||
|
using Base::get_allocator;
|
||||||
|
|
||||||
|
// btree_map::key_comp();
|
||||||
|
//
|
||||||
|
// Returns the key comparator associated with this `btree_map`.
|
||||||
|
using Base::key_comp;
|
||||||
|
|
||||||
|
// btree_map::value_comp();
|
||||||
|
//
|
||||||
|
// Returns the value comparator associated with this `btree_map`.
|
||||||
|
using Base::value_comp;
|
||||||
|
};
|
||||||
|
|
||||||
|
// absl::swap(absl::btree_map<>, absl::btree_map<>)
|
||||||
|
//
|
||||||
|
// Swaps the contents of two `absl::btree_map` containers.
|
||||||
|
template <typename K, typename V, typename C, typename A>
|
||||||
|
void swap(btree_map<K, V, C, A> &x, btree_map<K, V, C, A> &y) {
|
||||||
|
return x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// absl::erase_if(absl::btree_map<>, Pred)
|
||||||
|
//
|
||||||
|
// Erases all elements that satisfy the predicate pred from the container.
|
||||||
|
// Returns the number of erased elements.
|
||||||
|
template <typename K, typename V, typename C, typename A, typename Pred>
|
||||||
|
typename btree_map<K, V, C, A>::size_type erase_if(
|
||||||
|
btree_map<K, V, C, A> &map, Pred pred) {
|
||||||
|
return container_internal::btree_access::erase_if(map, std::move(pred));
|
||||||
|
}
|
||||||
|
|
||||||
|
// absl::btree_multimap
|
||||||
|
//
|
||||||
|
// An `absl::btree_multimap<K, V>` is an ordered associative container of
|
||||||
|
// keys and associated values designed to be a more efficient replacement for
|
||||||
|
// `std::multimap` (in most cases). Unlike `absl::btree_map`, a B-tree multimap
|
||||||
|
// allows multiple elements with equivalent keys.
|
||||||
|
//
|
||||||
|
// Keys are sorted using an (optional) comparison function, which defaults to
|
||||||
|
// `std::less<K>`.
|
||||||
|
//
|
||||||
|
// An `absl::btree_multimap<K, V>` uses a default allocator of
|
||||||
|
// `std::allocator<std::pair<const K, V>>` to allocate (and deallocate)
|
||||||
|
// nodes, and construct and destruct values within those nodes. You may
|
||||||
|
// instead specify a custom allocator `A` (which in turn requires specifying a
|
||||||
|
// custom comparator `C`) as in `absl::btree_multimap<K, V, C, A>`.
|
||||||
|
//
|
||||||
|
template <typename Key, typename Value, typename Compare = std::less<Key>,
|
||||||
|
typename Alloc = std::allocator<std::pair<const Key, Value>>>
|
||||||
|
class btree_multimap
|
||||||
|
: public container_internal::btree_multimap_container<
|
||||||
|
container_internal::btree<container_internal::map_params<
|
||||||
|
Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
|
||||||
|
/*IsMulti=*/true>>> {
|
||||||
|
using Base = typename btree_multimap::btree_multimap_container;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors and Assignment Operators
|
||||||
|
//
|
||||||
|
// A `btree_multimap` supports the same overload set as `std::multimap`
|
||||||
|
// for construction and assignment:
|
||||||
|
//
|
||||||
|
// * Default constructor
|
||||||
|
//
|
||||||
|
// absl::btree_multimap<int, std::string> map1;
|
||||||
|
//
|
||||||
|
// * Initializer List constructor
|
||||||
|
//
|
||||||
|
// absl::btree_multimap<int, std::string> map2 =
|
||||||
|
// {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
|
||||||
|
//
|
||||||
|
// * Copy constructor
|
||||||
|
//
|
||||||
|
// absl::btree_multimap<int, std::string> map3(map2);
|
||||||
|
//
|
||||||
|
// * Copy assignment operator
|
||||||
|
//
|
||||||
|
// absl::btree_multimap<int, std::string> map4;
|
||||||
|
// map4 = map3;
|
||||||
|
//
|
||||||
|
// * Move constructor
|
||||||
|
//
|
||||||
|
// // Move is guaranteed efficient
|
||||||
|
// absl::btree_multimap<int, std::string> map5(std::move(map4));
|
||||||
|
//
|
||||||
|
// * Move assignment operator
|
||||||
|
//
|
||||||
|
// // May be efficient if allocators are compatible
|
||||||
|
// absl::btree_multimap<int, std::string> map6;
|
||||||
|
// map6 = std::move(map5);
|
||||||
|
//
|
||||||
|
// * Range constructor
|
||||||
|
//
|
||||||
|
// std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
|
||||||
|
// absl::btree_multimap<int, std::string> map7(v.begin(), v.end());
|
||||||
|
btree_multimap() {}
|
||||||
|
using Base::Base;
|
||||||
|
|
||||||
|
// btree_multimap::begin()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the beginning of the `btree_multimap`.
|
||||||
|
using Base::begin;
|
||||||
|
|
||||||
|
// btree_multimap::cbegin()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the beginning of the `btree_multimap`.
|
||||||
|
using Base::cbegin;
|
||||||
|
|
||||||
|
// btree_multimap::end()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the end of the `btree_multimap`.
|
||||||
|
using Base::end;
|
||||||
|
|
||||||
|
// btree_multimap::cend()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the end of the `btree_multimap`.
|
||||||
|
using Base::cend;
|
||||||
|
|
||||||
|
// btree_multimap::empty()
|
||||||
|
//
|
||||||
|
// Returns whether or not the `btree_multimap` is empty.
|
||||||
|
using Base::empty;
|
||||||
|
|
||||||
|
// btree_multimap::max_size()
|
||||||
|
//
|
||||||
|
// Returns the largest theoretical possible number of elements within a
|
||||||
|
// `btree_multimap` under current memory constraints. This value can be
|
||||||
|
// thought of as the largest value of `std::distance(begin(), end())` for a
|
||||||
|
// `btree_multimap<Key, T>`.
|
||||||
|
using Base::max_size;
|
||||||
|
|
||||||
|
// btree_multimap::size()
|
||||||
|
//
|
||||||
|
// Returns the number of elements currently within the `btree_multimap`.
|
||||||
|
using Base::size;
|
||||||
|
|
||||||
|
// btree_multimap::clear()
|
||||||
|
//
|
||||||
|
// Removes all elements from the `btree_multimap`. Invalidates any references,
|
||||||
|
// pointers, or iterators referring to contained elements.
|
||||||
|
using Base::clear;
|
||||||
|
|
||||||
|
// btree_multimap::erase()
|
||||||
|
//
|
||||||
|
// Erases elements within the `btree_multimap`. If an erase occurs, any
|
||||||
|
// references, pointers, or iterators are invalidated.
|
||||||
|
// Overloads are listed below.
|
||||||
|
//
|
||||||
|
// iterator erase(iterator position):
|
||||||
|
// iterator erase(const_iterator position):
|
||||||
|
//
|
||||||
|
// Erases the element at `position` of the `btree_multimap`, returning
|
||||||
|
// the iterator pointing to the element after the one that was erased
|
||||||
|
// (or end() if none exists).
|
||||||
|
//
|
||||||
|
// iterator erase(const_iterator first, const_iterator last):
|
||||||
|
//
|
||||||
|
// Erases the elements in the open interval [`first`, `last`), returning
|
||||||
|
// the iterator pointing to the element after the interval that was erased
|
||||||
|
// (or end() if none exists).
|
||||||
|
//
|
||||||
|
// template <typename K> size_type erase(const K& key):
|
||||||
|
//
|
||||||
|
// Erases the elements matching the key, if any exist, returning the
|
||||||
|
// number of elements erased.
|
||||||
|
using Base::erase;
|
||||||
|
|
||||||
|
// btree_multimap::insert()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value into the `btree_multimap`,
|
||||||
|
// returning an iterator pointing to the newly inserted element.
|
||||||
|
// Any references, pointers, or iterators are invalidated. Overloads are
|
||||||
|
// listed below.
|
||||||
|
//
|
||||||
|
// iterator insert(const value_type& value):
|
||||||
|
//
|
||||||
|
// Inserts a value into the `btree_multimap`, returning an iterator to the
|
||||||
|
// inserted element.
|
||||||
|
//
|
||||||
|
// iterator insert(value_type&& value):
|
||||||
|
//
|
||||||
|
// Inserts a moveable value into the `btree_multimap`, returning an iterator
|
||||||
|
// to the inserted element.
|
||||||
|
//
|
||||||
|
// iterator insert(const_iterator hint, const value_type& value):
|
||||||
|
// iterator insert(const_iterator hint, value_type&& value):
|
||||||
|
//
|
||||||
|
// Inserts a value, using the position of `hint` as a non-binding suggestion
|
||||||
|
// for where to begin the insertion search. Returns an iterator to the
|
||||||
|
// inserted element.
|
||||||
|
//
|
||||||
|
// void insert(InputIterator first, InputIterator last):
|
||||||
|
//
|
||||||
|
// Inserts a range of values [`first`, `last`).
|
||||||
|
//
|
||||||
|
// void insert(std::initializer_list<init_type> ilist):
|
||||||
|
//
|
||||||
|
// Inserts the elements within the initializer list `ilist`.
|
||||||
|
using Base::insert;
|
||||||
|
|
||||||
|
// btree_multimap::emplace()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `btree_multimap`. Any references, pointers, or iterators are
|
||||||
|
// invalidated.
|
||||||
|
using Base::emplace;
|
||||||
|
|
||||||
|
// btree_multimap::emplace_hint()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `btree_multimap`, using the position of `hint` as a non-binding
|
||||||
|
// suggestion for where to begin the insertion search.
|
||||||
|
//
|
||||||
|
// Any references, pointers, or iterators are invalidated.
|
||||||
|
using Base::emplace_hint;
|
||||||
|
|
||||||
|
// btree_multimap::extract()
|
||||||
|
//
|
||||||
|
// Extracts the indicated element, erasing it in the process, and returns it
|
||||||
|
// as a C++17-compatible node handle. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// node_type extract(const_iterator position):
|
||||||
|
//
|
||||||
|
// Extracts the element at the indicated position and returns a node handle
|
||||||
|
// owning that extracted data.
|
||||||
|
//
|
||||||
|
// template <typename K> node_type extract(const K& k):
|
||||||
|
//
|
||||||
|
// Extracts the element with the key matching the passed key value and
|
||||||
|
// returns a node handle owning that extracted data. If the `btree_multimap`
|
||||||
|
// does not contain an element with a matching key, this function returns an
|
||||||
|
// empty node handle.
|
||||||
|
//
|
||||||
|
// NOTE: when compiled in an earlier version of C++ than C++17,
|
||||||
|
// `node_type::key()` returns a const reference to the key instead of a
|
||||||
|
// mutable reference. We cannot safely return a mutable reference without
|
||||||
|
// std::launder (which is not available before C++17).
|
||||||
|
//
|
||||||
|
// NOTE: In this context, `node_type` refers to the C++17 concept of a
|
||||||
|
// move-only type that owns and provides access to the elements in associative
|
||||||
|
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
|
||||||
|
// It does NOT refer to the data layout of the underlying btree.
|
||||||
|
using Base::extract;
|
||||||
|
|
||||||
|
// btree_multimap::merge()
|
||||||
|
//
|
||||||
|
// Extracts all elements from a given `source` btree_multimap into this
|
||||||
|
// `btree_multimap`.
|
||||||
|
using Base::merge;
|
||||||
|
|
||||||
|
// btree_multimap::swap(btree_multimap& other)
|
||||||
|
//
|
||||||
|
// Exchanges the contents of this `btree_multimap` with those of the `other`
|
||||||
|
// btree_multimap, avoiding invocation of any move, copy, or swap operations
|
||||||
|
// on individual elements.
|
||||||
|
//
|
||||||
|
// All iterators and references on the `btree_multimap` remain valid,
|
||||||
|
// excepting for the past-the-end iterator, which is invalidated.
|
||||||
|
using Base::swap;
|
||||||
|
|
||||||
|
// btree_multimap::contains()
|
||||||
|
//
|
||||||
|
// template <typename K> bool contains(const K& key) const:
|
||||||
|
//
|
||||||
|
// Determines whether an element comparing equal to the given `key` exists
|
||||||
|
// within the `btree_multimap`, returning `true` if so or `false` otherwise.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::contains;
|
||||||
|
|
||||||
|
// btree_multimap::count()
|
||||||
|
//
|
||||||
|
// template <typename K> size_type count(const K& key) const:
|
||||||
|
//
|
||||||
|
// Returns the number of elements comparing equal to the given `key` within
|
||||||
|
// the `btree_multimap`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::count;
|
||||||
|
|
||||||
|
// btree_multimap::equal_range()
|
||||||
|
//
|
||||||
|
// Returns a half-open range [first, last), defined by a `std::pair` of two
|
||||||
|
// iterators, containing all elements with the passed key in the
|
||||||
|
// `btree_multimap`.
|
||||||
|
using Base::equal_range;
|
||||||
|
|
||||||
|
// btree_multimap::find()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator find(const K& key):
|
||||||
|
// template <typename K> const_iterator find(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds an element with the passed `key` within the `btree_multimap`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::find;
|
||||||
|
|
||||||
|
// btree_multimap::lower_bound()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator lower_bound(const K& key):
|
||||||
|
// template <typename K> const_iterator lower_bound(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds the first element with a key that is not less than `key` within the
|
||||||
|
// `btree_multimap`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::lower_bound;
|
||||||
|
|
||||||
|
// btree_multimap::upper_bound()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator upper_bound(const K& key):
|
||||||
|
// template <typename K> const_iterator upper_bound(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds the first element with a key that is greater than `key` within the
|
||||||
|
// `btree_multimap`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::upper_bound;
|
||||||
|
|
||||||
|
// btree_multimap::get_allocator()
|
||||||
|
//
|
||||||
|
// Returns the allocator function associated with this `btree_multimap`.
|
||||||
|
using Base::get_allocator;
|
||||||
|
|
||||||
|
// btree_multimap::key_comp();
|
||||||
|
//
|
||||||
|
// Returns the key comparator associated with this `btree_multimap`.
|
||||||
|
using Base::key_comp;
|
||||||
|
|
||||||
|
// btree_multimap::value_comp();
|
||||||
|
//
|
||||||
|
// Returns the value comparator associated with this `btree_multimap`.
|
||||||
|
using Base::value_comp;
|
||||||
|
};
|
||||||
|
|
||||||
|
// absl::swap(absl::btree_multimap<>, absl::btree_multimap<>)
|
||||||
|
//
|
||||||
|
// Swaps the contents of two `absl::btree_multimap` containers.
|
||||||
|
template <typename K, typename V, typename C, typename A>
|
||||||
|
void swap(btree_multimap<K, V, C, A> &x, btree_multimap<K, V, C, A> &y) {
|
||||||
|
return x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// absl::erase_if(absl::btree_multimap<>, Pred)
|
||||||
|
//
|
||||||
|
// Erases all elements that satisfy the predicate pred from the container.
|
||||||
|
// Returns the number of erased elements.
|
||||||
|
template <typename K, typename V, typename C, typename A, typename Pred>
|
||||||
|
typename btree_multimap<K, V, C, A>::size_type erase_if(
|
||||||
|
btree_multimap<K, V, C, A> &map, Pred pred) {
|
||||||
|
return container_internal::btree_access::erase_if(map, std::move(pred));
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace container_internal {
|
||||||
|
|
||||||
|
// A parameters structure for holding the type parameters for a btree_map.
|
||||||
|
// Compare and Alloc should be nothrow copy-constructible.
|
||||||
|
template <typename Key, typename Data, typename Compare, typename Alloc,
|
||||||
|
int TargetNodeSize, bool IsMulti>
|
||||||
|
struct map_params : common_params<Key, Compare, Alloc, TargetNodeSize, IsMulti,
|
||||||
|
/*IsMap=*/true, map_slot_policy<Key, Data>> {
|
||||||
|
using super_type = typename map_params::common_params;
|
||||||
|
using mapped_type = Data;
|
||||||
|
// This type allows us to move keys when it is safe to do so. It is safe
|
||||||
|
// for maps in which value_type and mutable_value_type are layout compatible.
|
||||||
|
using slot_policy = typename super_type::slot_policy;
|
||||||
|
using slot_type = typename super_type::slot_type;
|
||||||
|
using value_type = typename super_type::value_type;
|
||||||
|
using init_type = typename super_type::init_type;
|
||||||
|
|
||||||
|
template <typename V>
|
||||||
|
static auto key(const V &value) -> decltype(value.first) {
|
||||||
|
return value.first;
|
||||||
|
}
|
||||||
|
static const Key &key(const slot_type *s) { return slot_policy::key(s); }
|
||||||
|
static const Key &key(slot_type *s) { return slot_policy::key(s); }
|
||||||
|
// For use in node handle.
|
||||||
|
static auto mutable_key(slot_type *s)
|
||||||
|
-> decltype(slot_policy::mutable_key(s)) {
|
||||||
|
return slot_policy::mutable_key(s);
|
||||||
|
}
|
||||||
|
static mapped_type &value(value_type *value) { return value->second; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace container_internal
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_CONTAINER_BTREE_MAP_H_
|
||||||
793
include/absl/container/btree_set.h
Normal file
@ -0,0 +1,793 @@
|
|||||||
|
// Copyright 2018 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: btree_set.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header file defines B-tree sets: sorted associative containers of
|
||||||
|
// values.
|
||||||
|
//
|
||||||
|
// * `absl::btree_set<>`
|
||||||
|
// * `absl::btree_multiset<>`
|
||||||
|
//
|
||||||
|
// These B-tree types are similar to the corresponding types in the STL
|
||||||
|
// (`std::set` and `std::multiset`) and generally conform to the STL interfaces
|
||||||
|
// of those types. However, because they are implemented using B-trees, they
|
||||||
|
// are more efficient in most situations.
|
||||||
|
//
|
||||||
|
// Unlike `std::set` and `std::multiset`, which are commonly implemented using
|
||||||
|
// red-black tree nodes, B-tree sets use more generic B-tree nodes able to hold
|
||||||
|
// multiple values per node. Holding multiple values per node often makes
|
||||||
|
// B-tree sets perform better than their `std::set` counterparts, because
|
||||||
|
// multiple entries can be checked within the same cache hit.
|
||||||
|
//
|
||||||
|
// However, these types should not be considered drop-in replacements for
|
||||||
|
// `std::set` and `std::multiset` as there are some API differences, which are
|
||||||
|
// noted in this header file. The most consequential differences with respect to
|
||||||
|
// migrating to b-tree from the STL types are listed in the next paragraph.
|
||||||
|
// Other API differences are minor.
|
||||||
|
//
|
||||||
|
// Importantly, insertions and deletions may invalidate outstanding iterators,
|
||||||
|
// pointers, and references to elements. Such invalidations are typically only
|
||||||
|
// an issue if insertion and deletion operations are interleaved with the use of
|
||||||
|
// more than one iterator, pointer, or reference simultaneously. For this
|
||||||
|
// reason, `insert()` and `erase()` return a valid iterator at the current
|
||||||
|
// position.
|
||||||
|
|
||||||
|
#ifndef ABSL_CONTAINER_BTREE_SET_H_
|
||||||
|
#define ABSL_CONTAINER_BTREE_SET_H_
|
||||||
|
|
||||||
|
#include "absl/container/internal/btree.h" // IWYU pragma: export
|
||||||
|
#include "absl/container/internal/btree_container.h" // IWYU pragma: export
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace container_internal {
|
||||||
|
|
||||||
|
template <typename Key>
|
||||||
|
struct set_slot_policy;
|
||||||
|
|
||||||
|
template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
|
||||||
|
bool IsMulti>
|
||||||
|
struct set_params;
|
||||||
|
|
||||||
|
} // namespace container_internal
|
||||||
|
|
||||||
|
// absl::btree_set<>
|
||||||
|
//
|
||||||
|
// An `absl::btree_set<K>` is an ordered associative container of unique key
|
||||||
|
// values designed to be a more efficient replacement for `std::set` (in most
|
||||||
|
// cases).
|
||||||
|
//
|
||||||
|
// Keys are sorted using an (optional) comparison function, which defaults to
|
||||||
|
// `std::less<K>`.
|
||||||
|
//
|
||||||
|
// An `absl::btree_set<K>` uses a default allocator of `std::allocator<K>` to
|
||||||
|
// allocate (and deallocate) nodes, and construct and destruct values within
|
||||||
|
// those nodes. You may instead specify a custom allocator `A` (which in turn
|
||||||
|
// requires specifying a custom comparator `C`) as in
|
||||||
|
// `absl::btree_set<K, C, A>`.
|
||||||
|
//
|
||||||
|
template <typename Key, typename Compare = std::less<Key>,
|
||||||
|
typename Alloc = std::allocator<Key>>
|
||||||
|
class btree_set
|
||||||
|
: public container_internal::btree_set_container<
|
||||||
|
container_internal::btree<container_internal::set_params<
|
||||||
|
Key, Compare, Alloc, /*TargetNodeSize=*/256,
|
||||||
|
/*IsMulti=*/false>>> {
|
||||||
|
using Base = typename btree_set::btree_set_container;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors and Assignment Operators
|
||||||
|
//
|
||||||
|
// A `btree_set` supports the same overload set as `std::set`
|
||||||
|
// for construction and assignment:
|
||||||
|
//
|
||||||
|
// * Default constructor
|
||||||
|
//
|
||||||
|
// absl::btree_set<std::string> set1;
|
||||||
|
//
|
||||||
|
// * Initializer List constructor
|
||||||
|
//
|
||||||
|
// absl::btree_set<std::string> set2 =
|
||||||
|
// {{"huey"}, {"dewey"}, {"louie"},};
|
||||||
|
//
|
||||||
|
// * Copy constructor
|
||||||
|
//
|
||||||
|
// absl::btree_set<std::string> set3(set2);
|
||||||
|
//
|
||||||
|
// * Copy assignment operator
|
||||||
|
//
|
||||||
|
// absl::btree_set<std::string> set4;
|
||||||
|
// set4 = set3;
|
||||||
|
//
|
||||||
|
// * Move constructor
|
||||||
|
//
|
||||||
|
// // Move is guaranteed efficient
|
||||||
|
// absl::btree_set<std::string> set5(std::move(set4));
|
||||||
|
//
|
||||||
|
// * Move assignment operator
|
||||||
|
//
|
||||||
|
// // May be efficient if allocators are compatible
|
||||||
|
// absl::btree_set<std::string> set6;
|
||||||
|
// set6 = std::move(set5);
|
||||||
|
//
|
||||||
|
// * Range constructor
|
||||||
|
//
|
||||||
|
// std::vector<std::string> v = {"a", "b"};
|
||||||
|
// absl::btree_set<std::string> set7(v.begin(), v.end());
|
||||||
|
btree_set() {}
|
||||||
|
using Base::Base;
|
||||||
|
|
||||||
|
// btree_set::begin()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the beginning of the `btree_set`.
|
||||||
|
using Base::begin;
|
||||||
|
|
||||||
|
// btree_set::cbegin()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the beginning of the `btree_set`.
|
||||||
|
using Base::cbegin;
|
||||||
|
|
||||||
|
// btree_set::end()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the end of the `btree_set`.
|
||||||
|
using Base::end;
|
||||||
|
|
||||||
|
// btree_set::cend()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the end of the `btree_set`.
|
||||||
|
using Base::cend;
|
||||||
|
|
||||||
|
// btree_set::empty()
|
||||||
|
//
|
||||||
|
// Returns whether or not the `btree_set` is empty.
|
||||||
|
using Base::empty;
|
||||||
|
|
||||||
|
// btree_set::max_size()
|
||||||
|
//
|
||||||
|
// Returns the largest theoretical possible number of elements within a
|
||||||
|
// `btree_set` under current memory constraints. This value can be thought
|
||||||
|
// of as the largest value of `std::distance(begin(), end())` for a
|
||||||
|
// `btree_set<Key>`.
|
||||||
|
using Base::max_size;
|
||||||
|
|
||||||
|
// btree_set::size()
|
||||||
|
//
|
||||||
|
// Returns the number of elements currently within the `btree_set`.
|
||||||
|
using Base::size;
|
||||||
|
|
||||||
|
// btree_set::clear()
|
||||||
|
//
|
||||||
|
// Removes all elements from the `btree_set`. Invalidates any references,
|
||||||
|
// pointers, or iterators referring to contained elements.
|
||||||
|
using Base::clear;
|
||||||
|
|
||||||
|
// btree_set::erase()
|
||||||
|
//
|
||||||
|
// Erases elements within the `btree_set`. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// iterator erase(iterator position):
|
||||||
|
// iterator erase(const_iterator position):
|
||||||
|
//
|
||||||
|
// Erases the element at `position` of the `btree_set`, returning
|
||||||
|
// the iterator pointing to the element after the one that was erased
|
||||||
|
// (or end() if none exists).
|
||||||
|
//
|
||||||
|
// iterator erase(const_iterator first, const_iterator last):
|
||||||
|
//
|
||||||
|
// Erases the elements in the open interval [`first`, `last`), returning
|
||||||
|
// the iterator pointing to the element after the interval that was erased
|
||||||
|
// (or end() if none exists).
|
||||||
|
//
|
||||||
|
// template <typename K> size_type erase(const K& key):
|
||||||
|
//
|
||||||
|
// Erases the element with the matching key, if it exists, returning the
|
||||||
|
// number of elements erased (0 or 1).
|
||||||
|
using Base::erase;
|
||||||
|
|
||||||
|
// btree_set::insert()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value into the `btree_set`,
|
||||||
|
// returning an iterator pointing to the newly inserted element, provided that
|
||||||
|
// an element with the given key does not already exist. If an insertion
|
||||||
|
// occurs, any references, pointers, or iterators are invalidated.
|
||||||
|
// Overloads are listed below.
|
||||||
|
//
|
||||||
|
// std::pair<iterator,bool> insert(const value_type& value):
|
||||||
|
//
|
||||||
|
// Inserts a value into the `btree_set`. Returns a pair consisting of an
|
||||||
|
// iterator to the inserted element (or to the element that prevented the
|
||||||
|
// insertion) and a bool denoting whether the insertion took place.
|
||||||
|
//
|
||||||
|
// std::pair<iterator,bool> insert(value_type&& value):
|
||||||
|
//
|
||||||
|
// Inserts a moveable value into the `btree_set`. Returns a pair
|
||||||
|
// consisting of an iterator to the inserted element (or to the element that
|
||||||
|
// prevented the insertion) and a bool denoting whether the insertion took
|
||||||
|
// place.
|
||||||
|
//
|
||||||
|
// iterator insert(const_iterator hint, const value_type& value):
|
||||||
|
// iterator insert(const_iterator hint, value_type&& value):
|
||||||
|
//
|
||||||
|
// Inserts a value, using the position of `hint` as a non-binding suggestion
|
||||||
|
// for where to begin the insertion search. Returns an iterator to the
|
||||||
|
// inserted element, or to the existing element that prevented the
|
||||||
|
// insertion.
|
||||||
|
//
|
||||||
|
// void insert(InputIterator first, InputIterator last):
|
||||||
|
//
|
||||||
|
// Inserts a range of values [`first`, `last`).
|
||||||
|
//
|
||||||
|
// void insert(std::initializer_list<init_type> ilist):
|
||||||
|
//
|
||||||
|
// Inserts the elements within the initializer list `ilist`.
|
||||||
|
using Base::insert;
|
||||||
|
|
||||||
|
// btree_set::emplace()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `btree_set`, provided that no element with the given key
|
||||||
|
// already exists.
|
||||||
|
//
|
||||||
|
// The element may be constructed even if there already is an element with the
|
||||||
|
// key in the container, in which case the newly constructed element will be
|
||||||
|
// destroyed immediately.
|
||||||
|
//
|
||||||
|
// If an insertion occurs, any references, pointers, or iterators are
|
||||||
|
// invalidated.
|
||||||
|
using Base::emplace;
|
||||||
|
|
||||||
|
// btree_set::emplace_hint()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `btree_set`, using the position of `hint` as a non-binding
|
||||||
|
// suggestion for where to begin the insertion search, and only inserts
|
||||||
|
// provided that no element with the given key already exists.
|
||||||
|
//
|
||||||
|
// The element may be constructed even if there already is an element with the
|
||||||
|
// key in the container, in which case the newly constructed element will be
|
||||||
|
// destroyed immediately.
|
||||||
|
//
|
||||||
|
// If an insertion occurs, any references, pointers, or iterators are
|
||||||
|
// invalidated.
|
||||||
|
using Base::emplace_hint;
|
||||||
|
|
||||||
|
// btree_set::extract()
|
||||||
|
//
|
||||||
|
// Extracts the indicated element, erasing it in the process, and returns it
|
||||||
|
// as a C++17-compatible node handle. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// node_type extract(const_iterator position):
|
||||||
|
//
|
||||||
|
// Extracts the element at the indicated position and returns a node handle
|
||||||
|
// owning that extracted data.
|
||||||
|
//
|
||||||
|
// template <typename K> node_type extract(const K& k):
|
||||||
|
//
|
||||||
|
// Extracts the element with the key matching the passed key value and
|
||||||
|
// returns a node handle owning that extracted data. If the `btree_set`
|
||||||
|
// does not contain an element with a matching key, this function returns an
|
||||||
|
// empty node handle.
|
||||||
|
//
|
||||||
|
// NOTE: In this context, `node_type` refers to the C++17 concept of a
|
||||||
|
// move-only type that owns and provides access to the elements in associative
|
||||||
|
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
|
||||||
|
// It does NOT refer to the data layout of the underlying btree.
|
||||||
|
using Base::extract;
|
||||||
|
|
||||||
|
// btree_set::merge()
|
||||||
|
//
|
||||||
|
// Extracts elements from a given `source` btree_set into this
|
||||||
|
// `btree_set`. If the destination `btree_set` already contains an
|
||||||
|
// element with an equivalent key, that element is not extracted.
|
||||||
|
using Base::merge;
|
||||||
|
|
||||||
|
// btree_set::swap(btree_set& other)
|
||||||
|
//
|
||||||
|
// Exchanges the contents of this `btree_set` with those of the `other`
|
||||||
|
// btree_set, avoiding invocation of any move, copy, or swap operations on
|
||||||
|
// individual elements.
|
||||||
|
//
|
||||||
|
// All iterators and references on the `btree_set` remain valid, excepting
|
||||||
|
// for the past-the-end iterator, which is invalidated.
|
||||||
|
using Base::swap;
|
||||||
|
|
||||||
|
// btree_set::contains()
|
||||||
|
//
|
||||||
|
// template <typename K> bool contains(const K& key) const:
|
||||||
|
//
|
||||||
|
// Determines whether an element comparing equal to the given `key` exists
|
||||||
|
// within the `btree_set`, returning `true` if so or `false` otherwise.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::contains;
|
||||||
|
|
||||||
|
// btree_set::count()
|
||||||
|
//
|
||||||
|
// template <typename K> size_type count(const K& key) const:
|
||||||
|
//
|
||||||
|
// Returns the number of elements comparing equal to the given `key` within
|
||||||
|
// the `btree_set`. Note that this function will return either `1` or `0`
|
||||||
|
// since duplicate elements are not allowed within a `btree_set`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::count;
|
||||||
|
|
||||||
|
// btree_set::equal_range()
|
||||||
|
//
|
||||||
|
// Returns a closed range [first, last], defined by a `std::pair` of two
|
||||||
|
// iterators, containing all elements with the passed key in the
|
||||||
|
// `btree_set`.
|
||||||
|
using Base::equal_range;
|
||||||
|
|
||||||
|
// btree_set::find()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator find(const K& key):
|
||||||
|
// template <typename K> const_iterator find(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds an element with the passed `key` within the `btree_set`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::find;
|
||||||
|
|
||||||
|
// btree_set::lower_bound()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator lower_bound(const K& key):
|
||||||
|
// template <typename K> const_iterator lower_bound(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds the first element that is not less than `key` within the `btree_set`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::lower_bound;
|
||||||
|
|
||||||
|
// btree_set::upper_bound()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator upper_bound(const K& key):
|
||||||
|
// template <typename K> const_iterator upper_bound(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds the first element that is greater than `key` within the `btree_set`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::upper_bound;
|
||||||
|
|
||||||
|
// btree_set::get_allocator()
|
||||||
|
//
|
||||||
|
// Returns the allocator function associated with this `btree_set`.
|
||||||
|
using Base::get_allocator;
|
||||||
|
|
||||||
|
// btree_set::key_comp();
|
||||||
|
//
|
||||||
|
// Returns the key comparator associated with this `btree_set`.
|
||||||
|
using Base::key_comp;
|
||||||
|
|
||||||
|
// btree_set::value_comp();
|
||||||
|
//
|
||||||
|
// Returns the value comparator associated with this `btree_set`. The keys to
|
||||||
|
// sort the elements are the values themselves, therefore `value_comp` and its
|
||||||
|
// sibling member function `key_comp` are equivalent.
|
||||||
|
using Base::value_comp;
|
||||||
|
};
|
||||||
|
|
||||||
|
// absl::swap(absl::btree_set<>, absl::btree_set<>)
|
||||||
|
//
|
||||||
|
// Swaps the contents of two `absl::btree_set` containers.
|
||||||
|
template <typename K, typename C, typename A>
|
||||||
|
void swap(btree_set<K, C, A> &x, btree_set<K, C, A> &y) {
|
||||||
|
return x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// absl::erase_if(absl::btree_set<>, Pred)
|
||||||
|
//
|
||||||
|
// Erases all elements that satisfy the predicate pred from the container.
|
||||||
|
// Returns the number of erased elements.
|
||||||
|
template <typename K, typename C, typename A, typename Pred>
|
||||||
|
typename btree_set<K, C, A>::size_type erase_if(btree_set<K, C, A> &set,
|
||||||
|
Pred pred) {
|
||||||
|
return container_internal::btree_access::erase_if(set, std::move(pred));
|
||||||
|
}
|
||||||
|
|
||||||
|
// absl::btree_multiset<>
|
||||||
|
//
|
||||||
|
// An `absl::btree_multiset<K>` is an ordered associative container of
|
||||||
|
// keys and associated values designed to be a more efficient replacement
|
||||||
|
// for `std::multiset` (in most cases). Unlike `absl::btree_set`, a B-tree
|
||||||
|
// multiset allows equivalent elements.
|
||||||
|
//
|
||||||
|
// Keys are sorted using an (optional) comparison function, which defaults to
|
||||||
|
// `std::less<K>`.
|
||||||
|
//
|
||||||
|
// An `absl::btree_multiset<K>` uses a default allocator of `std::allocator<K>`
|
||||||
|
// to allocate (and deallocate) nodes, and construct and destruct values within
|
||||||
|
// those nodes. You may instead specify a custom allocator `A` (which in turn
|
||||||
|
// requires specifying a custom comparator `C`) as in
|
||||||
|
// `absl::btree_multiset<K, C, A>`.
|
||||||
|
//
|
||||||
|
template <typename Key, typename Compare = std::less<Key>,
|
||||||
|
typename Alloc = std::allocator<Key>>
|
||||||
|
class btree_multiset
|
||||||
|
: public container_internal::btree_multiset_container<
|
||||||
|
container_internal::btree<container_internal::set_params<
|
||||||
|
Key, Compare, Alloc, /*TargetNodeSize=*/256,
|
||||||
|
/*IsMulti=*/true>>> {
|
||||||
|
using Base = typename btree_multiset::btree_multiset_container;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors and Assignment Operators
|
||||||
|
//
|
||||||
|
// A `btree_multiset` supports the same overload set as `std::set`
|
||||||
|
// for construction and assignment:
|
||||||
|
//
|
||||||
|
// * Default constructor
|
||||||
|
//
|
||||||
|
// absl::btree_multiset<std::string> set1;
|
||||||
|
//
|
||||||
|
// * Initializer List constructor
|
||||||
|
//
|
||||||
|
// absl::btree_multiset<std::string> set2 =
|
||||||
|
// {{"huey"}, {"dewey"}, {"louie"},};
|
||||||
|
//
|
||||||
|
// * Copy constructor
|
||||||
|
//
|
||||||
|
// absl::btree_multiset<std::string> set3(set2);
|
||||||
|
//
|
||||||
|
// * Copy assignment operator
|
||||||
|
//
|
||||||
|
// absl::btree_multiset<std::string> set4;
|
||||||
|
// set4 = set3;
|
||||||
|
//
|
||||||
|
// * Move constructor
|
||||||
|
//
|
||||||
|
// // Move is guaranteed efficient
|
||||||
|
// absl::btree_multiset<std::string> set5(std::move(set4));
|
||||||
|
//
|
||||||
|
// * Move assignment operator
|
||||||
|
//
|
||||||
|
// // May be efficient if allocators are compatible
|
||||||
|
// absl::btree_multiset<std::string> set6;
|
||||||
|
// set6 = std::move(set5);
|
||||||
|
//
|
||||||
|
// * Range constructor
|
||||||
|
//
|
||||||
|
// std::vector<std::string> v = {"a", "b"};
|
||||||
|
// absl::btree_multiset<std::string> set7(v.begin(), v.end());
|
||||||
|
btree_multiset() {}
|
||||||
|
using Base::Base;
|
||||||
|
|
||||||
|
// btree_multiset::begin()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the beginning of the `btree_multiset`.
|
||||||
|
using Base::begin;
|
||||||
|
|
||||||
|
// btree_multiset::cbegin()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the beginning of the `btree_multiset`.
|
||||||
|
using Base::cbegin;
|
||||||
|
|
||||||
|
// btree_multiset::end()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the end of the `btree_multiset`.
|
||||||
|
using Base::end;
|
||||||
|
|
||||||
|
// btree_multiset::cend()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the end of the `btree_multiset`.
|
||||||
|
using Base::cend;
|
||||||
|
|
||||||
|
// btree_multiset::empty()
|
||||||
|
//
|
||||||
|
// Returns whether or not the `btree_multiset` is empty.
|
||||||
|
using Base::empty;
|
||||||
|
|
||||||
|
// btree_multiset::max_size()
|
||||||
|
//
|
||||||
|
// Returns the largest theoretical possible number of elements within a
|
||||||
|
// `btree_multiset` under current memory constraints. This value can be
|
||||||
|
// thought of as the largest value of `std::distance(begin(), end())` for a
|
||||||
|
// `btree_multiset<Key>`.
|
||||||
|
using Base::max_size;
|
||||||
|
|
||||||
|
// btree_multiset::size()
|
||||||
|
//
|
||||||
|
// Returns the number of elements currently within the `btree_multiset`.
|
||||||
|
using Base::size;
|
||||||
|
|
||||||
|
// btree_multiset::clear()
|
||||||
|
//
|
||||||
|
// Removes all elements from the `btree_multiset`. Invalidates any references,
|
||||||
|
// pointers, or iterators referring to contained elements.
|
||||||
|
using Base::clear;
|
||||||
|
|
||||||
|
// btree_multiset::erase()
|
||||||
|
//
|
||||||
|
// Erases elements within the `btree_multiset`. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// iterator erase(iterator position):
|
||||||
|
// iterator erase(const_iterator position):
|
||||||
|
//
|
||||||
|
// Erases the element at `position` of the `btree_multiset`, returning
|
||||||
|
// the iterator pointing to the element after the one that was erased
|
||||||
|
// (or end() if none exists).
|
||||||
|
//
|
||||||
|
// iterator erase(const_iterator first, const_iterator last):
|
||||||
|
//
|
||||||
|
// Erases the elements in the open interval [`first`, `last`), returning
|
||||||
|
// the iterator pointing to the element after the interval that was erased
|
||||||
|
// (or end() if none exists).
|
||||||
|
//
|
||||||
|
// template <typename K> size_type erase(const K& key):
|
||||||
|
//
|
||||||
|
// Erases the elements matching the key, if any exist, returning the
|
||||||
|
// number of elements erased.
|
||||||
|
using Base::erase;
|
||||||
|
|
||||||
|
// btree_multiset::insert()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value into the `btree_multiset`,
|
||||||
|
// returning an iterator pointing to the newly inserted element.
|
||||||
|
// Any references, pointers, or iterators are invalidated. Overloads are
|
||||||
|
// listed below.
|
||||||
|
//
|
||||||
|
// iterator insert(const value_type& value):
|
||||||
|
//
|
||||||
|
// Inserts a value into the `btree_multiset`, returning an iterator to the
|
||||||
|
// inserted element.
|
||||||
|
//
|
||||||
|
// iterator insert(value_type&& value):
|
||||||
|
//
|
||||||
|
// Inserts a moveable value into the `btree_multiset`, returning an iterator
|
||||||
|
// to the inserted element.
|
||||||
|
//
|
||||||
|
// iterator insert(const_iterator hint, const value_type& value):
|
||||||
|
// iterator insert(const_iterator hint, value_type&& value):
|
||||||
|
//
|
||||||
|
// Inserts a value, using the position of `hint` as a non-binding suggestion
|
||||||
|
// for where to begin the insertion search. Returns an iterator to the
|
||||||
|
// inserted element.
|
||||||
|
//
|
||||||
|
// void insert(InputIterator first, InputIterator last):
|
||||||
|
//
|
||||||
|
// Inserts a range of values [`first`, `last`).
|
||||||
|
//
|
||||||
|
// void insert(std::initializer_list<init_type> ilist):
|
||||||
|
//
|
||||||
|
// Inserts the elements within the initializer list `ilist`.
|
||||||
|
using Base::insert;
|
||||||
|
|
||||||
|
// btree_multiset::emplace()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `btree_multiset`. Any references, pointers, or iterators are
|
||||||
|
// invalidated.
|
||||||
|
using Base::emplace;
|
||||||
|
|
||||||
|
// btree_multiset::emplace_hint()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `btree_multiset`, using the position of `hint` as a non-binding
|
||||||
|
// suggestion for where to begin the insertion search.
|
||||||
|
//
|
||||||
|
// Any references, pointers, or iterators are invalidated.
|
||||||
|
using Base::emplace_hint;
|
||||||
|
|
||||||
|
// btree_multiset::extract()
|
||||||
|
//
|
||||||
|
// Extracts the indicated element, erasing it in the process, and returns it
|
||||||
|
// as a C++17-compatible node handle. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// node_type extract(const_iterator position):
|
||||||
|
//
|
||||||
|
// Extracts the element at the indicated position and returns a node handle
|
||||||
|
// owning that extracted data.
|
||||||
|
//
|
||||||
|
// template <typename K> node_type extract(const K& k):
|
||||||
|
//
|
||||||
|
// Extracts the element with the key matching the passed key value and
|
||||||
|
// returns a node handle owning that extracted data. If the `btree_multiset`
|
||||||
|
// does not contain an element with a matching key, this function returns an
|
||||||
|
// empty node handle.
|
||||||
|
//
|
||||||
|
// NOTE: In this context, `node_type` refers to the C++17 concept of a
|
||||||
|
// move-only type that owns and provides access to the elements in associative
|
||||||
|
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
|
||||||
|
// It does NOT refer to the data layout of the underlying btree.
|
||||||
|
using Base::extract;
|
||||||
|
|
||||||
|
// btree_multiset::merge()
|
||||||
|
//
|
||||||
|
// Extracts all elements from a given `source` btree_multiset into this
|
||||||
|
// `btree_multiset`.
|
||||||
|
using Base::merge;
|
||||||
|
|
||||||
|
// btree_multiset::swap(btree_multiset& other)
|
||||||
|
//
|
||||||
|
// Exchanges the contents of this `btree_multiset` with those of the `other`
|
||||||
|
// btree_multiset, avoiding invocation of any move, copy, or swap operations
|
||||||
|
// on individual elements.
|
||||||
|
//
|
||||||
|
// All iterators and references on the `btree_multiset` remain valid,
|
||||||
|
// excepting for the past-the-end iterator, which is invalidated.
|
||||||
|
using Base::swap;
|
||||||
|
|
||||||
|
// btree_multiset::contains()
|
||||||
|
//
|
||||||
|
// template <typename K> bool contains(const K& key) const:
|
||||||
|
//
|
||||||
|
// Determines whether an element comparing equal to the given `key` exists
|
||||||
|
// within the `btree_multiset`, returning `true` if so or `false` otherwise.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::contains;
|
||||||
|
|
||||||
|
// btree_multiset::count()
|
||||||
|
//
|
||||||
|
// template <typename K> size_type count(const K& key) const:
|
||||||
|
//
|
||||||
|
// Returns the number of elements comparing equal to the given `key` within
|
||||||
|
// the `btree_multiset`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::count;
|
||||||
|
|
||||||
|
// btree_multiset::equal_range()
|
||||||
|
//
|
||||||
|
// Returns a closed range [first, last], defined by a `std::pair` of two
|
||||||
|
// iterators, containing all elements with the passed key in the
|
||||||
|
// `btree_multiset`.
|
||||||
|
using Base::equal_range;
|
||||||
|
|
||||||
|
// btree_multiset::find()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator find(const K& key):
|
||||||
|
// template <typename K> const_iterator find(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds an element with the passed `key` within the `btree_multiset`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::find;
|
||||||
|
|
||||||
|
// btree_multiset::lower_bound()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator lower_bound(const K& key):
|
||||||
|
// template <typename K> const_iterator lower_bound(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds the first element that is not less than `key` within the
|
||||||
|
// `btree_multiset`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::lower_bound;
|
||||||
|
|
||||||
|
// btree_multiset::upper_bound()
|
||||||
|
//
|
||||||
|
// template <typename K> iterator upper_bound(const K& key):
|
||||||
|
// template <typename K> const_iterator upper_bound(const K& key) const:
|
||||||
|
//
|
||||||
|
// Finds the first element that is greater than `key` within the
|
||||||
|
// `btree_multiset`.
|
||||||
|
//
|
||||||
|
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||||
|
// heterogeneous comparator.
|
||||||
|
using Base::upper_bound;
|
||||||
|
|
||||||
|
// btree_multiset::get_allocator()
|
||||||
|
//
|
||||||
|
// Returns the allocator function associated with this `btree_multiset`.
|
||||||
|
using Base::get_allocator;
|
||||||
|
|
||||||
|
// btree_multiset::key_comp();
|
||||||
|
//
|
||||||
|
// Returns the key comparator associated with this `btree_multiset`.
|
||||||
|
using Base::key_comp;
|
||||||
|
|
||||||
|
// btree_multiset::value_comp();
|
||||||
|
//
|
||||||
|
// Returns the value comparator associated with this `btree_multiset`. The
|
||||||
|
// keys to sort the elements are the values themselves, therefore `value_comp`
|
||||||
|
// and its sibling member function `key_comp` are equivalent.
|
||||||
|
using Base::value_comp;
|
||||||
|
};
|
||||||
|
|
||||||
|
// absl::swap(absl::btree_multiset<>, absl::btree_multiset<>)
|
||||||
|
//
|
||||||
|
// Swaps the contents of two `absl::btree_multiset` containers.
|
||||||
|
template <typename K, typename C, typename A>
|
||||||
|
void swap(btree_multiset<K, C, A> &x, btree_multiset<K, C, A> &y) {
|
||||||
|
return x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// absl::erase_if(absl::btree_multiset<>, Pred)
|
||||||
|
//
|
||||||
|
// Erases all elements that satisfy the predicate pred from the container.
|
||||||
|
// Returns the number of erased elements.
|
||||||
|
template <typename K, typename C, typename A, typename Pred>
|
||||||
|
typename btree_multiset<K, C, A>::size_type erase_if(
|
||||||
|
btree_multiset<K, C, A> & set, Pred pred) {
|
||||||
|
return container_internal::btree_access::erase_if(set, std::move(pred));
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace container_internal {
|
||||||
|
|
||||||
|
// This type implements the necessary functions from the
|
||||||
|
// absl::container_internal::slot_type interface for btree_(multi)set.
|
||||||
|
template <typename Key>
|
||||||
|
struct set_slot_policy {
|
||||||
|
using slot_type = Key;
|
||||||
|
using value_type = Key;
|
||||||
|
using mutable_value_type = Key;
|
||||||
|
|
||||||
|
static value_type &element(slot_type *slot) { return *slot; }
|
||||||
|
static const value_type &element(const slot_type *slot) { return *slot; }
|
||||||
|
|
||||||
|
template <typename Alloc, class... Args>
|
||||||
|
static void construct(Alloc *alloc, slot_type *slot, Args &&...args) {
|
||||||
|
absl::allocator_traits<Alloc>::construct(*alloc, slot,
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Alloc>
|
||||||
|
static void construct(Alloc *alloc, slot_type *slot, slot_type *other) {
|
||||||
|
absl::allocator_traits<Alloc>::construct(*alloc, slot, std::move(*other));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Alloc>
|
||||||
|
static void construct(Alloc *alloc, slot_type *slot, const slot_type *other) {
|
||||||
|
absl::allocator_traits<Alloc>::construct(*alloc, slot, *other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Alloc>
|
||||||
|
static void destroy(Alloc *alloc, slot_type *slot) {
|
||||||
|
absl::allocator_traits<Alloc>::destroy(*alloc, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Alloc>
|
||||||
|
static void transfer(Alloc *alloc, slot_type *new_slot, slot_type *old_slot) {
|
||||||
|
construct(alloc, new_slot, old_slot);
|
||||||
|
destroy(alloc, old_slot);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A parameters structure for holding the type parameters for a btree_set.
|
||||||
|
// Compare and Alloc should be nothrow copy-constructible.
|
||||||
|
template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
|
||||||
|
bool IsMulti>
|
||||||
|
struct set_params : common_params<Key, Compare, Alloc, TargetNodeSize, IsMulti,
|
||||||
|
/*IsMap=*/false, set_slot_policy<Key>> {
|
||||||
|
using value_type = Key;
|
||||||
|
using slot_type = typename set_params::common_params::slot_type;
|
||||||
|
|
||||||
|
template <typename V>
|
||||||
|
static const V &key(const V &value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
static const Key &key(const slot_type *slot) { return *slot; }
|
||||||
|
static const Key &key(slot_type *slot) { return *slot; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace container_internal
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_CONTAINER_BTREE_SET_H_
|
||||||
166
include/absl/container/btree_test.h
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
// Copyright 2018 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_CONTAINER_BTREE_TEST_H_
|
||||||
|
#define ABSL_CONTAINER_BTREE_TEST_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <random>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/container/btree_map.h"
|
||||||
|
#include "absl/container/btree_set.h"
|
||||||
|
#include "absl/container/flat_hash_set.h"
|
||||||
|
#include "absl/strings/cord.h"
|
||||||
|
#include "absl/time/time.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace container_internal {
|
||||||
|
|
||||||
|
// Like remove_const but propagates the removal through std::pair.
|
||||||
|
template <typename T>
|
||||||
|
struct remove_pair_const {
|
||||||
|
using type = typename std::remove_const<T>::type;
|
||||||
|
};
|
||||||
|
template <typename T, typename U>
|
||||||
|
struct remove_pair_const<std::pair<T, U> > {
|
||||||
|
using type = std::pair<typename remove_pair_const<T>::type,
|
||||||
|
typename remove_pair_const<U>::type>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Utility class to provide an accessor for a key given a value. The default
|
||||||
|
// behavior is to treat the value as a pair and return the first element.
|
||||||
|
template <typename K, typename V>
|
||||||
|
struct KeyOfValue {
|
||||||
|
struct type {
|
||||||
|
const K& operator()(const V& p) const { return p.first; }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Partial specialization of KeyOfValue class for when the key and value are
|
||||||
|
// the same type such as in set<> and btree_set<>.
|
||||||
|
template <typename K>
|
||||||
|
struct KeyOfValue<K, K> {
|
||||||
|
struct type {
|
||||||
|
const K& operator()(const K& k) const { return k; }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
inline char* GenerateDigits(char buf[16], unsigned val, unsigned maxval) {
|
||||||
|
assert(val <= maxval);
|
||||||
|
constexpr unsigned kBase = 64; // avoid integer division.
|
||||||
|
unsigned p = 15;
|
||||||
|
buf[p--] = 0;
|
||||||
|
while (maxval > 0) {
|
||||||
|
buf[p--] = ' ' + (val % kBase);
|
||||||
|
val /= kBase;
|
||||||
|
maxval /= kBase;
|
||||||
|
}
|
||||||
|
return buf + p + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
struct Generator {
|
||||||
|
int maxval;
|
||||||
|
explicit Generator(int m) : maxval(m) {}
|
||||||
|
K operator()(int i) const {
|
||||||
|
assert(i <= maxval);
|
||||||
|
return K(i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Generator<absl::Time> {
|
||||||
|
int maxval;
|
||||||
|
explicit Generator(int m) : maxval(m) {}
|
||||||
|
absl::Time operator()(int i) const { return absl::FromUnixMillis(i); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Generator<std::string> {
|
||||||
|
int maxval;
|
||||||
|
explicit Generator(int m) : maxval(m) {}
|
||||||
|
std::string operator()(int i) const {
|
||||||
|
char buf[16];
|
||||||
|
return GenerateDigits(buf, i, maxval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Generator<Cord> {
|
||||||
|
int maxval;
|
||||||
|
explicit Generator(int m) : maxval(m) {}
|
||||||
|
Cord operator()(int i) const {
|
||||||
|
char buf[16];
|
||||||
|
return Cord(GenerateDigits(buf, i, maxval));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
struct Generator<std::pair<T, U> > {
|
||||||
|
Generator<typename remove_pair_const<T>::type> tgen;
|
||||||
|
Generator<typename remove_pair_const<U>::type> ugen;
|
||||||
|
|
||||||
|
explicit Generator(int m) : tgen(m), ugen(m) {}
|
||||||
|
std::pair<T, U> operator()(int i) const {
|
||||||
|
return std::make_pair(tgen(i), ugen(i));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate n values for our tests and benchmarks. Value range is [0, maxval].
|
||||||
|
inline std::vector<int> GenerateNumbersWithSeed(int n, int maxval, int seed) {
|
||||||
|
// NOTE: Some tests rely on generated numbers not changing between test runs.
|
||||||
|
// We use std::minstd_rand0 because it is well-defined, but don't use
|
||||||
|
// std::uniform_int_distribution because platforms use different algorithms.
|
||||||
|
std::minstd_rand0 rng(seed);
|
||||||
|
|
||||||
|
std::vector<int> values;
|
||||||
|
absl::flat_hash_set<int> unique_values;
|
||||||
|
if (values.size() < n) {
|
||||||
|
for (int i = values.size(); i < n; i++) {
|
||||||
|
int value;
|
||||||
|
do {
|
||||||
|
value = static_cast<int>(rng()) % (maxval + 1);
|
||||||
|
} while (!unique_values.insert(value).second);
|
||||||
|
|
||||||
|
values.push_back(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates n values in the range [0, maxval].
|
||||||
|
template <typename V>
|
||||||
|
std::vector<V> GenerateValuesWithSeed(int n, int maxval, int seed) {
|
||||||
|
const std::vector<int> nums = GenerateNumbersWithSeed(n, maxval, seed);
|
||||||
|
Generator<V> gen(maxval);
|
||||||
|
std::vector<V> vec;
|
||||||
|
|
||||||
|
vec.reserve(n);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
vec.push_back(gen(nums[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace container_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_CONTAINER_BTREE_TEST_H_
|
||||||
529
include/absl/container/fixed_array.h
Normal file
@ -0,0 +1,529 @@
|
|||||||
|
// Copyright 2018 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: fixed_array.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// A `FixedArray<T>` represents a non-resizable array of `T` where the length of
|
||||||
|
// the array can be determined at run-time. It is a good replacement for
|
||||||
|
// non-standard and deprecated uses of `alloca()` and variable length arrays
|
||||||
|
// within the GCC extension. (See
|
||||||
|
// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html).
|
||||||
|
//
|
||||||
|
// `FixedArray` allocates small arrays inline, keeping performance fast by
|
||||||
|
// avoiding heap operations. It also helps reduce the chances of
|
||||||
|
// accidentally overflowing your stack if large input is passed to
|
||||||
|
// your function.
|
||||||
|
|
||||||
|
#ifndef ABSL_CONTAINER_FIXED_ARRAY_H_
|
||||||
|
#define ABSL_CONTAINER_FIXED_ARRAY_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <iterator>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
#include <new>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "absl/algorithm/algorithm.h"
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
#include "absl/base/dynamic_annotations.h"
|
||||||
|
#include "absl/base/internal/throw_delegate.h"
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/base/optimization.h"
|
||||||
|
#include "absl/base/port.h"
|
||||||
|
#include "absl/container/internal/compressed_tuple.h"
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// FixedArray
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// A `FixedArray` provides a run-time fixed-size array, allocating a small array
|
||||||
|
// inline for efficiency.
|
||||||
|
//
|
||||||
|
// Most users should not specify an `inline_elements` argument and let
|
||||||
|
// `FixedArray` automatically determine the number of elements
|
||||||
|
// to store inline based on `sizeof(T)`. If `inline_elements` is specified, the
|
||||||
|
// `FixedArray` implementation will use inline storage for arrays with a
|
||||||
|
// length <= `inline_elements`.
|
||||||
|
//
|
||||||
|
// Note that a `FixedArray` constructed with a `size_type` argument will
|
||||||
|
// default-initialize its values by leaving trivially constructible types
|
||||||
|
// uninitialized (e.g. int, int[4], double), and others default-constructed.
|
||||||
|
// This matches the behavior of c-style arrays and `std::array`, but not
|
||||||
|
// `std::vector`.
|
||||||
|
template <typename T, size_t N = kFixedArrayUseDefault,
|
||||||
|
typename A = std::allocator<T>>
|
||||||
|
class FixedArray {
|
||||||
|
static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
|
||||||
|
"Arrays with unknown bounds cannot be used with FixedArray.");
|
||||||
|
|
||||||
|
static constexpr size_t kInlineBytesDefault = 256;
|
||||||
|
|
||||||
|
using AllocatorTraits = std::allocator_traits<A>;
|
||||||
|
// std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
|
||||||
|
// but this seems to be mostly pedantic.
|
||||||
|
template <typename Iterator>
|
||||||
|
using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
|
||||||
|
typename std::iterator_traits<Iterator>::iterator_category,
|
||||||
|
std::forward_iterator_tag>::value>;
|
||||||
|
static constexpr bool NoexceptCopyable() {
|
||||||
|
return std::is_nothrow_copy_constructible<StorageElement>::value &&
|
||||||
|
absl::allocator_is_nothrow<allocator_type>::value;
|
||||||
|
}
|
||||||
|
static constexpr bool NoexceptMovable() {
|
||||||
|
return std::is_nothrow_move_constructible<StorageElement>::value &&
|
||||||
|
absl::allocator_is_nothrow<allocator_type>::value;
|
||||||
|
}
|
||||||
|
static constexpr bool DefaultConstructorIsNonTrivial() {
|
||||||
|
return !absl::is_trivially_default_constructible<StorageElement>::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using allocator_type = typename AllocatorTraits::allocator_type;
|
||||||
|
using value_type = typename AllocatorTraits::value_type;
|
||||||
|
using pointer = typename AllocatorTraits::pointer;
|
||||||
|
using const_pointer = typename AllocatorTraits::const_pointer;
|
||||||
|
using reference = value_type&;
|
||||||
|
using const_reference = const value_type&;
|
||||||
|
using size_type = typename AllocatorTraits::size_type;
|
||||||
|
using difference_type = typename AllocatorTraits::difference_type;
|
||||||
|
using iterator = pointer;
|
||||||
|
using const_iterator = const_pointer;
|
||||||
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||||
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
|
||||||
|
static constexpr size_type inline_elements =
|
||||||
|
(N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
|
||||||
|
: static_cast<size_type>(N));
|
||||||
|
|
||||||
|
FixedArray(
|
||||||
|
const FixedArray& other,
|
||||||
|
const allocator_type& a = allocator_type()) noexcept(NoexceptCopyable())
|
||||||
|
: FixedArray(other.begin(), other.end(), a) {}
|
||||||
|
|
||||||
|
FixedArray(
|
||||||
|
FixedArray&& other,
|
||||||
|
const allocator_type& a = allocator_type()) noexcept(NoexceptMovable())
|
||||||
|
: FixedArray(std::make_move_iterator(other.begin()),
|
||||||
|
std::make_move_iterator(other.end()), a) {}
|
||||||
|
|
||||||
|
// Creates an array object that can store `n` elements.
|
||||||
|
// Note that trivially constructible elements will be uninitialized.
|
||||||
|
explicit FixedArray(size_type n, const allocator_type& a = allocator_type())
|
||||||
|
: storage_(n, a) {
|
||||||
|
if (DefaultConstructorIsNonTrivial()) {
|
||||||
|
memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
|
||||||
|
storage_.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an array initialized with `n` copies of `val`.
|
||||||
|
FixedArray(size_type n, const value_type& val,
|
||||||
|
const allocator_type& a = allocator_type())
|
||||||
|
: storage_(n, a) {
|
||||||
|
memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
|
||||||
|
storage_.end(), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an array initialized with the size and contents of `init_list`.
|
||||||
|
FixedArray(std::initializer_list<value_type> init_list,
|
||||||
|
const allocator_type& a = allocator_type())
|
||||||
|
: FixedArray(init_list.begin(), init_list.end(), a) {}
|
||||||
|
|
||||||
|
// Creates an array initialized with the elements from the input
|
||||||
|
// range. The array's size will always be `std::distance(first, last)`.
|
||||||
|
// REQUIRES: Iterator must be a forward_iterator or better.
|
||||||
|
template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
|
||||||
|
FixedArray(Iterator first, Iterator last,
|
||||||
|
const allocator_type& a = allocator_type())
|
||||||
|
: storage_(std::distance(first, last), a) {
|
||||||
|
memory_internal::CopyRange(storage_.alloc(), storage_.begin(), first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
~FixedArray() noexcept {
|
||||||
|
for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) {
|
||||||
|
AllocatorTraits::destroy(storage_.alloc(), cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assignments are deleted because they break the invariant that the size of a
|
||||||
|
// `FixedArray` never changes.
|
||||||
|
void operator=(FixedArray&&) = delete;
|
||||||
|
void operator=(const FixedArray&) = delete;
|
||||||
|
|
||||||
|
// FixedArray::size()
|
||||||
|
//
|
||||||
|
// Returns the length of the fixed array.
|
||||||
|
size_type size() const { return storage_.size(); }
|
||||||
|
|
||||||
|
// FixedArray::max_size()
|
||||||
|
//
|
||||||
|
// Returns the largest possible value of `std::distance(begin(), end())` for a
|
||||||
|
// `FixedArray<T>`. This is equivalent to the most possible addressable bytes
|
||||||
|
// over the number of bytes taken by T.
|
||||||
|
constexpr size_type max_size() const {
|
||||||
|
return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixedArray::empty()
|
||||||
|
//
|
||||||
|
// Returns whether or not the fixed array is empty.
|
||||||
|
bool empty() const { return size() == 0; }
|
||||||
|
|
||||||
|
// FixedArray::memsize()
|
||||||
|
//
|
||||||
|
// Returns the memory size of the fixed array in bytes.
|
||||||
|
size_t memsize() const { return size() * sizeof(value_type); }
|
||||||
|
|
||||||
|
// FixedArray::data()
|
||||||
|
//
|
||||||
|
// Returns a const T* pointer to elements of the `FixedArray`. This pointer
|
||||||
|
// can be used to access (but not modify) the contained elements.
|
||||||
|
const_pointer data() const { return AsValueType(storage_.begin()); }
|
||||||
|
|
||||||
|
// Overload of FixedArray::data() to return a T* pointer to elements of the
|
||||||
|
// fixed array. This pointer can be used to access and modify the contained
|
||||||
|
// elements.
|
||||||
|
pointer data() { return AsValueType(storage_.begin()); }
|
||||||
|
|
||||||
|
// FixedArray::operator[]
|
||||||
|
//
|
||||||
|
// Returns a reference the ith element of the fixed array.
|
||||||
|
// REQUIRES: 0 <= i < size()
|
||||||
|
reference operator[](size_type i) {
|
||||||
|
ABSL_HARDENING_ASSERT(i < size());
|
||||||
|
return data()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of FixedArray::operator()[] to return a const reference to the
|
||||||
|
// ith element of the fixed array.
|
||||||
|
// REQUIRES: 0 <= i < size()
|
||||||
|
const_reference operator[](size_type i) const {
|
||||||
|
ABSL_HARDENING_ASSERT(i < size());
|
||||||
|
return data()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixedArray::at
|
||||||
|
//
|
||||||
|
// Bounds-checked access. Returns a reference to the ith element of the fixed
|
||||||
|
// array, or throws std::out_of_range
|
||||||
|
reference at(size_type i) {
|
||||||
|
if (ABSL_PREDICT_FALSE(i >= size())) {
|
||||||
|
base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
|
||||||
|
}
|
||||||
|
return data()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of FixedArray::at() to return a const reference to the ith element
|
||||||
|
// of the fixed array.
|
||||||
|
const_reference at(size_type i) const {
|
||||||
|
if (ABSL_PREDICT_FALSE(i >= size())) {
|
||||||
|
base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
|
||||||
|
}
|
||||||
|
return data()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixedArray::front()
|
||||||
|
//
|
||||||
|
// Returns a reference to the first element of the fixed array.
|
||||||
|
reference front() {
|
||||||
|
ABSL_HARDENING_ASSERT(!empty());
|
||||||
|
return data()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of FixedArray::front() to return a reference to the first element
|
||||||
|
// of a fixed array of const values.
|
||||||
|
const_reference front() const {
|
||||||
|
ABSL_HARDENING_ASSERT(!empty());
|
||||||
|
return data()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixedArray::back()
|
||||||
|
//
|
||||||
|
// Returns a reference to the last element of the fixed array.
|
||||||
|
reference back() {
|
||||||
|
ABSL_HARDENING_ASSERT(!empty());
|
||||||
|
return data()[size() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of FixedArray::back() to return a reference to the last element
|
||||||
|
// of a fixed array of const values.
|
||||||
|
const_reference back() const {
|
||||||
|
ABSL_HARDENING_ASSERT(!empty());
|
||||||
|
return data()[size() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixedArray::begin()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the beginning of the fixed array.
|
||||||
|
iterator begin() { return data(); }
|
||||||
|
|
||||||
|
// Overload of FixedArray::begin() to return a const iterator to the
|
||||||
|
// beginning of the fixed array.
|
||||||
|
const_iterator begin() const { return data(); }
|
||||||
|
|
||||||
|
// FixedArray::cbegin()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the beginning of the fixed array.
|
||||||
|
const_iterator cbegin() const { return begin(); }
|
||||||
|
|
||||||
|
// FixedArray::end()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the end of the fixed array.
|
||||||
|
iterator end() { return data() + size(); }
|
||||||
|
|
||||||
|
// Overload of FixedArray::end() to return a const iterator to the end of the
|
||||||
|
// fixed array.
|
||||||
|
const_iterator end() const { return data() + size(); }
|
||||||
|
|
||||||
|
// FixedArray::cend()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the end of the fixed array.
|
||||||
|
const_iterator cend() const { return end(); }
|
||||||
|
|
||||||
|
// FixedArray::rbegin()
|
||||||
|
//
|
||||||
|
// Returns a reverse iterator from the end of the fixed array.
|
||||||
|
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||||
|
|
||||||
|
// Overload of FixedArray::rbegin() to return a const reverse iterator from
|
||||||
|
// the end of the fixed array.
|
||||||
|
const_reverse_iterator rbegin() const {
|
||||||
|
return const_reverse_iterator(end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixedArray::crbegin()
|
||||||
|
//
|
||||||
|
// Returns a const reverse iterator from the end of the fixed array.
|
||||||
|
const_reverse_iterator crbegin() const { return rbegin(); }
|
||||||
|
|
||||||
|
// FixedArray::rend()
|
||||||
|
//
|
||||||
|
// Returns a reverse iterator from the beginning of the fixed array.
|
||||||
|
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||||
|
|
||||||
|
// Overload of FixedArray::rend() for returning a const reverse iterator
|
||||||
|
// from the beginning of the fixed array.
|
||||||
|
const_reverse_iterator rend() const {
|
||||||
|
return const_reverse_iterator(begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixedArray::crend()
|
||||||
|
//
|
||||||
|
// Returns a reverse iterator from the beginning of the fixed array.
|
||||||
|
const_reverse_iterator crend() const { return rend(); }
|
||||||
|
|
||||||
|
// FixedArray::fill()
|
||||||
|
//
|
||||||
|
// Assigns the given `value` to all elements in the fixed array.
|
||||||
|
void fill(const value_type& val) { std::fill(begin(), end(), val); }
|
||||||
|
|
||||||
|
// Relational operators. Equality operators are elementwise using
|
||||||
|
// `operator==`, while order operators order FixedArrays lexicographically.
|
||||||
|
friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) {
|
||||||
|
return absl::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) {
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) {
|
||||||
|
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
|
||||||
|
rhs.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) {
|
||||||
|
return rhs < lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) {
|
||||||
|
return !(rhs < lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
|
||||||
|
return !(lhs < rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename H>
|
||||||
|
friend H AbslHashValue(H h, const FixedArray& v) {
|
||||||
|
return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
|
||||||
|
v.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// StorageElement
|
||||||
|
//
|
||||||
|
// For FixedArrays with a C-style-array value_type, StorageElement is a POD
|
||||||
|
// wrapper struct called StorageElementWrapper that holds the value_type
|
||||||
|
// instance inside. This is needed for construction and destruction of the
|
||||||
|
// entire array regardless of how many dimensions it has. For all other cases,
|
||||||
|
// StorageElement is just an alias of value_type.
|
||||||
|
//
|
||||||
|
// Maintainer's Note: The simpler solution would be to simply wrap value_type
|
||||||
|
// in a struct whether it's an array or not. That causes some paranoid
|
||||||
|
// diagnostics to misfire, believing that 'data()' returns a pointer to a
|
||||||
|
// single element, rather than the packed array that it really is.
|
||||||
|
// e.g.:
|
||||||
|
//
|
||||||
|
// FixedArray<char> buf(1);
|
||||||
|
// sprintf(buf.data(), "foo");
|
||||||
|
//
|
||||||
|
// error: call to int __builtin___sprintf_chk(etc...)
|
||||||
|
// will always overflow destination buffer [-Werror]
|
||||||
|
//
|
||||||
|
template <typename OuterT, typename InnerT = absl::remove_extent_t<OuterT>,
|
||||||
|
size_t InnerN = std::extent<OuterT>::value>
|
||||||
|
struct StorageElementWrapper {
|
||||||
|
InnerT array[InnerN];
|
||||||
|
};
|
||||||
|
|
||||||
|
using StorageElement =
|
||||||
|
absl::conditional_t<std::is_array<value_type>::value,
|
||||||
|
StorageElementWrapper<value_type>, value_type>;
|
||||||
|
|
||||||
|
static pointer AsValueType(pointer ptr) { return ptr; }
|
||||||
|
static pointer AsValueType(StorageElementWrapper<value_type>* ptr) {
|
||||||
|
return std::addressof(ptr->array);
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(sizeof(StorageElement) == sizeof(value_type), "");
|
||||||
|
static_assert(alignof(StorageElement) == alignof(value_type), "");
|
||||||
|
|
||||||
|
class NonEmptyInlinedStorage {
|
||||||
|
public:
|
||||||
|
StorageElement* data() { return reinterpret_cast<StorageElement*>(buff_); }
|
||||||
|
void AnnotateConstruct(size_type n);
|
||||||
|
void AnnotateDestruct(size_type n);
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
void* RedzoneBegin() { return &redzone_begin_; }
|
||||||
|
void* RedzoneEnd() { return &redzone_end_ + 1; }
|
||||||
|
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
|
||||||
|
private:
|
||||||
|
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
|
||||||
|
alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
|
||||||
|
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
|
||||||
|
};
|
||||||
|
|
||||||
|
class EmptyInlinedStorage {
|
||||||
|
public:
|
||||||
|
StorageElement* data() { return nullptr; }
|
||||||
|
void AnnotateConstruct(size_type) {}
|
||||||
|
void AnnotateDestruct(size_type) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
using InlinedStorage =
|
||||||
|
absl::conditional_t<inline_elements == 0, EmptyInlinedStorage,
|
||||||
|
NonEmptyInlinedStorage>;
|
||||||
|
|
||||||
|
// Storage
|
||||||
|
//
|
||||||
|
// An instance of Storage manages the inline and out-of-line memory for
|
||||||
|
// instances of FixedArray. This guarantees that even when construction of
|
||||||
|
// individual elements fails in the FixedArray constructor body, the
|
||||||
|
// destructor for Storage will still be called and out-of-line memory will be
|
||||||
|
// properly deallocated.
|
||||||
|
//
|
||||||
|
class Storage : public InlinedStorage {
|
||||||
|
public:
|
||||||
|
Storage(size_type n, const allocator_type& a)
|
||||||
|
: size_alloc_(n, a), data_(InitializeData()) {}
|
||||||
|
|
||||||
|
~Storage() noexcept {
|
||||||
|
if (UsingInlinedStorage(size())) {
|
||||||
|
InlinedStorage::AnnotateDestruct(size());
|
||||||
|
} else {
|
||||||
|
AllocatorTraits::deallocate(alloc(), AsValueType(begin()), size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type size() const { return size_alloc_.template get<0>(); }
|
||||||
|
StorageElement* begin() const { return data_; }
|
||||||
|
StorageElement* end() const { return begin() + size(); }
|
||||||
|
allocator_type& alloc() { return size_alloc_.template get<1>(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool UsingInlinedStorage(size_type n) {
|
||||||
|
return n <= inline_elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageElement* InitializeData() {
|
||||||
|
if (UsingInlinedStorage(size())) {
|
||||||
|
InlinedStorage::AnnotateConstruct(size());
|
||||||
|
return InlinedStorage::data();
|
||||||
|
} else {
|
||||||
|
return reinterpret_cast<StorageElement*>(
|
||||||
|
AllocatorTraits::allocate(alloc(), size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `CompressedTuple` takes advantage of EBCO for stateless `allocator_type`s
|
||||||
|
container_internal::CompressedTuple<size_type, allocator_type> size_alloc_;
|
||||||
|
StorageElement* data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
Storage storage_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;
|
||||||
|
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
constexpr typename FixedArray<T, N, A>::size_type
|
||||||
|
FixedArray<T, N, A>::inline_elements;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
|
||||||
|
typename FixedArray<T, N, A>::size_type n) {
|
||||||
|
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
if (!n) return;
|
||||||
|
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(),
|
||||||
|
data() + n);
|
||||||
|
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(),
|
||||||
|
RedzoneBegin());
|
||||||
|
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
static_cast<void>(n); // Mark used when not in asan mode
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
|
||||||
|
typename FixedArray<T, N, A>::size_type n) {
|
||||||
|
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
if (!n) return;
|
||||||
|
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n,
|
||||||
|
RedzoneEnd());
|
||||||
|
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(),
|
||||||
|
data());
|
||||||
|
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||||
|
static_cast<void>(n); // Mark used when not in asan mode
|
||||||
|
}
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_CONTAINER_FIXED_ARRAY_H_
|
||||||
613
include/absl/container/flat_hash_map.h
Normal file
@ -0,0 +1,613 @@
|
|||||||
|
// Copyright 2018 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: flat_hash_map.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// An `absl::flat_hash_map<K, V>` is an unordered associative container of
|
||||||
|
// unique keys and associated values designed to be a more efficient replacement
|
||||||
|
// for `std::unordered_map`. Like `unordered_map`, search, insertion, and
|
||||||
|
// deletion of map elements can be done as an `O(1)` operation. However,
|
||||||
|
// `flat_hash_map` (and other unordered associative containers known as the
|
||||||
|
// collection of Abseil "Swiss tables") contain other optimizations that result
|
||||||
|
// in both memory and computation advantages.
|
||||||
|
//
|
||||||
|
// In most cases, your default choice for a hash map should be a map of type
|
||||||
|
// `flat_hash_map`.
|
||||||
|
|
||||||
|
#ifndef ABSL_CONTAINER_FLAT_HASH_MAP_H_
|
||||||
|
#define ABSL_CONTAINER_FLAT_HASH_MAP_H_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <new>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "absl/algorithm/container.h"
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/container/internal/container_memory.h"
|
||||||
|
#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
|
||||||
|
#include "absl/container/internal/raw_hash_map.h" // IWYU pragma: export
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace container_internal {
|
||||||
|
template <class K, class V>
|
||||||
|
struct FlatHashMapPolicy;
|
||||||
|
} // namespace container_internal
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// absl::flat_hash_map
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// An `absl::flat_hash_map<K, V>` is an unordered associative container which
|
||||||
|
// has been optimized for both speed and memory footprint in most common use
|
||||||
|
// cases. Its interface is similar to that of `std::unordered_map<K, V>` with
|
||||||
|
// the following notable differences:
|
||||||
|
//
|
||||||
|
// * Requires keys that are CopyConstructible
|
||||||
|
// * Requires values that are MoveConstructible
|
||||||
|
// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
|
||||||
|
// `insert()`, provided that the map is provided a compatible heterogeneous
|
||||||
|
// hashing function and equality operator.
|
||||||
|
// * Invalidates any references and pointers to elements within the table after
|
||||||
|
// `rehash()`.
|
||||||
|
// * Contains a `capacity()` member function indicating the number of element
|
||||||
|
// slots (open, deleted, and empty) within the hash map.
|
||||||
|
// * Returns `void` from the `erase(iterator)` overload.
|
||||||
|
//
|
||||||
|
// By default, `flat_hash_map` uses the `absl::Hash` hashing framework.
|
||||||
|
// All fundamental and Abseil types that support the `absl::Hash` framework have
|
||||||
|
// a compatible equality operator for comparing insertions into `flat_hash_map`.
|
||||||
|
// If your type is not yet supported by the `absl::Hash` framework, see
|
||||||
|
// absl/hash/hash.h for information on extending Abseil hashing to user-defined
|
||||||
|
// types.
|
||||||
|
//
|
||||||
|
// Using `absl::flat_hash_map` at interface boundaries in dynamically loaded
|
||||||
|
// libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may
|
||||||
|
// be randomized across dynamically loaded libraries.
|
||||||
|
//
|
||||||
|
// NOTE: A `flat_hash_map` stores its value types directly inside its
|
||||||
|
// implementation array to avoid memory indirection. Because a `flat_hash_map`
|
||||||
|
// is designed to move data when rehashed, map values will not retain pointer
|
||||||
|
// stability. If you require pointer stability, or if your values are large,
|
||||||
|
// consider using `absl::flat_hash_map<Key, std::unique_ptr<Value>>` instead.
|
||||||
|
// If your types are not moveable or you require pointer stability for keys,
|
||||||
|
// consider `absl::node_hash_map`.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // Create a flat hash map of three strings (that map to strings)
|
||||||
|
// absl::flat_hash_map<std::string, std::string> ducks =
|
||||||
|
// {{"a", "huey"}, {"b", "dewey"}, {"c", "louie"}};
|
||||||
|
//
|
||||||
|
// // Insert a new element into the flat hash map
|
||||||
|
// ducks.insert({"d", "donald"});
|
||||||
|
//
|
||||||
|
// // Force a rehash of the flat hash map
|
||||||
|
// ducks.rehash(0);
|
||||||
|
//
|
||||||
|
// // Find the element with the key "b"
|
||||||
|
// std::string search_key = "b";
|
||||||
|
// auto result = ducks.find(search_key);
|
||||||
|
// if (result != ducks.end()) {
|
||||||
|
// std::cout << "Result: " << result->second << std::endl;
|
||||||
|
// }
|
||||||
|
template <class K, class V,
|
||||||
|
class Hash = absl::container_internal::hash_default_hash<K>,
|
||||||
|
class Eq = absl::container_internal::hash_default_eq<K>,
|
||||||
|
class Allocator = std::allocator<std::pair<const K, V>>>
|
||||||
|
class flat_hash_map : public absl::container_internal::raw_hash_map<
|
||||||
|
absl::container_internal::FlatHashMapPolicy<K, V>,
|
||||||
|
Hash, Eq, Allocator> {
|
||||||
|
using Base = typename flat_hash_map::raw_hash_map;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors and Assignment Operators
|
||||||
|
//
|
||||||
|
// A flat_hash_map supports the same overload set as `std::unordered_map`
|
||||||
|
// for construction and assignment:
|
||||||
|
//
|
||||||
|
// * Default constructor
|
||||||
|
//
|
||||||
|
// // No allocation for the table's elements is made.
|
||||||
|
// absl::flat_hash_map<int, std::string> map1;
|
||||||
|
//
|
||||||
|
// * Initializer List constructor
|
||||||
|
//
|
||||||
|
// absl::flat_hash_map<int, std::string> map2 =
|
||||||
|
// {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
|
||||||
|
//
|
||||||
|
// * Copy constructor
|
||||||
|
//
|
||||||
|
// absl::flat_hash_map<int, std::string> map3(map2);
|
||||||
|
//
|
||||||
|
// * Copy assignment operator
|
||||||
|
//
|
||||||
|
// // Hash functor and Comparator are copied as well
|
||||||
|
// absl::flat_hash_map<int, std::string> map4;
|
||||||
|
// map4 = map3;
|
||||||
|
//
|
||||||
|
// * Move constructor
|
||||||
|
//
|
||||||
|
// // Move is guaranteed efficient
|
||||||
|
// absl::flat_hash_map<int, std::string> map5(std::move(map4));
|
||||||
|
//
|
||||||
|
// * Move assignment operator
|
||||||
|
//
|
||||||
|
// // May be efficient if allocators are compatible
|
||||||
|
// absl::flat_hash_map<int, std::string> map6;
|
||||||
|
// map6 = std::move(map5);
|
||||||
|
//
|
||||||
|
// * Range constructor
|
||||||
|
//
|
||||||
|
// std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
|
||||||
|
// absl::flat_hash_map<int, std::string> map7(v.begin(), v.end());
|
||||||
|
flat_hash_map() {}
|
||||||
|
using Base::Base;
|
||||||
|
|
||||||
|
// flat_hash_map::begin()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the beginning of the `flat_hash_map`.
|
||||||
|
using Base::begin;
|
||||||
|
|
||||||
|
// flat_hash_map::cbegin()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the beginning of the `flat_hash_map`.
|
||||||
|
using Base::cbegin;
|
||||||
|
|
||||||
|
// flat_hash_map::cend()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the end of the `flat_hash_map`.
|
||||||
|
using Base::cend;
|
||||||
|
|
||||||
|
// flat_hash_map::end()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the end of the `flat_hash_map`.
|
||||||
|
using Base::end;
|
||||||
|
|
||||||
|
// flat_hash_map::capacity()
|
||||||
|
//
|
||||||
|
// Returns the number of element slots (assigned, deleted, and empty)
|
||||||
|
// available within the `flat_hash_map`.
|
||||||
|
//
|
||||||
|
// NOTE: this member function is particular to `absl::flat_hash_map` and is
|
||||||
|
// not provided in the `std::unordered_map` API.
|
||||||
|
using Base::capacity;
|
||||||
|
|
||||||
|
// flat_hash_map::empty()
|
||||||
|
//
|
||||||
|
// Returns whether or not the `flat_hash_map` is empty.
|
||||||
|
using Base::empty;
|
||||||
|
|
||||||
|
// flat_hash_map::max_size()
|
||||||
|
//
|
||||||
|
// Returns the largest theoretical possible number of elements within a
|
||||||
|
// `flat_hash_map` under current memory constraints. This value can be thought
|
||||||
|
// of the largest value of `std::distance(begin(), end())` for a
|
||||||
|
// `flat_hash_map<K, V>`.
|
||||||
|
using Base::max_size;
|
||||||
|
|
||||||
|
// flat_hash_map::size()
|
||||||
|
//
|
||||||
|
// Returns the number of elements currently within the `flat_hash_map`.
|
||||||
|
using Base::size;
|
||||||
|
|
||||||
|
// flat_hash_map::clear()
|
||||||
|
//
|
||||||
|
// Removes all elements from the `flat_hash_map`. Invalidates any references,
|
||||||
|
// pointers, or iterators referring to contained elements.
|
||||||
|
//
|
||||||
|
// NOTE: this operation may shrink the underlying buffer. To avoid shrinking
|
||||||
|
// the underlying buffer call `erase(begin(), end())`.
|
||||||
|
using Base::clear;
|
||||||
|
|
||||||
|
// flat_hash_map::erase()
|
||||||
|
//
|
||||||
|
// Erases elements within the `flat_hash_map`. Erasing does not trigger a
|
||||||
|
// rehash. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// void erase(const_iterator pos):
|
||||||
|
//
|
||||||
|
// Erases the element at `position` of the `flat_hash_map`, returning
|
||||||
|
// `void`.
|
||||||
|
//
|
||||||
|
// NOTE: returning `void` in this case is different than that of STL
|
||||||
|
// containers in general and `std::unordered_map` in particular (which
|
||||||
|
// return an iterator to the element following the erased element). If that
|
||||||
|
// iterator is needed, simply post increment the iterator:
|
||||||
|
//
|
||||||
|
// map.erase(it++);
|
||||||
|
//
|
||||||
|
// iterator erase(const_iterator first, const_iterator last):
|
||||||
|
//
|
||||||
|
// Erases the elements in the open interval [`first`, `last`), returning an
|
||||||
|
// iterator pointing to `last`.
|
||||||
|
//
|
||||||
|
// size_type erase(const key_type& key):
|
||||||
|
//
|
||||||
|
// Erases the element with the matching key, if it exists, returning the
|
||||||
|
// number of elements erased (0 or 1).
|
||||||
|
using Base::erase;
|
||||||
|
|
||||||
|
// flat_hash_map::insert()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value into the `flat_hash_map`,
|
||||||
|
// returning an iterator pointing to the newly inserted element, provided that
|
||||||
|
// an element with the given key does not already exist. If rehashing occurs
|
||||||
|
// due to the insertion, all iterators are invalidated. Overloads are listed
|
||||||
|
// below.
|
||||||
|
//
|
||||||
|
// std::pair<iterator,bool> insert(const init_type& value):
|
||||||
|
//
|
||||||
|
// Inserts a value into the `flat_hash_map`. Returns a pair consisting of an
|
||||||
|
// iterator to the inserted element (or to the element that prevented the
|
||||||
|
// insertion) and a bool denoting whether the insertion took place.
|
||||||
|
//
|
||||||
|
// std::pair<iterator,bool> insert(T&& value):
|
||||||
|
// std::pair<iterator,bool> insert(init_type&& value):
|
||||||
|
//
|
||||||
|
// Inserts a moveable value into the `flat_hash_map`. Returns a pair
|
||||||
|
// consisting of an iterator to the inserted element (or to the element that
|
||||||
|
// prevented the insertion) and a bool denoting whether the insertion took
|
||||||
|
// place.
|
||||||
|
//
|
||||||
|
// iterator insert(const_iterator hint, const init_type& value):
|
||||||
|
// iterator insert(const_iterator hint, T&& value):
|
||||||
|
// iterator insert(const_iterator hint, init_type&& value);
|
||||||
|
//
|
||||||
|
// Inserts a value, using the position of `hint` as a non-binding suggestion
|
||||||
|
// for where to begin the insertion search. Returns an iterator to the
|
||||||
|
// inserted element, or to the existing element that prevented the
|
||||||
|
// insertion.
|
||||||
|
//
|
||||||
|
// void insert(InputIterator first, InputIterator last):
|
||||||
|
//
|
||||||
|
// Inserts a range of values [`first`, `last`).
|
||||||
|
//
|
||||||
|
// NOTE: Although the STL does not specify which element may be inserted if
|
||||||
|
// multiple keys compare equivalently, for `flat_hash_map` we guarantee the
|
||||||
|
// first match is inserted.
|
||||||
|
//
|
||||||
|
// void insert(std::initializer_list<init_type> ilist):
|
||||||
|
//
|
||||||
|
// Inserts the elements within the initializer list `ilist`.
|
||||||
|
//
|
||||||
|
// NOTE: Although the STL does not specify which element may be inserted if
|
||||||
|
// multiple keys compare equivalently within the initializer list, for
|
||||||
|
// `flat_hash_map` we guarantee the first match is inserted.
|
||||||
|
using Base::insert;
|
||||||
|
|
||||||
|
// flat_hash_map::insert_or_assign()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value into the `flat_hash_map` provided
|
||||||
|
// that a value with the given key does not already exist, or replaces it with
|
||||||
|
// the element value if a key for that value already exists, returning an
|
||||||
|
// iterator pointing to the newly inserted element. If rehashing occurs due
|
||||||
|
// to the insertion, all existing iterators are invalidated. Overloads are
|
||||||
|
// listed below.
|
||||||
|
//
|
||||||
|
// pair<iterator, bool> insert_or_assign(const init_type& k, T&& obj):
|
||||||
|
// pair<iterator, bool> insert_or_assign(init_type&& k, T&& obj):
|
||||||
|
//
|
||||||
|
// Inserts/Assigns (or moves) the element of the specified key into the
|
||||||
|
// `flat_hash_map`.
|
||||||
|
//
|
||||||
|
// iterator insert_or_assign(const_iterator hint,
|
||||||
|
// const init_type& k, T&& obj):
|
||||||
|
// iterator insert_or_assign(const_iterator hint, init_type&& k, T&& obj):
|
||||||
|
//
|
||||||
|
// Inserts/Assigns (or moves) the element of the specified key into the
|
||||||
|
// `flat_hash_map` using the position of `hint` as a non-binding suggestion
|
||||||
|
// for where to begin the insertion search.
|
||||||
|
using Base::insert_or_assign;
|
||||||
|
|
||||||
|
// flat_hash_map::emplace()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `flat_hash_map`, provided that no element with the given key
|
||||||
|
// already exists.
|
||||||
|
//
|
||||||
|
// The element may be constructed even if there already is an element with the
|
||||||
|
// key in the container, in which case the newly constructed element will be
|
||||||
|
// destroyed immediately. Prefer `try_emplace()` unless your key is not
|
||||||
|
// copyable or moveable.
|
||||||
|
//
|
||||||
|
// If rehashing occurs due to the insertion, all iterators are invalidated.
|
||||||
|
using Base::emplace;
|
||||||
|
|
||||||
|
// flat_hash_map::emplace_hint()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `flat_hash_map`, using the position of `hint` as a non-binding
|
||||||
|
// suggestion for where to begin the insertion search, and only inserts
|
||||||
|
// provided that no element with the given key already exists.
|
||||||
|
//
|
||||||
|
// The element may be constructed even if there already is an element with the
|
||||||
|
// key in the container, in which case the newly constructed element will be
|
||||||
|
// destroyed immediately. Prefer `try_emplace()` unless your key is not
|
||||||
|
// copyable or moveable.
|
||||||
|
//
|
||||||
|
// If rehashing occurs due to the insertion, all iterators are invalidated.
|
||||||
|
using Base::emplace_hint;
|
||||||
|
|
||||||
|
// flat_hash_map::try_emplace()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `flat_hash_map`, provided that no element with the given key
|
||||||
|
// already exists. Unlike `emplace()`, if an element with the given key
|
||||||
|
// already exists, we guarantee that no element is constructed.
|
||||||
|
//
|
||||||
|
// If rehashing occurs due to the insertion, all iterators are invalidated.
|
||||||
|
// Overloads are listed below.
|
||||||
|
//
|
||||||
|
// pair<iterator, bool> try_emplace(const key_type& k, Args&&... args):
|
||||||
|
// pair<iterator, bool> try_emplace(key_type&& k, Args&&... args):
|
||||||
|
//
|
||||||
|
// Inserts (via copy or move) the element of the specified key into the
|
||||||
|
// `flat_hash_map`.
|
||||||
|
//
|
||||||
|
// iterator try_emplace(const_iterator hint,
|
||||||
|
// const key_type& k, Args&&... args):
|
||||||
|
// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args):
|
||||||
|
//
|
||||||
|
// Inserts (via copy or move) the element of the specified key into the
|
||||||
|
// `flat_hash_map` using the position of `hint` as a non-binding suggestion
|
||||||
|
// for where to begin the insertion search.
|
||||||
|
//
|
||||||
|
// All `try_emplace()` overloads make the same guarantees regarding rvalue
|
||||||
|
// arguments as `std::unordered_map::try_emplace()`, namely that these
|
||||||
|
// functions will not move from rvalue arguments if insertions do not happen.
|
||||||
|
using Base::try_emplace;
|
||||||
|
|
||||||
|
// flat_hash_map::extract()
|
||||||
|
//
|
||||||
|
// Extracts the indicated element, erasing it in the process, and returns it
|
||||||
|
// as a C++17-compatible node handle. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// node_type extract(const_iterator position):
|
||||||
|
//
|
||||||
|
// Extracts the key,value pair of the element at the indicated position and
|
||||||
|
// returns a node handle owning that extracted data.
|
||||||
|
//
|
||||||
|
// node_type extract(const key_type& x):
|
||||||
|
//
|
||||||
|
// Extracts the key,value pair of the element with a key matching the passed
|
||||||
|
// key value and returns a node handle owning that extracted data. If the
|
||||||
|
// `flat_hash_map` does not contain an element with a matching key, this
|
||||||
|
// function returns an empty node handle.
|
||||||
|
//
|
||||||
|
// NOTE: when compiled in an earlier version of C++ than C++17,
|
||||||
|
// `node_type::key()` returns a const reference to the key instead of a
|
||||||
|
// mutable reference. We cannot safely return a mutable reference without
|
||||||
|
// std::launder (which is not available before C++17).
|
||||||
|
using Base::extract;
|
||||||
|
|
||||||
|
// flat_hash_map::merge()
|
||||||
|
//
|
||||||
|
// Extracts elements from a given `source` flat hash map into this
|
||||||
|
// `flat_hash_map`. If the destination `flat_hash_map` already contains an
|
||||||
|
// element with an equivalent key, that element is not extracted.
|
||||||
|
using Base::merge;
|
||||||
|
|
||||||
|
// flat_hash_map::swap(flat_hash_map& other)
|
||||||
|
//
|
||||||
|
// Exchanges the contents of this `flat_hash_map` with those of the `other`
|
||||||
|
// flat hash map, avoiding invocation of any move, copy, or swap operations on
|
||||||
|
// individual elements.
|
||||||
|
//
|
||||||
|
// All iterators and references on the `flat_hash_map` remain valid, excepting
|
||||||
|
// for the past-the-end iterator, which is invalidated.
|
||||||
|
//
|
||||||
|
// `swap()` requires that the flat hash map's hashing and key equivalence
|
||||||
|
// functions be Swappable, and are exchanged using unqualified calls to
|
||||||
|
// non-member `swap()`. If the map's allocator has
|
||||||
|
// `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
|
||||||
|
// set to `true`, the allocators are also exchanged using an unqualified call
|
||||||
|
// to non-member `swap()`; otherwise, the allocators are not swapped.
|
||||||
|
using Base::swap;
|
||||||
|
|
||||||
|
// flat_hash_map::rehash(count)
|
||||||
|
//
|
||||||
|
// Rehashes the `flat_hash_map`, setting the number of slots to be at least
|
||||||
|
// the passed value. If the new number of slots increases the load factor more
|
||||||
|
// than the current maximum load factor
|
||||||
|
// (`count` < `size()` / `max_load_factor()`), then the new number of slots
|
||||||
|
// will be at least `size()` / `max_load_factor()`.
|
||||||
|
//
|
||||||
|
// To force a rehash, pass rehash(0).
|
||||||
|
//
|
||||||
|
// NOTE: unlike behavior in `std::unordered_map`, references are also
|
||||||
|
// invalidated upon a `rehash()`.
|
||||||
|
using Base::rehash;
|
||||||
|
|
||||||
|
// flat_hash_map::reserve(count)
|
||||||
|
//
|
||||||
|
// Sets the number of slots in the `flat_hash_map` to the number needed to
|
||||||
|
// accommodate at least `count` total elements without exceeding the current
|
||||||
|
// maximum load factor, and may rehash the container if needed.
|
||||||
|
using Base::reserve;
|
||||||
|
|
||||||
|
// flat_hash_map::at()
|
||||||
|
//
|
||||||
|
// Returns a reference to the mapped value of the element with key equivalent
|
||||||
|
// to the passed key.
|
||||||
|
using Base::at;
|
||||||
|
|
||||||
|
// flat_hash_map::contains()
|
||||||
|
//
|
||||||
|
// Determines whether an element with a key comparing equal to the given `key`
|
||||||
|
// exists within the `flat_hash_map`, returning `true` if so or `false`
|
||||||
|
// otherwise.
|
||||||
|
using Base::contains;
|
||||||
|
|
||||||
|
// flat_hash_map::count(const Key& key) const
|
||||||
|
//
|
||||||
|
// Returns the number of elements with a key comparing equal to the given
|
||||||
|
// `key` within the `flat_hash_map`. note that this function will return
|
||||||
|
// either `1` or `0` since duplicate keys are not allowed within a
|
||||||
|
// `flat_hash_map`.
|
||||||
|
using Base::count;
|
||||||
|
|
||||||
|
// flat_hash_map::equal_range()
|
||||||
|
//
|
||||||
|
// Returns a closed range [first, last], defined by a `std::pair` of two
|
||||||
|
// iterators, containing all elements with the passed key in the
|
||||||
|
// `flat_hash_map`.
|
||||||
|
using Base::equal_range;
|
||||||
|
|
||||||
|
// flat_hash_map::find()
|
||||||
|
//
|
||||||
|
// Finds an element with the passed `key` within the `flat_hash_map`.
|
||||||
|
using Base::find;
|
||||||
|
|
||||||
|
// flat_hash_map::operator[]()
|
||||||
|
//
|
||||||
|
// Returns a reference to the value mapped to the passed key within the
|
||||||
|
// `flat_hash_map`, performing an `insert()` if the key does not already
|
||||||
|
// exist.
|
||||||
|
//
|
||||||
|
// If an insertion occurs and results in a rehashing of the container, all
|
||||||
|
// iterators are invalidated. Otherwise iterators are not affected and
|
||||||
|
// references are not invalidated. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// T& operator[](const Key& key):
|
||||||
|
//
|
||||||
|
// Inserts an init_type object constructed in-place if the element with the
|
||||||
|
// given key does not exist.
|
||||||
|
//
|
||||||
|
// T& operator[](Key&& key):
|
||||||
|
//
|
||||||
|
// Inserts an init_type object constructed in-place provided that an element
|
||||||
|
// with the given key does not exist.
|
||||||
|
using Base::operator[];
|
||||||
|
|
||||||
|
// flat_hash_map::bucket_count()
|
||||||
|
//
|
||||||
|
// Returns the number of "buckets" within the `flat_hash_map`. Note that
|
||||||
|
// because a flat hash map contains all elements within its internal storage,
|
||||||
|
// this value simply equals the current capacity of the `flat_hash_map`.
|
||||||
|
using Base::bucket_count;
|
||||||
|
|
||||||
|
// flat_hash_map::load_factor()
|
||||||
|
//
|
||||||
|
// Returns the current load factor of the `flat_hash_map` (the average number
|
||||||
|
// of slots occupied with a value within the hash map).
|
||||||
|
using Base::load_factor;
|
||||||
|
|
||||||
|
// flat_hash_map::max_load_factor()
|
||||||
|
//
|
||||||
|
// Manages the maximum load factor of the `flat_hash_map`. Overloads are
|
||||||
|
// listed below.
|
||||||
|
//
|
||||||
|
// float flat_hash_map::max_load_factor()
|
||||||
|
//
|
||||||
|
// Returns the current maximum load factor of the `flat_hash_map`.
|
||||||
|
//
|
||||||
|
// void flat_hash_map::max_load_factor(float ml)
|
||||||
|
//
|
||||||
|
// Sets the maximum load factor of the `flat_hash_map` to the passed value.
|
||||||
|
//
|
||||||
|
// NOTE: This overload is provided only for API compatibility with the STL;
|
||||||
|
// `flat_hash_map` will ignore any set load factor and manage its rehashing
|
||||||
|
// internally as an implementation detail.
|
||||||
|
using Base::max_load_factor;
|
||||||
|
|
||||||
|
// flat_hash_map::get_allocator()
|
||||||
|
//
|
||||||
|
// Returns the allocator function associated with this `flat_hash_map`.
|
||||||
|
using Base::get_allocator;
|
||||||
|
|
||||||
|
// flat_hash_map::hash_function()
|
||||||
|
//
|
||||||
|
// Returns the hashing function used to hash the keys within this
|
||||||
|
// `flat_hash_map`.
|
||||||
|
using Base::hash_function;
|
||||||
|
|
||||||
|
// flat_hash_map::key_eq()
|
||||||
|
//
|
||||||
|
// Returns the function used for comparing keys equality.
|
||||||
|
using Base::key_eq;
|
||||||
|
};
|
||||||
|
|
||||||
|
// erase_if(flat_hash_map<>, Pred)
|
||||||
|
//
|
||||||
|
// Erases all elements that satisfy the predicate `pred` from the container `c`.
|
||||||
|
// Returns the number of erased elements.
|
||||||
|
template <typename K, typename V, typename H, typename E, typename A,
|
||||||
|
typename Predicate>
|
||||||
|
typename flat_hash_map<K, V, H, E, A>::size_type erase_if(
|
||||||
|
flat_hash_map<K, V, H, E, A>& c, Predicate pred) {
|
||||||
|
return container_internal::EraseIf(pred, &c);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace container_internal {
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
struct FlatHashMapPolicy {
|
||||||
|
using slot_policy = container_internal::map_slot_policy<K, V>;
|
||||||
|
using slot_type = typename slot_policy::slot_type;
|
||||||
|
using key_type = K;
|
||||||
|
using mapped_type = V;
|
||||||
|
using init_type = std::pair</*non const*/ key_type, mapped_type>;
|
||||||
|
|
||||||
|
template <class Allocator, class... Args>
|
||||||
|
static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
|
||||||
|
slot_policy::construct(alloc, slot, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Allocator>
|
||||||
|
static void destroy(Allocator* alloc, slot_type* slot) {
|
||||||
|
slot_policy::destroy(alloc, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Allocator>
|
||||||
|
static void transfer(Allocator* alloc, slot_type* new_slot,
|
||||||
|
slot_type* old_slot) {
|
||||||
|
slot_policy::transfer(alloc, new_slot, old_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F, class... Args>
|
||||||
|
static decltype(absl::container_internal::DecomposePair(
|
||||||
|
std::declval<F>(), std::declval<Args>()...))
|
||||||
|
apply(F&& f, Args&&... args) {
|
||||||
|
return absl::container_internal::DecomposePair(std::forward<F>(f),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t space_used(const slot_type*) { return 0; }
|
||||||
|
|
||||||
|
static std::pair<const K, V>& element(slot_type* slot) { return slot->value; }
|
||||||
|
|
||||||
|
static V& value(std::pair<const K, V>* kv) { return kv->second; }
|
||||||
|
static const V& value(const std::pair<const K, V>* kv) { return kv->second; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace container_internal
|
||||||
|
|
||||||
|
namespace container_algorithm_internal {
|
||||||
|
|
||||||
|
// Specialization of trait in absl/algorithm/container.h
|
||||||
|
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||||
|
struct IsUnorderedContainer<
|
||||||
|
absl::flat_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
|
||||||
|
|
||||||
|
} // namespace container_algorithm_internal
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_CONTAINER_FLAT_HASH_MAP_H_
|
||||||
510
include/absl/container/flat_hash_set.h
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
// Copyright 2018 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: flat_hash_set.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// An `absl::flat_hash_set<T>` is an unordered associative container designed to
|
||||||
|
// be a more efficient replacement for `std::unordered_set`. Like
|
||||||
|
// `unordered_set`, search, insertion, and deletion of set elements can be done
|
||||||
|
// as an `O(1)` operation. However, `flat_hash_set` (and other unordered
|
||||||
|
// associative containers known as the collection of Abseil "Swiss tables")
|
||||||
|
// contain other optimizations that result in both memory and computation
|
||||||
|
// advantages.
|
||||||
|
//
|
||||||
|
// In most cases, your default choice for a hash set should be a set of type
|
||||||
|
// `flat_hash_set`.
|
||||||
|
#ifndef ABSL_CONTAINER_FLAT_HASH_SET_H_
|
||||||
|
#define ABSL_CONTAINER_FLAT_HASH_SET_H_
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "absl/algorithm/container.h"
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/container/internal/container_memory.h"
|
||||||
|
#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
|
||||||
|
#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace container_internal {
|
||||||
|
template <typename T>
|
||||||
|
struct FlatHashSetPolicy;
|
||||||
|
} // namespace container_internal
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// absl::flat_hash_set
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// An `absl::flat_hash_set<T>` is an unordered associative container which has
|
||||||
|
// been optimized for both speed and memory footprint in most common use cases.
|
||||||
|
// Its interface is similar to that of `std::unordered_set<T>` with the
|
||||||
|
// following notable differences:
|
||||||
|
//
|
||||||
|
// * Requires keys that are CopyConstructible
|
||||||
|
// * Supports heterogeneous lookup, through `find()` and `insert()`, provided
|
||||||
|
// that the set is provided a compatible heterogeneous hashing function and
|
||||||
|
// equality operator.
|
||||||
|
// * Invalidates any references and pointers to elements within the table after
|
||||||
|
// `rehash()`.
|
||||||
|
// * Contains a `capacity()` member function indicating the number of element
|
||||||
|
// slots (open, deleted, and empty) within the hash set.
|
||||||
|
// * Returns `void` from the `erase(iterator)` overload.
|
||||||
|
//
|
||||||
|
// By default, `flat_hash_set` uses the `absl::Hash` hashing framework. All
|
||||||
|
// fundamental and Abseil types that support the `absl::Hash` framework have a
|
||||||
|
// compatible equality operator for comparing insertions into `flat_hash_set`.
|
||||||
|
// If your type is not yet supported by the `absl::Hash` framework, see
|
||||||
|
// absl/hash/hash.h for information on extending Abseil hashing to user-defined
|
||||||
|
// types.
|
||||||
|
//
|
||||||
|
// Using `absl::flat_hash_set` at interface boundaries in dynamically loaded
|
||||||
|
// libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may
|
||||||
|
// be randomized across dynamically loaded libraries.
|
||||||
|
//
|
||||||
|
// NOTE: A `flat_hash_set` stores its keys directly inside its implementation
|
||||||
|
// array to avoid memory indirection. Because a `flat_hash_set` is designed to
|
||||||
|
// move data when rehashed, set keys will not retain pointer stability. If you
|
||||||
|
// require pointer stability, consider using
|
||||||
|
// `absl::flat_hash_set<std::unique_ptr<T>>`. If your type is not moveable and
|
||||||
|
// you require pointer stability, consider `absl::node_hash_set` instead.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // Create a flat hash set of three strings
|
||||||
|
// absl::flat_hash_set<std::string> ducks =
|
||||||
|
// {"huey", "dewey", "louie"};
|
||||||
|
//
|
||||||
|
// // Insert a new element into the flat hash set
|
||||||
|
// ducks.insert("donald");
|
||||||
|
//
|
||||||
|
// // Force a rehash of the flat hash set
|
||||||
|
// ducks.rehash(0);
|
||||||
|
//
|
||||||
|
// // See if "dewey" is present
|
||||||
|
// if (ducks.contains("dewey")) {
|
||||||
|
// std::cout << "We found dewey!" << std::endl;
|
||||||
|
// }
|
||||||
|
template <class T, class Hash = absl::container_internal::hash_default_hash<T>,
|
||||||
|
class Eq = absl::container_internal::hash_default_eq<T>,
|
||||||
|
class Allocator = std::allocator<T>>
|
||||||
|
class flat_hash_set
|
||||||
|
: public absl::container_internal::raw_hash_set<
|
||||||
|
absl::container_internal::FlatHashSetPolicy<T>, Hash, Eq, Allocator> {
|
||||||
|
using Base = typename flat_hash_set::raw_hash_set;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors and Assignment Operators
|
||||||
|
//
|
||||||
|
// A flat_hash_set supports the same overload set as `std::unordered_set`
|
||||||
|
// for construction and assignment:
|
||||||
|
//
|
||||||
|
// * Default constructor
|
||||||
|
//
|
||||||
|
// // No allocation for the table's elements is made.
|
||||||
|
// absl::flat_hash_set<std::string> set1;
|
||||||
|
//
|
||||||
|
// * Initializer List constructor
|
||||||
|
//
|
||||||
|
// absl::flat_hash_set<std::string> set2 =
|
||||||
|
// {{"huey"}, {"dewey"}, {"louie"},};
|
||||||
|
//
|
||||||
|
// * Copy constructor
|
||||||
|
//
|
||||||
|
// absl::flat_hash_set<std::string> set3(set2);
|
||||||
|
//
|
||||||
|
// * Copy assignment operator
|
||||||
|
//
|
||||||
|
// // Hash functor and Comparator are copied as well
|
||||||
|
// absl::flat_hash_set<std::string> set4;
|
||||||
|
// set4 = set3;
|
||||||
|
//
|
||||||
|
// * Move constructor
|
||||||
|
//
|
||||||
|
// // Move is guaranteed efficient
|
||||||
|
// absl::flat_hash_set<std::string> set5(std::move(set4));
|
||||||
|
//
|
||||||
|
// * Move assignment operator
|
||||||
|
//
|
||||||
|
// // May be efficient if allocators are compatible
|
||||||
|
// absl::flat_hash_set<std::string> set6;
|
||||||
|
// set6 = std::move(set5);
|
||||||
|
//
|
||||||
|
// * Range constructor
|
||||||
|
//
|
||||||
|
// std::vector<std::string> v = {"a", "b"};
|
||||||
|
// absl::flat_hash_set<std::string> set7(v.begin(), v.end());
|
||||||
|
flat_hash_set() {}
|
||||||
|
using Base::Base;
|
||||||
|
|
||||||
|
// flat_hash_set::begin()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the beginning of the `flat_hash_set`.
|
||||||
|
using Base::begin;
|
||||||
|
|
||||||
|
// flat_hash_set::cbegin()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the beginning of the `flat_hash_set`.
|
||||||
|
using Base::cbegin;
|
||||||
|
|
||||||
|
// flat_hash_set::cend()
|
||||||
|
//
|
||||||
|
// Returns a const iterator to the end of the `flat_hash_set`.
|
||||||
|
using Base::cend;
|
||||||
|
|
||||||
|
// flat_hash_set::end()
|
||||||
|
//
|
||||||
|
// Returns an iterator to the end of the `flat_hash_set`.
|
||||||
|
using Base::end;
|
||||||
|
|
||||||
|
// flat_hash_set::capacity()
|
||||||
|
//
|
||||||
|
// Returns the number of element slots (assigned, deleted, and empty)
|
||||||
|
// available within the `flat_hash_set`.
|
||||||
|
//
|
||||||
|
// NOTE: this member function is particular to `absl::flat_hash_set` and is
|
||||||
|
// not provided in the `std::unordered_set` API.
|
||||||
|
using Base::capacity;
|
||||||
|
|
||||||
|
// flat_hash_set::empty()
|
||||||
|
//
|
||||||
|
// Returns whether or not the `flat_hash_set` is empty.
|
||||||
|
using Base::empty;
|
||||||
|
|
||||||
|
// flat_hash_set::max_size()
|
||||||
|
//
|
||||||
|
// Returns the largest theoretical possible number of elements within a
|
||||||
|
// `flat_hash_set` under current memory constraints. This value can be thought
|
||||||
|
// of the largest value of `std::distance(begin(), end())` for a
|
||||||
|
// `flat_hash_set<T>`.
|
||||||
|
using Base::max_size;
|
||||||
|
|
||||||
|
// flat_hash_set::size()
|
||||||
|
//
|
||||||
|
// Returns the number of elements currently within the `flat_hash_set`.
|
||||||
|
using Base::size;
|
||||||
|
|
||||||
|
// flat_hash_set::clear()
|
||||||
|
//
|
||||||
|
// Removes all elements from the `flat_hash_set`. Invalidates any references,
|
||||||
|
// pointers, or iterators referring to contained elements.
|
||||||
|
//
|
||||||
|
// NOTE: this operation may shrink the underlying buffer. To avoid shrinking
|
||||||
|
// the underlying buffer call `erase(begin(), end())`.
|
||||||
|
using Base::clear;
|
||||||
|
|
||||||
|
// flat_hash_set::erase()
|
||||||
|
//
|
||||||
|
// Erases elements within the `flat_hash_set`. Erasing does not trigger a
|
||||||
|
// rehash. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// void erase(const_iterator pos):
|
||||||
|
//
|
||||||
|
// Erases the element at `position` of the `flat_hash_set`, returning
|
||||||
|
// `void`.
|
||||||
|
//
|
||||||
|
// NOTE: returning `void` in this case is different than that of STL
|
||||||
|
// containers in general and `std::unordered_set` in particular (which
|
||||||
|
// return an iterator to the element following the erased element). If that
|
||||||
|
// iterator is needed, simply post increment the iterator:
|
||||||
|
//
|
||||||
|
// set.erase(it++);
|
||||||
|
//
|
||||||
|
// iterator erase(const_iterator first, const_iterator last):
|
||||||
|
//
|
||||||
|
// Erases the elements in the open interval [`first`, `last`), returning an
|
||||||
|
// iterator pointing to `last`.
|
||||||
|
//
|
||||||
|
// size_type erase(const key_type& key):
|
||||||
|
//
|
||||||
|
// Erases the element with the matching key, if it exists, returning the
|
||||||
|
// number of elements erased (0 or 1).
|
||||||
|
using Base::erase;
|
||||||
|
|
||||||
|
// flat_hash_set::insert()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value into the `flat_hash_set`,
|
||||||
|
// returning an iterator pointing to the newly inserted element, provided that
|
||||||
|
// an element with the given key does not already exist. If rehashing occurs
|
||||||
|
// due to the insertion, all iterators are invalidated. Overloads are listed
|
||||||
|
// below.
|
||||||
|
//
|
||||||
|
// std::pair<iterator,bool> insert(const T& value):
|
||||||
|
//
|
||||||
|
// Inserts a value into the `flat_hash_set`. Returns a pair consisting of an
|
||||||
|
// iterator to the inserted element (or to the element that prevented the
|
||||||
|
// insertion) and a bool denoting whether the insertion took place.
|
||||||
|
//
|
||||||
|
// std::pair<iterator,bool> insert(T&& value):
|
||||||
|
//
|
||||||
|
// Inserts a moveable value into the `flat_hash_set`. Returns a pair
|
||||||
|
// consisting of an iterator to the inserted element (or to the element that
|
||||||
|
// prevented the insertion) and a bool denoting whether the insertion took
|
||||||
|
// place.
|
||||||
|
//
|
||||||
|
// iterator insert(const_iterator hint, const T& value):
|
||||||
|
// iterator insert(const_iterator hint, T&& value):
|
||||||
|
//
|
||||||
|
// Inserts a value, using the position of `hint` as a non-binding suggestion
|
||||||
|
// for where to begin the insertion search. Returns an iterator to the
|
||||||
|
// inserted element, or to the existing element that prevented the
|
||||||
|
// insertion.
|
||||||
|
//
|
||||||
|
// void insert(InputIterator first, InputIterator last):
|
||||||
|
//
|
||||||
|
// Inserts a range of values [`first`, `last`).
|
||||||
|
//
|
||||||
|
// NOTE: Although the STL does not specify which element may be inserted if
|
||||||
|
// multiple keys compare equivalently, for `flat_hash_set` we guarantee the
|
||||||
|
// first match is inserted.
|
||||||
|
//
|
||||||
|
// void insert(std::initializer_list<T> ilist):
|
||||||
|
//
|
||||||
|
// Inserts the elements within the initializer list `ilist`.
|
||||||
|
//
|
||||||
|
// NOTE: Although the STL does not specify which element may be inserted if
|
||||||
|
// multiple keys compare equivalently within the initializer list, for
|
||||||
|
// `flat_hash_set` we guarantee the first match is inserted.
|
||||||
|
using Base::insert;
|
||||||
|
|
||||||
|
// flat_hash_set::emplace()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `flat_hash_set`, provided that no element with the given key
|
||||||
|
// already exists.
|
||||||
|
//
|
||||||
|
// The element may be constructed even if there already is an element with the
|
||||||
|
// key in the container, in which case the newly constructed element will be
|
||||||
|
// destroyed immediately.
|
||||||
|
//
|
||||||
|
// If rehashing occurs due to the insertion, all iterators are invalidated.
|
||||||
|
using Base::emplace;
|
||||||
|
|
||||||
|
// flat_hash_set::emplace_hint()
|
||||||
|
//
|
||||||
|
// Inserts an element of the specified value by constructing it in-place
|
||||||
|
// within the `flat_hash_set`, using the position of `hint` as a non-binding
|
||||||
|
// suggestion for where to begin the insertion search, and only inserts
|
||||||
|
// provided that no element with the given key already exists.
|
||||||
|
//
|
||||||
|
// The element may be constructed even if there already is an element with the
|
||||||
|
// key in the container, in which case the newly constructed element will be
|
||||||
|
// destroyed immediately.
|
||||||
|
//
|
||||||
|
// If rehashing occurs due to the insertion, all iterators are invalidated.
|
||||||
|
using Base::emplace_hint;
|
||||||
|
|
||||||
|
// flat_hash_set::extract()
|
||||||
|
//
|
||||||
|
// Extracts the indicated element, erasing it in the process, and returns it
|
||||||
|
// as a C++17-compatible node handle. Overloads are listed below.
|
||||||
|
//
|
||||||
|
// node_type extract(const_iterator position):
|
||||||
|
//
|
||||||
|
// Extracts the element at the indicated position and returns a node handle
|
||||||
|
// owning that extracted data.
|
||||||
|
//
|
||||||
|
// node_type extract(const key_type& x):
|
||||||
|
//
|
||||||
|
// Extracts the element with the key matching the passed key value and
|
||||||
|
// returns a node handle owning that extracted data. If the `flat_hash_set`
|
||||||
|
// does not contain an element with a matching key, this function returns an
|
||||||
|
// empty node handle.
|
||||||
|
using Base::extract;
|
||||||
|
|
||||||
|
// flat_hash_set::merge()
|
||||||
|
//
|
||||||
|
// Extracts elements from a given `source` flat hash set into this
|
||||||
|
// `flat_hash_set`. If the destination `flat_hash_set` already contains an
|
||||||
|
// element with an equivalent key, that element is not extracted.
|
||||||
|
using Base::merge;
|
||||||
|
|
||||||
|
// flat_hash_set::swap(flat_hash_set& other)
|
||||||
|
//
|
||||||
|
// Exchanges the contents of this `flat_hash_set` with those of the `other`
|
||||||
|
// flat hash set, avoiding invocation of any move, copy, or swap operations on
|
||||||
|
// individual elements.
|
||||||
|
//
|
||||||
|
// All iterators and references on the `flat_hash_set` remain valid, excepting
|
||||||
|
// for the past-the-end iterator, which is invalidated.
|
||||||
|
//
|
||||||
|
// `swap()` requires that the flat hash set's hashing and key equivalence
|
||||||
|
// functions be Swappable, and are exchaged using unqualified calls to
|
||||||
|
// non-member `swap()`. If the set's allocator has
|
||||||
|
// `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
|
||||||
|
// set to `true`, the allocators are also exchanged using an unqualified call
|
||||||
|
// to non-member `swap()`; otherwise, the allocators are not swapped.
|
||||||
|
using Base::swap;
|
||||||
|
|
||||||
|
// flat_hash_set::rehash(count)
|
||||||
|
//
|
||||||
|
// Rehashes the `flat_hash_set`, setting the number of slots to be at least
|
||||||
|
// the passed value. If the new number of slots increases the load factor more
|
||||||
|
// than the current maximum load factor
|
||||||
|
// (`count` < `size()` / `max_load_factor()`), then the new number of slots
|
||||||
|
// will be at least `size()` / `max_load_factor()`.
|
||||||
|
//
|
||||||
|
// To force a rehash, pass rehash(0).
|
||||||
|
//
|
||||||
|
// NOTE: unlike behavior in `std::unordered_set`, references are also
|
||||||
|
// invalidated upon a `rehash()`.
|
||||||
|
using Base::rehash;
|
||||||
|
|
||||||
|
// flat_hash_set::reserve(count)
|
||||||
|
//
|
||||||
|
// Sets the number of slots in the `flat_hash_set` to the number needed to
|
||||||
|
// accommodate at least `count` total elements without exceeding the current
|
||||||
|
// maximum load factor, and may rehash the container if needed.
|
||||||
|
using Base::reserve;
|
||||||
|
|
||||||
|
// flat_hash_set::contains()
|
||||||
|
//
|
||||||
|
// Determines whether an element comparing equal to the given `key` exists
|
||||||
|
// within the `flat_hash_set`, returning `true` if so or `false` otherwise.
|
||||||
|
using Base::contains;
|
||||||
|
|
||||||
|
// flat_hash_set::count(const Key& key) const
|
||||||
|
//
|
||||||
|
// Returns the number of elements comparing equal to the given `key` within
|
||||||
|
// the `flat_hash_set`. note that this function will return either `1` or `0`
|
||||||
|
// since duplicate elements are not allowed within a `flat_hash_set`.
|
||||||
|
using Base::count;
|
||||||
|
|
||||||
|
// flat_hash_set::equal_range()
|
||||||
|
//
|
||||||
|
// Returns a closed range [first, last], defined by a `std::pair` of two
|
||||||
|
// iterators, containing all elements with the passed key in the
|
||||||
|
// `flat_hash_set`.
|
||||||
|
using Base::equal_range;
|
||||||
|
|
||||||
|
// flat_hash_set::find()
|
||||||
|
//
|
||||||
|
// Finds an element with the passed `key` within the `flat_hash_set`.
|
||||||
|
using Base::find;
|
||||||
|
|
||||||
|
// flat_hash_set::bucket_count()
|
||||||
|
//
|
||||||
|
// Returns the number of "buckets" within the `flat_hash_set`. Note that
|
||||||
|
// because a flat hash set contains all elements within its internal storage,
|
||||||
|
// this value simply equals the current capacity of the `flat_hash_set`.
|
||||||
|
using Base::bucket_count;
|
||||||
|
|
||||||
|
// flat_hash_set::load_factor()
|
||||||
|
//
|
||||||
|
// Returns the current load factor of the `flat_hash_set` (the average number
|
||||||
|
// of slots occupied with a value within the hash set).
|
||||||
|
using Base::load_factor;
|
||||||
|
|
||||||
|
// flat_hash_set::max_load_factor()
|
||||||
|
//
|
||||||
|
// Manages the maximum load factor of the `flat_hash_set`. Overloads are
|
||||||
|
// listed below.
|
||||||
|
//
|
||||||
|
// float flat_hash_set::max_load_factor()
|
||||||
|
//
|
||||||
|
// Returns the current maximum load factor of the `flat_hash_set`.
|
||||||
|
//
|
||||||
|
// void flat_hash_set::max_load_factor(float ml)
|
||||||
|
//
|
||||||
|
// Sets the maximum load factor of the `flat_hash_set` to the passed value.
|
||||||
|
//
|
||||||
|
// NOTE: This overload is provided only for API compatibility with the STL;
|
||||||
|
// `flat_hash_set` will ignore any set load factor and manage its rehashing
|
||||||
|
// internally as an implementation detail.
|
||||||
|
using Base::max_load_factor;
|
||||||
|
|
||||||
|
// flat_hash_set::get_allocator()
|
||||||
|
//
|
||||||
|
// Returns the allocator function associated with this `flat_hash_set`.
|
||||||
|
using Base::get_allocator;
|
||||||
|
|
||||||
|
// flat_hash_set::hash_function()
|
||||||
|
//
|
||||||
|
// Returns the hashing function used to hash the keys within this
|
||||||
|
// `flat_hash_set`.
|
||||||
|
using Base::hash_function;
|
||||||
|
|
||||||
|
// flat_hash_set::key_eq()
|
||||||
|
//
|
||||||
|
// Returns the function used for comparing keys equality.
|
||||||
|
using Base::key_eq;
|
||||||
|
};
|
||||||
|
|
||||||
|
// erase_if(flat_hash_set<>, Pred)
|
||||||
|
//
|
||||||
|
// Erases all elements that satisfy the predicate `pred` from the container `c`.
|
||||||
|
// Returns the number of erased elements.
|
||||||
|
template <typename T, typename H, typename E, typename A, typename Predicate>
|
||||||
|
typename flat_hash_set<T, H, E, A>::size_type erase_if(
|
||||||
|
flat_hash_set<T, H, E, A>& c, Predicate pred) {
|
||||||
|
return container_internal::EraseIf(pred, &c);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace container_internal {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct FlatHashSetPolicy {
|
||||||
|
using slot_type = T;
|
||||||
|
using key_type = T;
|
||||||
|
using init_type = T;
|
||||||
|
using constant_iterators = std::true_type;
|
||||||
|
|
||||||
|
template <class Allocator, class... Args>
|
||||||
|
static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
|
||||||
|
absl::allocator_traits<Allocator>::construct(*alloc, slot,
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Allocator>
|
||||||
|
static void destroy(Allocator* alloc, slot_type* slot) {
|
||||||
|
absl::allocator_traits<Allocator>::destroy(*alloc, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Allocator>
|
||||||
|
static void transfer(Allocator* alloc, slot_type* new_slot,
|
||||||
|
slot_type* old_slot) {
|
||||||
|
construct(alloc, new_slot, std::move(*old_slot));
|
||||||
|
destroy(alloc, old_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T& element(slot_type* slot) { return *slot; }
|
||||||
|
|
||||||
|
template <class F, class... Args>
|
||||||
|
static decltype(absl::container_internal::DecomposeValue(
|
||||||
|
std::declval<F>(), std::declval<Args>()...))
|
||||||
|
apply(F&& f, Args&&... args) {
|
||||||
|
return absl::container_internal::DecomposeValue(
|
||||||
|
std::forward<F>(f), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t space_used(const T*) { return 0; }
|
||||||
|
};
|
||||||
|
} // namespace container_internal
|
||||||
|
|
||||||
|
namespace container_algorithm_internal {
|
||||||
|
|
||||||
|
// Specialization of trait in absl/algorithm/container.h
|
||||||
|
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||||
|
struct IsUnorderedContainer<absl::flat_hash_set<Key, Hash, KeyEqual, Allocator>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
} // namespace container_algorithm_internal
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_CONTAINER_FLAT_HASH_SET_H_
|
||||||
866
include/absl/container/inlined_vector.h
Normal file
@ -0,0 +1,866 @@
|
|||||||
|
// Copyright 2019 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: inlined_vector.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This header file contains the declaration and definition of an "inlined
|
||||||
|
// vector" which behaves in an equivalent fashion to a `std::vector`, except
|
||||||
|
// that storage for small sequences of the vector are provided inline without
|
||||||
|
// requiring any heap allocation.
|
||||||
|
//
|
||||||
|
// An `absl::InlinedVector<T, N>` specifies the default capacity `N` as one of
|
||||||
|
// its template parameters. Instances where `size() <= N` hold contained
|
||||||
|
// elements in inline space. Typically `N` is very small so that sequences that
|
||||||
|
// are expected to be short do not require allocations.
|
||||||
|
//
|
||||||
|
// An `absl::InlinedVector` does not usually require a specific allocator. If
|
||||||
|
// the inlined vector grows beyond its initial constraints, it will need to
|
||||||
|
// allocate (as any normal `std::vector` would). This is usually performed with
|
||||||
|
// the default allocator (defined as `std::allocator<T>`). Optionally, a custom
|
||||||
|
// allocator type may be specified as `A` in `absl::InlinedVector<T, N, A>`.
|
||||||
|
|
||||||
|
#ifndef ABSL_CONTAINER_INLINED_VECTOR_H_
|
||||||
|
#define ABSL_CONTAINER_INLINED_VECTOR_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "absl/algorithm/algorithm.h"
|
||||||
|
#include "absl/base/internal/throw_delegate.h"
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/base/optimization.h"
|
||||||
|
#include "absl/base/port.h"
|
||||||
|
#include "absl/container/internal/inlined_vector.h"
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// InlinedVector
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// An `absl::InlinedVector` is designed to be a drop-in replacement for
|
||||||
|
// `std::vector` for use cases where the vector's size is sufficiently small
|
||||||
|
// that it can be inlined. If the inlined vector does grow beyond its estimated
|
||||||
|
// capacity, it will trigger an initial allocation on the heap, and will behave
|
||||||
|
// as a `std::vector`. The API of the `absl::InlinedVector` within this file is
|
||||||
|
// designed to cover the same API footprint as covered by `std::vector`.
|
||||||
|
template <typename T, size_t N, typename A = std::allocator<T>>
|
||||||
|
class InlinedVector {
|
||||||
|
static_assert(N > 0, "`absl::InlinedVector` requires an inlined capacity.");
|
||||||
|
|
||||||
|
using Storage = inlined_vector_internal::Storage<T, N, A>;
|
||||||
|
|
||||||
|
template <typename TheA>
|
||||||
|
using AllocatorTraits = inlined_vector_internal::AllocatorTraits<TheA>;
|
||||||
|
template <typename TheA>
|
||||||
|
using MoveIterator = inlined_vector_internal::MoveIterator<TheA>;
|
||||||
|
template <typename TheA>
|
||||||
|
using IsMemcpyOk = inlined_vector_internal::IsMemcpyOk<TheA>;
|
||||||
|
|
||||||
|
template <typename TheA, typename Iterator>
|
||||||
|
using IteratorValueAdapter =
|
||||||
|
inlined_vector_internal::IteratorValueAdapter<TheA, Iterator>;
|
||||||
|
template <typename TheA>
|
||||||
|
using CopyValueAdapter = inlined_vector_internal::CopyValueAdapter<TheA>;
|
||||||
|
template <typename TheA>
|
||||||
|
using DefaultValueAdapter =
|
||||||
|
inlined_vector_internal::DefaultValueAdapter<TheA>;
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
using EnableIfAtLeastForwardIterator = absl::enable_if_t<
|
||||||
|
inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
|
||||||
|
template <typename Iterator>
|
||||||
|
using DisableIfAtLeastForwardIterator = absl::enable_if_t<
|
||||||
|
!inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using allocator_type = A;
|
||||||
|
using value_type = inlined_vector_internal::ValueType<A>;
|
||||||
|
using pointer = inlined_vector_internal::Pointer<A>;
|
||||||
|
using const_pointer = inlined_vector_internal::ConstPointer<A>;
|
||||||
|
using size_type = inlined_vector_internal::SizeType<A>;
|
||||||
|
using difference_type = inlined_vector_internal::DifferenceType<A>;
|
||||||
|
using reference = inlined_vector_internal::Reference<A>;
|
||||||
|
using const_reference = inlined_vector_internal::ConstReference<A>;
|
||||||
|
using iterator = inlined_vector_internal::Iterator<A>;
|
||||||
|
using const_iterator = inlined_vector_internal::ConstIterator<A>;
|
||||||
|
using reverse_iterator = inlined_vector_internal::ReverseIterator<A>;
|
||||||
|
using const_reverse_iterator =
|
||||||
|
inlined_vector_internal::ConstReverseIterator<A>;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// InlinedVector Constructors and Destructor
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Creates an empty inlined vector with a value-initialized allocator.
|
||||||
|
InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {}
|
||||||
|
|
||||||
|
// Creates an empty inlined vector with a copy of `allocator`.
|
||||||
|
explicit InlinedVector(const allocator_type& allocator) noexcept
|
||||||
|
: storage_(allocator) {}
|
||||||
|
|
||||||
|
// Creates an inlined vector with `n` copies of `value_type()`.
|
||||||
|
explicit InlinedVector(size_type n,
|
||||||
|
const allocator_type& allocator = allocator_type())
|
||||||
|
: storage_(allocator) {
|
||||||
|
storage_.Initialize(DefaultValueAdapter<A>(), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an inlined vector with `n` copies of `v`.
|
||||||
|
InlinedVector(size_type n, const_reference v,
|
||||||
|
const allocator_type& allocator = allocator_type())
|
||||||
|
: storage_(allocator) {
|
||||||
|
storage_.Initialize(CopyValueAdapter<A>(std::addressof(v)), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an inlined vector with copies of the elements of `list`.
|
||||||
|
InlinedVector(std::initializer_list<value_type> list,
|
||||||
|
const allocator_type& allocator = allocator_type())
|
||||||
|
: InlinedVector(list.begin(), list.end(), allocator) {}
|
||||||
|
|
||||||
|
// Creates an inlined vector with elements constructed from the provided
|
||||||
|
// forward iterator range [`first`, `last`).
|
||||||
|
//
|
||||||
|
// NOTE: the `enable_if` prevents ambiguous interpretation between a call to
|
||||||
|
// this constructor with two integral arguments and a call to the above
|
||||||
|
// `InlinedVector(size_type, const_reference)` constructor.
|
||||||
|
template <typename ForwardIterator,
|
||||||
|
EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
|
||||||
|
InlinedVector(ForwardIterator first, ForwardIterator last,
|
||||||
|
const allocator_type& allocator = allocator_type())
|
||||||
|
: storage_(allocator) {
|
||||||
|
storage_.Initialize(IteratorValueAdapter<A, ForwardIterator>(first),
|
||||||
|
static_cast<size_t>(std::distance(first, last)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an inlined vector with elements constructed from the provided input
|
||||||
|
// iterator range [`first`, `last`).
|
||||||
|
template <typename InputIterator,
|
||||||
|
DisableIfAtLeastForwardIterator<InputIterator> = 0>
|
||||||
|
InlinedVector(InputIterator first, InputIterator last,
|
||||||
|
const allocator_type& allocator = allocator_type())
|
||||||
|
: storage_(allocator) {
|
||||||
|
std::copy(first, last, std::back_inserter(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an inlined vector by copying the contents of `other` using
|
||||||
|
// `other`'s allocator.
|
||||||
|
InlinedVector(const InlinedVector& other)
|
||||||
|
: InlinedVector(other, other.storage_.GetAllocator()) {}
|
||||||
|
|
||||||
|
// Creates an inlined vector by copying the contents of `other` using the
|
||||||
|
// provided `allocator`.
|
||||||
|
InlinedVector(const InlinedVector& other, const allocator_type& allocator)
|
||||||
|
: storage_(allocator) {
|
||||||
|
if (other.empty()) {
|
||||||
|
// Empty; nothing to do.
|
||||||
|
} else if (IsMemcpyOk<A>::value && !other.storage_.GetIsAllocated()) {
|
||||||
|
// Memcpy-able and do not need allocation.
|
||||||
|
storage_.MemcpyFrom(other.storage_);
|
||||||
|
} else {
|
||||||
|
storage_.InitFrom(other.storage_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an inlined vector by moving in the contents of `other` without
|
||||||
|
// allocating. If `other` contains allocated memory, the newly-created inlined
|
||||||
|
// vector will take ownership of that memory. However, if `other` does not
|
||||||
|
// contain allocated memory, the newly-created inlined vector will perform
|
||||||
|
// element-wise move construction of the contents of `other`.
|
||||||
|
//
|
||||||
|
// NOTE: since no allocation is performed for the inlined vector in either
|
||||||
|
// case, the `noexcept(...)` specification depends on whether moving the
|
||||||
|
// underlying objects can throw. It is assumed assumed that...
|
||||||
|
// a) move constructors should only throw due to allocation failure.
|
||||||
|
// b) if `value_type`'s move constructor allocates, it uses the same
|
||||||
|
// allocation function as the inlined vector's allocator.
|
||||||
|
// Thus, the move constructor is non-throwing if the allocator is non-throwing
|
||||||
|
// or `value_type`'s move constructor is specified as `noexcept`.
|
||||||
|
InlinedVector(InlinedVector&& other) noexcept(
|
||||||
|
absl::allocator_is_nothrow<allocator_type>::value ||
|
||||||
|
std::is_nothrow_move_constructible<value_type>::value)
|
||||||
|
: storage_(other.storage_.GetAllocator()) {
|
||||||
|
if (IsMemcpyOk<A>::value) {
|
||||||
|
storage_.MemcpyFrom(other.storage_);
|
||||||
|
|
||||||
|
other.storage_.SetInlinedSize(0);
|
||||||
|
} else if (other.storage_.GetIsAllocated()) {
|
||||||
|
storage_.SetAllocation({other.storage_.GetAllocatedData(),
|
||||||
|
other.storage_.GetAllocatedCapacity()});
|
||||||
|
storage_.SetAllocatedSize(other.storage_.GetSize());
|
||||||
|
|
||||||
|
other.storage_.SetInlinedSize(0);
|
||||||
|
} else {
|
||||||
|
IteratorValueAdapter<A, MoveIterator<A>> other_values(
|
||||||
|
MoveIterator<A>(other.storage_.GetInlinedData()));
|
||||||
|
|
||||||
|
inlined_vector_internal::ConstructElements<A>(
|
||||||
|
storage_.GetAllocator(), storage_.GetInlinedData(), other_values,
|
||||||
|
other.storage_.GetSize());
|
||||||
|
|
||||||
|
storage_.SetInlinedSize(other.storage_.GetSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an inlined vector by moving in the contents of `other` with a copy
|
||||||
|
// of `allocator`.
|
||||||
|
//
|
||||||
|
// NOTE: if `other`'s allocator is not equal to `allocator`, even if `other`
|
||||||
|
// contains allocated memory, this move constructor will still allocate. Since
|
||||||
|
// allocation is performed, this constructor can only be `noexcept` if the
|
||||||
|
// specified allocator is also `noexcept`.
|
||||||
|
InlinedVector(
|
||||||
|
InlinedVector&& other,
|
||||||
|
const allocator_type&
|
||||||
|
allocator) noexcept(absl::allocator_is_nothrow<allocator_type>::value)
|
||||||
|
: storage_(allocator) {
|
||||||
|
if (IsMemcpyOk<A>::value) {
|
||||||
|
storage_.MemcpyFrom(other.storage_);
|
||||||
|
|
||||||
|
other.storage_.SetInlinedSize(0);
|
||||||
|
} else if ((storage_.GetAllocator() == other.storage_.GetAllocator()) &&
|
||||||
|
other.storage_.GetIsAllocated()) {
|
||||||
|
storage_.SetAllocation({other.storage_.GetAllocatedData(),
|
||||||
|
other.storage_.GetAllocatedCapacity()});
|
||||||
|
storage_.SetAllocatedSize(other.storage_.GetSize());
|
||||||
|
|
||||||
|
other.storage_.SetInlinedSize(0);
|
||||||
|
} else {
|
||||||
|
storage_.Initialize(IteratorValueAdapter<A, MoveIterator<A>>(
|
||||||
|
MoveIterator<A>(other.data())),
|
||||||
|
other.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~InlinedVector() {}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// InlinedVector Member Accessors
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// `InlinedVector::empty()`
|
||||||
|
//
|
||||||
|
// Returns whether the inlined vector contains no elements.
|
||||||
|
bool empty() const noexcept { return !size(); }
|
||||||
|
|
||||||
|
// `InlinedVector::size()`
|
||||||
|
//
|
||||||
|
// Returns the number of elements in the inlined vector.
|
||||||
|
size_type size() const noexcept { return storage_.GetSize(); }
|
||||||
|
|
||||||
|
// `InlinedVector::max_size()`
|
||||||
|
//
|
||||||
|
// Returns the maximum number of elements the inlined vector can hold.
|
||||||
|
size_type max_size() const noexcept {
|
||||||
|
// One bit of the size storage is used to indicate whether the inlined
|
||||||
|
// vector contains allocated memory. As a result, the maximum size that the
|
||||||
|
// inlined vector can express is half of the max for `size_type`.
|
||||||
|
return (std::numeric_limits<size_type>::max)() / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::capacity()`
|
||||||
|
//
|
||||||
|
// Returns the number of elements that could be stored in the inlined vector
|
||||||
|
// without requiring a reallocation.
|
||||||
|
//
|
||||||
|
// NOTE: for most inlined vectors, `capacity()` should be equal to the
|
||||||
|
// template parameter `N`. For inlined vectors which exceed this capacity,
|
||||||
|
// they will no longer be inlined and `capacity()` will equal the capactity of
|
||||||
|
// the allocated memory.
|
||||||
|
size_type capacity() const noexcept {
|
||||||
|
return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity()
|
||||||
|
: storage_.GetInlinedCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::data()`
|
||||||
|
//
|
||||||
|
// Returns a `pointer` to the elements of the inlined vector. This pointer
|
||||||
|
// can be used to access and modify the contained elements.
|
||||||
|
//
|
||||||
|
// NOTE: only elements within [`data()`, `data() + size()`) are valid.
|
||||||
|
pointer data() noexcept {
|
||||||
|
return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
|
||||||
|
: storage_.GetInlinedData();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::data()` that returns a `const_pointer` to the
|
||||||
|
// elements of the inlined vector. This pointer can be used to access but not
|
||||||
|
// modify the contained elements.
|
||||||
|
//
|
||||||
|
// NOTE: only elements within [`data()`, `data() + size()`) are valid.
|
||||||
|
const_pointer data() const noexcept {
|
||||||
|
return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
|
||||||
|
: storage_.GetInlinedData();
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::operator[](...)`
|
||||||
|
//
|
||||||
|
// Returns a `reference` to the `i`th element of the inlined vector.
|
||||||
|
reference operator[](size_type i) {
|
||||||
|
ABSL_HARDENING_ASSERT(i < size());
|
||||||
|
return data()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::operator[](...)` that returns a
|
||||||
|
// `const_reference` to the `i`th element of the inlined vector.
|
||||||
|
const_reference operator[](size_type i) const {
|
||||||
|
ABSL_HARDENING_ASSERT(i < size());
|
||||||
|
return data()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::at(...)`
|
||||||
|
//
|
||||||
|
// Returns a `reference` to the `i`th element of the inlined vector.
|
||||||
|
//
|
||||||
|
// NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
|
||||||
|
// in both debug and non-debug builds, `std::out_of_range` will be thrown.
|
||||||
|
reference at(size_type i) {
|
||||||
|
if (ABSL_PREDICT_FALSE(i >= size())) {
|
||||||
|
base_internal::ThrowStdOutOfRange(
|
||||||
|
"`InlinedVector::at(size_type)` failed bounds check");
|
||||||
|
}
|
||||||
|
return data()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::at(...)` that returns a `const_reference` to
|
||||||
|
// the `i`th element of the inlined vector.
|
||||||
|
//
|
||||||
|
// NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
|
||||||
|
// in both debug and non-debug builds, `std::out_of_range` will be thrown.
|
||||||
|
const_reference at(size_type i) const {
|
||||||
|
if (ABSL_PREDICT_FALSE(i >= size())) {
|
||||||
|
base_internal::ThrowStdOutOfRange(
|
||||||
|
"`InlinedVector::at(size_type) const` failed bounds check");
|
||||||
|
}
|
||||||
|
return data()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::front()`
|
||||||
|
//
|
||||||
|
// Returns a `reference` to the first element of the inlined vector.
|
||||||
|
reference front() {
|
||||||
|
ABSL_HARDENING_ASSERT(!empty());
|
||||||
|
return data()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::front()` that returns a `const_reference` to
|
||||||
|
// the first element of the inlined vector.
|
||||||
|
const_reference front() const {
|
||||||
|
ABSL_HARDENING_ASSERT(!empty());
|
||||||
|
return data()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::back()`
|
||||||
|
//
|
||||||
|
// Returns a `reference` to the last element of the inlined vector.
|
||||||
|
reference back() {
|
||||||
|
ABSL_HARDENING_ASSERT(!empty());
|
||||||
|
return data()[size() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::back()` that returns a `const_reference` to the
|
||||||
|
// last element of the inlined vector.
|
||||||
|
const_reference back() const {
|
||||||
|
ABSL_HARDENING_ASSERT(!empty());
|
||||||
|
return data()[size() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::begin()`
|
||||||
|
//
|
||||||
|
// Returns an `iterator` to the beginning of the inlined vector.
|
||||||
|
iterator begin() noexcept { return data(); }
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::begin()` that returns a `const_iterator` to
|
||||||
|
// the beginning of the inlined vector.
|
||||||
|
const_iterator begin() const noexcept { return data(); }
|
||||||
|
|
||||||
|
// `InlinedVector::end()`
|
||||||
|
//
|
||||||
|
// Returns an `iterator` to the end of the inlined vector.
|
||||||
|
iterator end() noexcept { return data() + size(); }
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::end()` that returns a `const_iterator` to the
|
||||||
|
// end of the inlined vector.
|
||||||
|
const_iterator end() const noexcept { return data() + size(); }
|
||||||
|
|
||||||
|
// `InlinedVector::cbegin()`
|
||||||
|
//
|
||||||
|
// Returns a `const_iterator` to the beginning of the inlined vector.
|
||||||
|
const_iterator cbegin() const noexcept { return begin(); }
|
||||||
|
|
||||||
|
// `InlinedVector::cend()`
|
||||||
|
//
|
||||||
|
// Returns a `const_iterator` to the end of the inlined vector.
|
||||||
|
const_iterator cend() const noexcept { return end(); }
|
||||||
|
|
||||||
|
// `InlinedVector::rbegin()`
|
||||||
|
//
|
||||||
|
// Returns a `reverse_iterator` from the end of the inlined vector.
|
||||||
|
reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::rbegin()` that returns a
|
||||||
|
// `const_reverse_iterator` from the end of the inlined vector.
|
||||||
|
const_reverse_iterator rbegin() const noexcept {
|
||||||
|
return const_reverse_iterator(end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::rend()`
|
||||||
|
//
|
||||||
|
// Returns a `reverse_iterator` from the beginning of the inlined vector.
|
||||||
|
reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::rend()` that returns a `const_reverse_iterator`
|
||||||
|
// from the beginning of the inlined vector.
|
||||||
|
const_reverse_iterator rend() const noexcept {
|
||||||
|
return const_reverse_iterator(begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::crbegin()`
|
||||||
|
//
|
||||||
|
// Returns a `const_reverse_iterator` from the end of the inlined vector.
|
||||||
|
const_reverse_iterator crbegin() const noexcept { return rbegin(); }
|
||||||
|
|
||||||
|
// `InlinedVector::crend()`
|
||||||
|
//
|
||||||
|
// Returns a `const_reverse_iterator` from the beginning of the inlined
|
||||||
|
// vector.
|
||||||
|
const_reverse_iterator crend() const noexcept { return rend(); }
|
||||||
|
|
||||||
|
// `InlinedVector::get_allocator()`
|
||||||
|
//
|
||||||
|
// Returns a copy of the inlined vector's allocator.
|
||||||
|
allocator_type get_allocator() const { return storage_.GetAllocator(); }
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// InlinedVector Member Mutators
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// `InlinedVector::operator=(...)`
|
||||||
|
//
|
||||||
|
// Replaces the elements of the inlined vector with copies of the elements of
|
||||||
|
// `list`.
|
||||||
|
InlinedVector& operator=(std::initializer_list<value_type> list) {
|
||||||
|
assign(list.begin(), list.end());
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::operator=(...)` that replaces the elements of
|
||||||
|
// the inlined vector with copies of the elements of `other`.
|
||||||
|
InlinedVector& operator=(const InlinedVector& other) {
|
||||||
|
if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
|
||||||
|
const_pointer other_data = other.data();
|
||||||
|
assign(other_data, other_data + other.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::operator=(...)` that moves the elements of
|
||||||
|
// `other` into the inlined vector.
|
||||||
|
//
|
||||||
|
// NOTE: as a result of calling this overload, `other` is left in a valid but
|
||||||
|
// unspecified state.
|
||||||
|
InlinedVector& operator=(InlinedVector&& other) {
|
||||||
|
if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
|
||||||
|
if (IsMemcpyOk<A>::value || other.storage_.GetIsAllocated()) {
|
||||||
|
inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
|
||||||
|
storage_.GetAllocator(), data(), size());
|
||||||
|
storage_.DeallocateIfAllocated();
|
||||||
|
storage_.MemcpyFrom(other.storage_);
|
||||||
|
|
||||||
|
other.storage_.SetInlinedSize(0);
|
||||||
|
} else {
|
||||||
|
storage_.Assign(IteratorValueAdapter<A, MoveIterator<A>>(
|
||||||
|
MoveIterator<A>(other.storage_.GetInlinedData())),
|
||||||
|
other.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::assign(...)`
|
||||||
|
//
|
||||||
|
// Replaces the contents of the inlined vector with `n` copies of `v`.
|
||||||
|
void assign(size_type n, const_reference v) {
|
||||||
|
storage_.Assign(CopyValueAdapter<A>(std::addressof(v)), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::assign(...)` that replaces the contents of the
|
||||||
|
// inlined vector with copies of the elements of `list`.
|
||||||
|
void assign(std::initializer_list<value_type> list) {
|
||||||
|
assign(list.begin(), list.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::assign(...)` to replace the contents of the
|
||||||
|
// inlined vector with the range [`first`, `last`).
|
||||||
|
//
|
||||||
|
// NOTE: this overload is for iterators that are "forward" category or better.
|
||||||
|
template <typename ForwardIterator,
|
||||||
|
EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
|
||||||
|
void assign(ForwardIterator first, ForwardIterator last) {
|
||||||
|
storage_.Assign(IteratorValueAdapter<A, ForwardIterator>(first),
|
||||||
|
static_cast<size_t>(std::distance(first, last)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::assign(...)` to replace the contents of the
|
||||||
|
// inlined vector with the range [`first`, `last`).
|
||||||
|
//
|
||||||
|
// NOTE: this overload is for iterators that are "input" category.
|
||||||
|
template <typename InputIterator,
|
||||||
|
DisableIfAtLeastForwardIterator<InputIterator> = 0>
|
||||||
|
void assign(InputIterator first, InputIterator last) {
|
||||||
|
size_type i = 0;
|
||||||
|
for (; i < size() && first != last; ++i, static_cast<void>(++first)) {
|
||||||
|
data()[i] = *first;
|
||||||
|
}
|
||||||
|
|
||||||
|
erase(data() + i, data() + size());
|
||||||
|
std::copy(first, last, std::back_inserter(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::resize(...)`
|
||||||
|
//
|
||||||
|
// Resizes the inlined vector to contain `n` elements.
|
||||||
|
//
|
||||||
|
// NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n`
|
||||||
|
// is larger than `size()`, new elements are value-initialized.
|
||||||
|
void resize(size_type n) {
|
||||||
|
ABSL_HARDENING_ASSERT(n <= max_size());
|
||||||
|
storage_.Resize(DefaultValueAdapter<A>(), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
|
||||||
|
// contain `n` elements.
|
||||||
|
//
|
||||||
|
// NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
|
||||||
|
// is larger than `size()`, new elements are copied-constructed from `v`.
|
||||||
|
void resize(size_type n, const_reference v) {
|
||||||
|
ABSL_HARDENING_ASSERT(n <= max_size());
|
||||||
|
storage_.Resize(CopyValueAdapter<A>(std::addressof(v)), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::insert(...)`
|
||||||
|
//
|
||||||
|
// Inserts a copy of `v` at `pos`, returning an `iterator` to the newly
|
||||||
|
// inserted element.
|
||||||
|
iterator insert(const_iterator pos, const_reference v) {
|
||||||
|
return emplace(pos, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using
|
||||||
|
// move semantics, returning an `iterator` to the newly inserted element.
|
||||||
|
iterator insert(const_iterator pos, value_type&& v) {
|
||||||
|
return emplace(pos, std::move(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::insert(...)` that inserts `n` contiguous copies
|
||||||
|
// of `v` starting at `pos`, returning an `iterator` pointing to the first of
|
||||||
|
// the newly inserted elements.
|
||||||
|
iterator insert(const_iterator pos, size_type n, const_reference v) {
|
||||||
|
ABSL_HARDENING_ASSERT(pos >= begin());
|
||||||
|
ABSL_HARDENING_ASSERT(pos <= end());
|
||||||
|
|
||||||
|
if (ABSL_PREDICT_TRUE(n != 0)) {
|
||||||
|
value_type dealias = v;
|
||||||
|
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2
|
||||||
|
// It appears that GCC thinks that since `pos` is a const pointer and may
|
||||||
|
// point to uninitialized memory at this point, a warning should be
|
||||||
|
// issued. But `pos` is actually only used to compute an array index to
|
||||||
|
// write to.
|
||||||
|
#if !defined(__clang__) && defined(__GNUC__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||||
|
#endif
|
||||||
|
return storage_.Insert(pos, CopyValueAdapter<A>(std::addressof(dealias)),
|
||||||
|
n);
|
||||||
|
#if !defined(__clang__) && defined(__GNUC__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
return const_cast<iterator>(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::insert(...)` that inserts copies of the
|
||||||
|
// elements of `list` starting at `pos`, returning an `iterator` pointing to
|
||||||
|
// the first of the newly inserted elements.
|
||||||
|
iterator insert(const_iterator pos, std::initializer_list<value_type> list) {
|
||||||
|
return insert(pos, list.begin(), list.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
|
||||||
|
// `last`) starting at `pos`, returning an `iterator` pointing to the first
|
||||||
|
// of the newly inserted elements.
|
||||||
|
//
|
||||||
|
// NOTE: this overload is for iterators that are "forward" category or better.
|
||||||
|
template <typename ForwardIterator,
|
||||||
|
EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
|
||||||
|
iterator insert(const_iterator pos, ForwardIterator first,
|
||||||
|
ForwardIterator last) {
|
||||||
|
ABSL_HARDENING_ASSERT(pos >= begin());
|
||||||
|
ABSL_HARDENING_ASSERT(pos <= end());
|
||||||
|
|
||||||
|
if (ABSL_PREDICT_TRUE(first != last)) {
|
||||||
|
return storage_.Insert(pos,
|
||||||
|
IteratorValueAdapter<A, ForwardIterator>(first),
|
||||||
|
std::distance(first, last));
|
||||||
|
} else {
|
||||||
|
return const_cast<iterator>(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
|
||||||
|
// `last`) starting at `pos`, returning an `iterator` pointing to the first
|
||||||
|
// of the newly inserted elements.
|
||||||
|
//
|
||||||
|
// NOTE: this overload is for iterators that are "input" category.
|
||||||
|
template <typename InputIterator,
|
||||||
|
DisableIfAtLeastForwardIterator<InputIterator> = 0>
|
||||||
|
iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
|
||||||
|
ABSL_HARDENING_ASSERT(pos >= begin());
|
||||||
|
ABSL_HARDENING_ASSERT(pos <= end());
|
||||||
|
|
||||||
|
size_type index = std::distance(cbegin(), pos);
|
||||||
|
for (size_type i = index; first != last; ++i, static_cast<void>(++first)) {
|
||||||
|
insert(data() + i, *first);
|
||||||
|
}
|
||||||
|
|
||||||
|
return iterator(data() + index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::emplace(...)`
|
||||||
|
//
|
||||||
|
// Constructs and inserts an element using `args...` in the inlined vector at
|
||||||
|
// `pos`, returning an `iterator` pointing to the newly emplaced element.
|
||||||
|
template <typename... Args>
|
||||||
|
iterator emplace(const_iterator pos, Args&&... args) {
|
||||||
|
ABSL_HARDENING_ASSERT(pos >= begin());
|
||||||
|
ABSL_HARDENING_ASSERT(pos <= end());
|
||||||
|
|
||||||
|
value_type dealias(std::forward<Args>(args)...);
|
||||||
|
return storage_.Insert(pos,
|
||||||
|
IteratorValueAdapter<A, MoveIterator<A>>(
|
||||||
|
MoveIterator<A>(std::addressof(dealias))),
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::emplace_back(...)`
|
||||||
|
//
|
||||||
|
// Constructs and inserts an element using `args...` in the inlined vector at
|
||||||
|
// `end()`, returning a `reference` to the newly emplaced element.
|
||||||
|
template <typename... Args>
|
||||||
|
reference emplace_back(Args&&... args) {
|
||||||
|
return storage_.EmplaceBack(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::push_back(...)`
|
||||||
|
//
|
||||||
|
// Inserts a copy of `v` in the inlined vector at `end()`.
|
||||||
|
void push_back(const_reference v) { static_cast<void>(emplace_back(v)); }
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()`
|
||||||
|
// using move semantics.
|
||||||
|
void push_back(value_type&& v) {
|
||||||
|
static_cast<void>(emplace_back(std::move(v)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::pop_back()`
|
||||||
|
//
|
||||||
|
// Destroys the element at `back()`, reducing the size by `1`.
|
||||||
|
void pop_back() noexcept {
|
||||||
|
ABSL_HARDENING_ASSERT(!empty());
|
||||||
|
|
||||||
|
AllocatorTraits<A>::destroy(storage_.GetAllocator(), data() + (size() - 1));
|
||||||
|
storage_.SubtractSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::erase(...)`
|
||||||
|
//
|
||||||
|
// Erases the element at `pos`, returning an `iterator` pointing to where the
|
||||||
|
// erased element was located.
|
||||||
|
//
|
||||||
|
// NOTE: may return `end()`, which is not dereferencable.
|
||||||
|
iterator erase(const_iterator pos) {
|
||||||
|
ABSL_HARDENING_ASSERT(pos >= begin());
|
||||||
|
ABSL_HARDENING_ASSERT(pos < end());
|
||||||
|
|
||||||
|
return storage_.Erase(pos, pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload of `InlinedVector::erase(...)` that erases every element in the
|
||||||
|
// range [`from`, `to`), returning an `iterator` pointing to where the first
|
||||||
|
// erased element was located.
|
||||||
|
//
|
||||||
|
// NOTE: may return `end()`, which is not dereferencable.
|
||||||
|
iterator erase(const_iterator from, const_iterator to) {
|
||||||
|
ABSL_HARDENING_ASSERT(from >= begin());
|
||||||
|
ABSL_HARDENING_ASSERT(from <= to);
|
||||||
|
ABSL_HARDENING_ASSERT(to <= end());
|
||||||
|
|
||||||
|
if (ABSL_PREDICT_TRUE(from != to)) {
|
||||||
|
return storage_.Erase(from, to);
|
||||||
|
} else {
|
||||||
|
return const_cast<iterator>(from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::clear()`
|
||||||
|
//
|
||||||
|
// Destroys all elements in the inlined vector, setting the size to `0` and
|
||||||
|
// deallocating any held memory.
|
||||||
|
void clear() noexcept {
|
||||||
|
inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
|
||||||
|
storage_.GetAllocator(), data(), size());
|
||||||
|
storage_.DeallocateIfAllocated();
|
||||||
|
|
||||||
|
storage_.SetInlinedSize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::reserve(...)`
|
||||||
|
//
|
||||||
|
// Ensures that there is enough room for at least `n` elements.
|
||||||
|
void reserve(size_type n) { storage_.Reserve(n); }
|
||||||
|
|
||||||
|
// `InlinedVector::shrink_to_fit()`
|
||||||
|
//
|
||||||
|
// Attempts to reduce memory usage by moving elements to (or keeping elements
|
||||||
|
// in) the smallest available buffer sufficient for containing `size()`
|
||||||
|
// elements.
|
||||||
|
//
|
||||||
|
// If `size()` is sufficiently small, the elements will be moved into (or kept
|
||||||
|
// in) the inlined space.
|
||||||
|
void shrink_to_fit() {
|
||||||
|
if (storage_.GetIsAllocated()) {
|
||||||
|
storage_.ShrinkToFit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `InlinedVector::swap(...)`
|
||||||
|
//
|
||||||
|
// Swaps the contents of the inlined vector with `other`.
|
||||||
|
void swap(InlinedVector& other) {
|
||||||
|
if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
|
||||||
|
storage_.Swap(std::addressof(other.storage_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename H, typename TheT, size_t TheN, typename TheA>
|
||||||
|
friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);
|
||||||
|
|
||||||
|
Storage storage_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// InlinedVector Non-Member Functions
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// `swap(...)`
|
||||||
|
//
|
||||||
|
// Swaps the contents of two inlined vectors.
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
void swap(absl::InlinedVector<T, N, A>& a,
|
||||||
|
absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
|
||||||
|
a.swap(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `operator==(...)`
|
||||||
|
//
|
||||||
|
// Tests for value-equality of two inlined vectors.
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
bool operator==(const absl::InlinedVector<T, N, A>& a,
|
||||||
|
const absl::InlinedVector<T, N, A>& b) {
|
||||||
|
auto a_data = a.data();
|
||||||
|
auto b_data = b.data();
|
||||||
|
return absl::equal(a_data, a_data + a.size(), b_data, b_data + b.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// `operator!=(...)`
|
||||||
|
//
|
||||||
|
// Tests for value-inequality of two inlined vectors.
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
bool operator!=(const absl::InlinedVector<T, N, A>& a,
|
||||||
|
const absl::InlinedVector<T, N, A>& b) {
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `operator<(...)`
|
||||||
|
//
|
||||||
|
// Tests whether the value of an inlined vector is less than the value of
|
||||||
|
// another inlined vector using a lexicographical comparison algorithm.
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
bool operator<(const absl::InlinedVector<T, N, A>& a,
|
||||||
|
const absl::InlinedVector<T, N, A>& b) {
|
||||||
|
auto a_data = a.data();
|
||||||
|
auto b_data = b.data();
|
||||||
|
return std::lexicographical_compare(a_data, a_data + a.size(), b_data,
|
||||||
|
b_data + b.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// `operator>(...)`
|
||||||
|
//
|
||||||
|
// Tests whether the value of an inlined vector is greater than the value of
|
||||||
|
// another inlined vector using a lexicographical comparison algorithm.
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
bool operator>(const absl::InlinedVector<T, N, A>& a,
|
||||||
|
const absl::InlinedVector<T, N, A>& b) {
|
||||||
|
return b < a;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `operator<=(...)`
|
||||||
|
//
|
||||||
|
// Tests whether the value of an inlined vector is less than or equal to the
|
||||||
|
// value of another inlined vector using a lexicographical comparison algorithm.
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
bool operator<=(const absl::InlinedVector<T, N, A>& a,
|
||||||
|
const absl::InlinedVector<T, N, A>& b) {
|
||||||
|
return !(b < a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `operator>=(...)`
|
||||||
|
//
|
||||||
|
// Tests whether the value of an inlined vector is greater than or equal to the
|
||||||
|
// value of another inlined vector using a lexicographical comparison algorithm.
|
||||||
|
template <typename T, size_t N, typename A>
|
||||||
|
bool operator>=(const absl::InlinedVector<T, N, A>& a,
|
||||||
|
const absl::InlinedVector<T, N, A>& b) {
|
||||||
|
return !(a < b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `AbslHashValue(...)`
|
||||||
|
//
|
||||||
|
// Provides `absl::Hash` support for `absl::InlinedVector`. It is uncommon to
|
||||||
|
// call this directly.
|
||||||
|
template <typename H, typename T, size_t N, typename A>
|
||||||
|
H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a) {
|
||||||
|
auto size = a.size();
|
||||||
|
return H::combine(H::combine_contiguous(std::move(h), a.data(), size), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_CONTAINER_INLINED_VECTOR_H_
|
||||||
2854
include/absl/container/internal/btree.h
Normal file
699
include/absl/container/internal/btree_container.h
Normal file
@ -0,0 +1,699 @@
|
|||||||
|
// Copyright 2018 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_
|
||||||
|
#define ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <iterator>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/internal/throw_delegate.h"
|
||||||
|
#include "absl/container/internal/btree.h" // IWYU pragma: export
|
||||||
|
#include "absl/container/internal/common.h"
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
|
#include "absl/meta/type_traits.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
namespace container_internal {
|
||||||
|
|
||||||
|
// A common base class for btree_set, btree_map, btree_multiset, and
|
||||||
|
// btree_multimap.
|
||||||
|
template <typename Tree>
|
||||||
|
class btree_container {
|
||||||
|
using params_type = typename Tree::params_type;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Alias used for heterogeneous lookup functions.
|
||||||
|
// `key_arg<K>` evaluates to `K` when the functors are transparent and to
|
||||||
|
// `key_type` otherwise. It permits template argument deduction on `K` for the
|
||||||
|
// transparent case.
|
||||||
|
template <class K>
|
||||||
|
using key_arg =
|
||||||
|
typename KeyArg<params_type::kIsKeyCompareTransparent>::template type<
|
||||||
|
K, typename Tree::key_type>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using key_type = typename Tree::key_type;
|
||||||
|
using value_type = typename Tree::value_type;
|
||||||
|
using size_type = typename Tree::size_type;
|
||||||
|
using difference_type = typename Tree::difference_type;
|
||||||
|
using key_compare = typename Tree::original_key_compare;
|
||||||
|
using value_compare = typename Tree::value_compare;
|
||||||
|
using allocator_type = typename Tree::allocator_type;
|
||||||
|
using reference = typename Tree::reference;
|
||||||
|
using const_reference = typename Tree::const_reference;
|
||||||
|
using pointer = typename Tree::pointer;
|
||||||
|
using const_pointer = typename Tree::const_pointer;
|
||||||
|
using iterator = typename Tree::iterator;
|
||||||
|
using const_iterator = typename Tree::const_iterator;
|
||||||
|
using reverse_iterator = typename Tree::reverse_iterator;
|
||||||
|
using const_reverse_iterator = typename Tree::const_reverse_iterator;
|
||||||
|
using node_type = typename Tree::node_handle_type;
|
||||||
|
|
||||||
|
// Constructors/assignments.
|
||||||
|
btree_container() : tree_(key_compare(), allocator_type()) {}
|
||||||
|
explicit btree_container(const key_compare &comp,
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: tree_(comp, alloc) {}
|
||||||
|
explicit btree_container(const allocator_type &alloc)
|
||||||
|
: tree_(key_compare(), alloc) {}
|
||||||
|
|
||||||
|
btree_container(const btree_container &other)
|
||||||
|
: btree_container(other, absl::allocator_traits<allocator_type>::
|
||||||
|
select_on_container_copy_construction(
|
||||||
|
other.get_allocator())) {}
|
||||||
|
btree_container(const btree_container &other, const allocator_type &alloc)
|
||||||
|
: tree_(other.tree_, alloc) {}
|
||||||
|
|
||||||
|
btree_container(btree_container &&other) noexcept(
|
||||||
|
std::is_nothrow_move_constructible<Tree>::value) = default;
|
||||||
|
btree_container(btree_container &&other, const allocator_type &alloc)
|
||||||
|
: tree_(std::move(other.tree_), alloc) {}
|
||||||
|
|
||||||
|
btree_container &operator=(const btree_container &other) = default;
|
||||||
|
btree_container &operator=(btree_container &&other) noexcept(
|
||||||
|
std::is_nothrow_move_assignable<Tree>::value) = default;
|
||||||
|
|
||||||
|
// Iterator routines.
|
||||||
|
iterator begin() { return tree_.begin(); }
|
||||||
|
const_iterator begin() const { return tree_.begin(); }
|
||||||
|
const_iterator cbegin() const { return tree_.begin(); }
|
||||||
|
iterator end() { return tree_.end(); }
|
||||||
|
const_iterator end() const { return tree_.end(); }
|
||||||
|
const_iterator cend() const { return tree_.end(); }
|
||||||
|
reverse_iterator rbegin() { return tree_.rbegin(); }
|
||||||
|
const_reverse_iterator rbegin() const { return tree_.rbegin(); }
|
||||||
|
const_reverse_iterator crbegin() const { return tree_.rbegin(); }
|
||||||
|
reverse_iterator rend() { return tree_.rend(); }
|
||||||
|
const_reverse_iterator rend() const { return tree_.rend(); }
|
||||||
|
const_reverse_iterator crend() const { return tree_.rend(); }
|
||||||
|
|
||||||
|
// Lookup routines.
|
||||||
|
template <typename K = key_type>
|
||||||
|
size_type count(const key_arg<K> &key) const {
|
||||||
|
auto equal_range = this->equal_range(key);
|
||||||
|
return std::distance(equal_range.first, equal_range.second);
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
iterator find(const key_arg<K> &key) {
|
||||||
|
return tree_.find(key);
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
const_iterator find(const key_arg<K> &key) const {
|
||||||
|
return tree_.find(key);
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
bool contains(const key_arg<K> &key) const {
|
||||||
|
return find(key) != end();
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
iterator lower_bound(const key_arg<K> &key) {
|
||||||
|
return tree_.lower_bound(key);
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
const_iterator lower_bound(const key_arg<K> &key) const {
|
||||||
|
return tree_.lower_bound(key);
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
iterator upper_bound(const key_arg<K> &key) {
|
||||||
|
return tree_.upper_bound(key);
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
const_iterator upper_bound(const key_arg<K> &key) const {
|
||||||
|
return tree_.upper_bound(key);
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
std::pair<iterator, iterator> equal_range(const key_arg<K> &key) {
|
||||||
|
return tree_.equal_range(key);
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
std::pair<const_iterator, const_iterator> equal_range(
|
||||||
|
const key_arg<K> &key) const {
|
||||||
|
return tree_.equal_range(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletion routines. Note that there is also a deletion routine that is
|
||||||
|
// specific to btree_set_container/btree_multiset_container.
|
||||||
|
|
||||||
|
// Erase the specified iterator from the btree. The iterator must be valid
|
||||||
|
// (i.e. not equal to end()). Return an iterator pointing to the node after
|
||||||
|
// the one that was erased (or end() if none exists).
|
||||||
|
iterator erase(const_iterator iter) { return tree_.erase(iterator(iter)); }
|
||||||
|
iterator erase(iterator iter) { return tree_.erase(iter); }
|
||||||
|
iterator erase(const_iterator first, const_iterator last) {
|
||||||
|
return tree_.erase_range(iterator(first), iterator(last)).second;
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
size_type erase(const key_arg<K> &key) {
|
||||||
|
auto equal_range = this->equal_range(key);
|
||||||
|
return tree_.erase_range(equal_range.first, equal_range.second).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract routines.
|
||||||
|
node_type extract(iterator position) {
|
||||||
|
// Use Construct instead of Transfer because the rebalancing code will
|
||||||
|
// destroy the slot later.
|
||||||
|
auto node =
|
||||||
|
CommonAccess::Construct<node_type>(get_allocator(), position.slot());
|
||||||
|
erase(position);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
node_type extract(const_iterator position) {
|
||||||
|
return extract(iterator(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility routines.
|
||||||
|
ABSL_ATTRIBUTE_REINITIALIZES void clear() { tree_.clear(); }
|
||||||
|
void swap(btree_container &other) { tree_.swap(other.tree_); }
|
||||||
|
void verify() const { tree_.verify(); }
|
||||||
|
|
||||||
|
// Size routines.
|
||||||
|
size_type size() const { return tree_.size(); }
|
||||||
|
size_type max_size() const { return tree_.max_size(); }
|
||||||
|
bool empty() const { return tree_.empty(); }
|
||||||
|
|
||||||
|
friend bool operator==(const btree_container &x, const btree_container &y) {
|
||||||
|
if (x.size() != y.size()) return false;
|
||||||
|
return std::equal(x.begin(), x.end(), y.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const btree_container &x, const btree_container &y) {
|
||||||
|
return !(x == y);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator<(const btree_container &x, const btree_container &y) {
|
||||||
|
return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator>(const btree_container &x, const btree_container &y) {
|
||||||
|
return y < x;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator<=(const btree_container &x, const btree_container &y) {
|
||||||
|
return !(y < x);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator>=(const btree_container &x, const btree_container &y) {
|
||||||
|
return !(x < y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The allocator used by the btree.
|
||||||
|
allocator_type get_allocator() const { return tree_.get_allocator(); }
|
||||||
|
|
||||||
|
// The key comparator used by the btree.
|
||||||
|
key_compare key_comp() const { return key_compare(tree_.key_comp()); }
|
||||||
|
value_compare value_comp() const { return tree_.value_comp(); }
|
||||||
|
|
||||||
|
// Support absl::Hash.
|
||||||
|
template <typename State>
|
||||||
|
friend State AbslHashValue(State h, const btree_container &b) {
|
||||||
|
for (const auto &v : b) {
|
||||||
|
h = State::combine(std::move(h), v);
|
||||||
|
}
|
||||||
|
return State::combine(std::move(h), b.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend struct btree_access;
|
||||||
|
Tree tree_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A common base class for btree_set and btree_map.
|
||||||
|
template <typename Tree>
|
||||||
|
class btree_set_container : public btree_container<Tree> {
|
||||||
|
using super_type = btree_container<Tree>;
|
||||||
|
using params_type = typename Tree::params_type;
|
||||||
|
using init_type = typename params_type::init_type;
|
||||||
|
using is_key_compare_to = typename params_type::is_key_compare_to;
|
||||||
|
friend class BtreeNodePeer;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <class K>
|
||||||
|
using key_arg = typename super_type::template key_arg<K>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using key_type = typename Tree::key_type;
|
||||||
|
using value_type = typename Tree::value_type;
|
||||||
|
using size_type = typename Tree::size_type;
|
||||||
|
using key_compare = typename Tree::original_key_compare;
|
||||||
|
using allocator_type = typename Tree::allocator_type;
|
||||||
|
using iterator = typename Tree::iterator;
|
||||||
|
using const_iterator = typename Tree::const_iterator;
|
||||||
|
using node_type = typename super_type::node_type;
|
||||||
|
using insert_return_type = InsertReturnType<iterator, node_type>;
|
||||||
|
|
||||||
|
// Inherit constructors.
|
||||||
|
using super_type::super_type;
|
||||||
|
btree_set_container() {}
|
||||||
|
|
||||||
|
// Range constructors.
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_set_container(InputIterator b, InputIterator e,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
insert(b, e);
|
||||||
|
}
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_set_container(InputIterator b, InputIterator e,
|
||||||
|
const allocator_type &alloc)
|
||||||
|
: btree_set_container(b, e, key_compare(), alloc) {}
|
||||||
|
|
||||||
|
// Initializer list constructors.
|
||||||
|
btree_set_container(std::initializer_list<init_type> init,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: btree_set_container(init.begin(), init.end(), comp, alloc) {}
|
||||||
|
btree_set_container(std::initializer_list<init_type> init,
|
||||||
|
const allocator_type &alloc)
|
||||||
|
: btree_set_container(init.begin(), init.end(), alloc) {}
|
||||||
|
|
||||||
|
// Insertion routines.
|
||||||
|
std::pair<iterator, bool> insert(const value_type &v) {
|
||||||
|
return this->tree_.insert_unique(params_type::key(v), v);
|
||||||
|
}
|
||||||
|
std::pair<iterator, bool> insert(value_type &&v) {
|
||||||
|
return this->tree_.insert_unique(params_type::key(v), std::move(v));
|
||||||
|
}
|
||||||
|
template <typename... Args>
|
||||||
|
std::pair<iterator, bool> emplace(Args &&... args) {
|
||||||
|
// Use a node handle to manage a temp slot.
|
||||||
|
auto node = CommonAccess::Construct<node_type>(this->get_allocator(),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
auto *slot = CommonAccess::GetSlot(node);
|
||||||
|
return this->tree_.insert_unique(params_type::key(slot), slot);
|
||||||
|
}
|
||||||
|
iterator insert(const_iterator hint, const value_type &v) {
|
||||||
|
return this->tree_
|
||||||
|
.insert_hint_unique(iterator(hint), params_type::key(v), v)
|
||||||
|
.first;
|
||||||
|
}
|
||||||
|
iterator insert(const_iterator hint, value_type &&v) {
|
||||||
|
return this->tree_
|
||||||
|
.insert_hint_unique(iterator(hint), params_type::key(v), std::move(v))
|
||||||
|
.first;
|
||||||
|
}
|
||||||
|
template <typename... Args>
|
||||||
|
iterator emplace_hint(const_iterator hint, Args &&... args) {
|
||||||
|
// Use a node handle to manage a temp slot.
|
||||||
|
auto node = CommonAccess::Construct<node_type>(this->get_allocator(),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
auto *slot = CommonAccess::GetSlot(node);
|
||||||
|
return this->tree_
|
||||||
|
.insert_hint_unique(iterator(hint), params_type::key(slot), slot)
|
||||||
|
.first;
|
||||||
|
}
|
||||||
|
template <typename InputIterator>
|
||||||
|
void insert(InputIterator b, InputIterator e) {
|
||||||
|
this->tree_.insert_iterator_unique(b, e, 0);
|
||||||
|
}
|
||||||
|
void insert(std::initializer_list<init_type> init) {
|
||||||
|
this->tree_.insert_iterator_unique(init.begin(), init.end(), 0);
|
||||||
|
}
|
||||||
|
insert_return_type insert(node_type &&node) {
|
||||||
|
if (!node) return {this->end(), false, node_type()};
|
||||||
|
std::pair<iterator, bool> res =
|
||||||
|
this->tree_.insert_unique(params_type::key(CommonAccess::GetSlot(node)),
|
||||||
|
CommonAccess::GetSlot(node));
|
||||||
|
if (res.second) {
|
||||||
|
CommonAccess::Destroy(&node);
|
||||||
|
return {res.first, true, node_type()};
|
||||||
|
} else {
|
||||||
|
return {res.first, false, std::move(node)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iterator insert(const_iterator hint, node_type &&node) {
|
||||||
|
if (!node) return this->end();
|
||||||
|
std::pair<iterator, bool> res = this->tree_.insert_hint_unique(
|
||||||
|
iterator(hint), params_type::key(CommonAccess::GetSlot(node)),
|
||||||
|
CommonAccess::GetSlot(node));
|
||||||
|
if (res.second) CommonAccess::Destroy(&node);
|
||||||
|
return res.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node extraction routines.
|
||||||
|
template <typename K = key_type>
|
||||||
|
node_type extract(const key_arg<K> &key) {
|
||||||
|
const std::pair<iterator, bool> lower_and_equal =
|
||||||
|
this->tree_.lower_bound_equal(key);
|
||||||
|
return lower_and_equal.second ? extract(lower_and_equal.first)
|
||||||
|
: node_type();
|
||||||
|
}
|
||||||
|
using super_type::extract;
|
||||||
|
|
||||||
|
// Merge routines.
|
||||||
|
// Moves elements from `src` into `this`. If the element already exists in
|
||||||
|
// `this`, it is left unmodified in `src`.
|
||||||
|
template <
|
||||||
|
typename T,
|
||||||
|
typename absl::enable_if_t<
|
||||||
|
absl::conjunction<
|
||||||
|
std::is_same<value_type, typename T::value_type>,
|
||||||
|
std::is_same<allocator_type, typename T::allocator_type>,
|
||||||
|
std::is_same<typename params_type::is_map_container,
|
||||||
|
typename T::params_type::is_map_container>>::value,
|
||||||
|
int> = 0>
|
||||||
|
void merge(btree_container<T> &src) { // NOLINT
|
||||||
|
for (auto src_it = src.begin(); src_it != src.end();) {
|
||||||
|
if (insert(std::move(params_type::element(src_it.slot()))).second) {
|
||||||
|
src_it = src.erase(src_it);
|
||||||
|
} else {
|
||||||
|
++src_it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename T,
|
||||||
|
typename absl::enable_if_t<
|
||||||
|
absl::conjunction<
|
||||||
|
std::is_same<value_type, typename T::value_type>,
|
||||||
|
std::is_same<allocator_type, typename T::allocator_type>,
|
||||||
|
std::is_same<typename params_type::is_map_container,
|
||||||
|
typename T::params_type::is_map_container>>::value,
|
||||||
|
int> = 0>
|
||||||
|
void merge(btree_container<T> &&src) {
|
||||||
|
merge(src);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base class for btree_map.
|
||||||
|
template <typename Tree>
|
||||||
|
class btree_map_container : public btree_set_container<Tree> {
|
||||||
|
using super_type = btree_set_container<Tree>;
|
||||||
|
using params_type = typename Tree::params_type;
|
||||||
|
friend class BtreeNodePeer;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <class K>
|
||||||
|
using key_arg = typename super_type::template key_arg<K>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using key_type = typename Tree::key_type;
|
||||||
|
using mapped_type = typename params_type::mapped_type;
|
||||||
|
using value_type = typename Tree::value_type;
|
||||||
|
using key_compare = typename Tree::original_key_compare;
|
||||||
|
using allocator_type = typename Tree::allocator_type;
|
||||||
|
using iterator = typename Tree::iterator;
|
||||||
|
using const_iterator = typename Tree::const_iterator;
|
||||||
|
|
||||||
|
// Inherit constructors.
|
||||||
|
using super_type::super_type;
|
||||||
|
btree_map_container() {}
|
||||||
|
|
||||||
|
// Insertion routines.
|
||||||
|
// Note: the nullptr template arguments and extra `const M&` overloads allow
|
||||||
|
// for supporting bitfield arguments.
|
||||||
|
template <typename K = key_type, class M>
|
||||||
|
std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k,
|
||||||
|
const M &obj) {
|
||||||
|
return insert_or_assign_impl(k, obj);
|
||||||
|
}
|
||||||
|
template <typename K = key_type, class M, K * = nullptr>
|
||||||
|
std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, const M &obj) {
|
||||||
|
return insert_or_assign_impl(std::forward<K>(k), obj);
|
||||||
|
}
|
||||||
|
template <typename K = key_type, class M, M * = nullptr>
|
||||||
|
std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k, M &&obj) {
|
||||||
|
return insert_or_assign_impl(k, std::forward<M>(obj));
|
||||||
|
}
|
||||||
|
template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
|
||||||
|
std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, M &&obj) {
|
||||||
|
return insert_or_assign_impl(std::forward<K>(k), std::forward<M>(obj));
|
||||||
|
}
|
||||||
|
template <typename K = key_type, class M>
|
||||||
|
iterator insert_or_assign(const_iterator hint, const key_arg<K> &k,
|
||||||
|
const M &obj) {
|
||||||
|
return insert_or_assign_hint_impl(hint, k, obj);
|
||||||
|
}
|
||||||
|
template <typename K = key_type, class M, K * = nullptr>
|
||||||
|
iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, const M &obj) {
|
||||||
|
return insert_or_assign_hint_impl(hint, std::forward<K>(k), obj);
|
||||||
|
}
|
||||||
|
template <typename K = key_type, class M, M * = nullptr>
|
||||||
|
iterator insert_or_assign(const_iterator hint, const key_arg<K> &k, M &&obj) {
|
||||||
|
return insert_or_assign_hint_impl(hint, k, std::forward<M>(obj));
|
||||||
|
}
|
||||||
|
template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
|
||||||
|
iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, M &&obj) {
|
||||||
|
return insert_or_assign_hint_impl(hint, std::forward<K>(k),
|
||||||
|
std::forward<M>(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename K = key_type, typename... Args,
|
||||||
|
typename absl::enable_if_t<
|
||||||
|
!std::is_convertible<K, const_iterator>::value, int> = 0>
|
||||||
|
std::pair<iterator, bool> try_emplace(const key_arg<K> &k, Args &&... args) {
|
||||||
|
return try_emplace_impl(k, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
template <typename K = key_type, typename... Args,
|
||||||
|
typename absl::enable_if_t<
|
||||||
|
!std::is_convertible<K, const_iterator>::value, int> = 0>
|
||||||
|
std::pair<iterator, bool> try_emplace(key_arg<K> &&k, Args &&... args) {
|
||||||
|
return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
template <typename K = key_type, typename... Args>
|
||||||
|
iterator try_emplace(const_iterator hint, const key_arg<K> &k,
|
||||||
|
Args &&... args) {
|
||||||
|
return try_emplace_hint_impl(hint, k, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
template <typename K = key_type, typename... Args>
|
||||||
|
iterator try_emplace(const_iterator hint, key_arg<K> &&k, Args &&... args) {
|
||||||
|
return try_emplace_hint_impl(hint, std::forward<K>(k),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename K = key_type>
|
||||||
|
mapped_type &operator[](const key_arg<K> &k) {
|
||||||
|
return try_emplace(k).first->second;
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
mapped_type &operator[](key_arg<K> &&k) {
|
||||||
|
return try_emplace(std::forward<K>(k)).first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename K = key_type>
|
||||||
|
mapped_type &at(const key_arg<K> &key) {
|
||||||
|
auto it = this->find(key);
|
||||||
|
if (it == this->end())
|
||||||
|
base_internal::ThrowStdOutOfRange("absl::btree_map::at");
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
template <typename K = key_type>
|
||||||
|
const mapped_type &at(const key_arg<K> &key) const {
|
||||||
|
auto it = this->find(key);
|
||||||
|
if (it == this->end())
|
||||||
|
base_internal::ThrowStdOutOfRange("absl::btree_map::at");
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Note: when we call `std::forward<M>(obj)` twice, it's safe because
|
||||||
|
// insert_unique/insert_hint_unique are guaranteed to not consume `obj` when
|
||||||
|
// `ret.second` is false.
|
||||||
|
template <class K, class M>
|
||||||
|
std::pair<iterator, bool> insert_or_assign_impl(K &&k, M &&obj) {
|
||||||
|
const std::pair<iterator, bool> ret =
|
||||||
|
this->tree_.insert_unique(k, std::forward<K>(k), std::forward<M>(obj));
|
||||||
|
if (!ret.second) ret.first->second = std::forward<M>(obj);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
template <class K, class M>
|
||||||
|
iterator insert_or_assign_hint_impl(const_iterator hint, K &&k, M &&obj) {
|
||||||
|
const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique(
|
||||||
|
iterator(hint), k, std::forward<K>(k), std::forward<M>(obj));
|
||||||
|
if (!ret.second) ret.first->second = std::forward<M>(obj);
|
||||||
|
return ret.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class... Args>
|
||||||
|
std::pair<iterator, bool> try_emplace_impl(K &&k, Args &&... args) {
|
||||||
|
return this->tree_.insert_unique(
|
||||||
|
k, std::piecewise_construct, std::forward_as_tuple(std::forward<K>(k)),
|
||||||
|
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
template <class K, class... Args>
|
||||||
|
iterator try_emplace_hint_impl(const_iterator hint, K &&k, Args &&... args) {
|
||||||
|
return this->tree_
|
||||||
|
.insert_hint_unique(iterator(hint), k, std::piecewise_construct,
|
||||||
|
std::forward_as_tuple(std::forward<K>(k)),
|
||||||
|
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||||
|
.first;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A common base class for btree_multiset and btree_multimap.
|
||||||
|
template <typename Tree>
|
||||||
|
class btree_multiset_container : public btree_container<Tree> {
|
||||||
|
using super_type = btree_container<Tree>;
|
||||||
|
using params_type = typename Tree::params_type;
|
||||||
|
using init_type = typename params_type::init_type;
|
||||||
|
using is_key_compare_to = typename params_type::is_key_compare_to;
|
||||||
|
friend class BtreeNodePeer;
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
using key_arg = typename super_type::template key_arg<K>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using key_type = typename Tree::key_type;
|
||||||
|
using value_type = typename Tree::value_type;
|
||||||
|
using size_type = typename Tree::size_type;
|
||||||
|
using key_compare = typename Tree::original_key_compare;
|
||||||
|
using allocator_type = typename Tree::allocator_type;
|
||||||
|
using iterator = typename Tree::iterator;
|
||||||
|
using const_iterator = typename Tree::const_iterator;
|
||||||
|
using node_type = typename super_type::node_type;
|
||||||
|
|
||||||
|
// Inherit constructors.
|
||||||
|
using super_type::super_type;
|
||||||
|
btree_multiset_container() {}
|
||||||
|
|
||||||
|
// Range constructors.
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_multiset_container(InputIterator b, InputIterator e,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: super_type(comp, alloc) {
|
||||||
|
insert(b, e);
|
||||||
|
}
|
||||||
|
template <class InputIterator>
|
||||||
|
btree_multiset_container(InputIterator b, InputIterator e,
|
||||||
|
const allocator_type &alloc)
|
||||||
|
: btree_multiset_container(b, e, key_compare(), alloc) {}
|
||||||
|
|
||||||
|
// Initializer list constructors.
|
||||||
|
btree_multiset_container(std::initializer_list<init_type> init,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
|
const allocator_type &alloc = allocator_type())
|
||||||
|
: btree_multiset_container(init.begin(), init.end(), comp, alloc) {}
|
||||||
|
btree_multiset_container(std::initializer_list<init_type> init,
|
||||||
|
const allocator_type &alloc)
|
||||||
|
: btree_multiset_container(init.begin(), init.end(), alloc) {}
|
||||||
|
|
||||||
|
// Insertion routines.
|
||||||
|
iterator insert(const value_type &v) { return this->tree_.insert_multi(v); }
|
||||||
|
iterator insert(value_type &&v) {
|
||||||
|
return this->tree_.insert_multi(std::move(v));
|
||||||
|
}
|
||||||
|
iterator insert(const_iterator hint, const value_type &v) {
|
||||||
|
return this->tree_.insert_hint_multi(iterator(hint), v);
|
||||||
|
}
|
||||||
|
iterator insert(const_iterator hint, value_type &&v) {
|
||||||
|
return this->tree_.insert_hint_multi(iterator(hint), std::move(v));
|
||||||
|
}
|
||||||
|
template <typename InputIterator>
|
||||||
|
void insert(InputIterator b, InputIterator e) {
|
||||||
|
this->tree_.insert_iterator_multi(b, e);
|
||||||
|
}
|
||||||
|
void insert(std::initializer_list<init_type> init) {
|
||||||
|
this->tree_.insert_iterator_multi(init.begin(), init.end());
|
||||||
|
}
|
||||||
|
template <typename... Args>
|
||||||
|
iterator emplace(Args &&... args) {
|
||||||
|
// Use a node handle to manage a temp slot.
|
||||||
|
auto node = CommonAccess::Construct<node_type>(this->get_allocator(),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
return this->tree_.insert_multi(CommonAccess::GetSlot(node));
|
||||||
|
}
|
||||||
|
template <typename... Args>
|
||||||
|
iterator emplace_hint(const_iterator hint, Args &&... args) {
|
||||||
|
// Use a node handle to manage a temp slot.
|
||||||
|
auto node = CommonAccess::Construct<node_type>(this->get_allocator(),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
return this->tree_.insert_hint_multi(iterator(hint),
|
||||||
|
CommonAccess::GetSlot(node));
|
||||||
|
}
|
||||||
|
iterator insert(node_type &&node) {
|
||||||
|
if (!node) return this->end();
|
||||||
|
iterator res =
|
||||||
|
this->tree_.insert_multi(params_type::key(CommonAccess::GetSlot(node)),
|
||||||
|
CommonAccess::GetSlot(node));
|
||||||
|
CommonAccess::Destroy(&node);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
iterator insert(const_iterator hint, node_type &&node) {
|
||||||
|
if (!node) return this->end();
|
||||||
|
iterator res = this->tree_.insert_hint_multi(
|
||||||
|
iterator(hint),
|
||||||
|
std::move(params_type::element(CommonAccess::GetSlot(node))));
|
||||||
|
CommonAccess::Destroy(&node);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node extraction routines.
|
||||||
|
template <typename K = key_type>
|
||||||
|
node_type extract(const key_arg<K> &key) {
|
||||||
|
const std::pair<iterator, bool> lower_and_equal =
|
||||||
|
this->tree_.lower_bound_equal(key);
|
||||||
|
return lower_and_equal.second ? extract(lower_and_equal.first)
|
||||||
|
: node_type();
|
||||||
|
}
|
||||||
|
using super_type::extract;
|
||||||
|
|
||||||
|
// Merge routines.
|
||||||
|
// Moves all elements from `src` into `this`.
|
||||||
|
template <
|
||||||
|
typename T,
|
||||||
|
typename absl::enable_if_t<
|
||||||
|
absl::conjunction<
|
||||||
|
std::is_same<value_type, typename T::value_type>,
|
||||||
|
std::is_same<allocator_type, typename T::allocator_type>,
|
||||||
|
std::is_same<typename params_type::is_map_container,
|
||||||
|
typename T::params_type::is_map_container>>::value,
|
||||||
|
int> = 0>
|
||||||
|
void merge(btree_container<T> &src) { // NOLINT
|
||||||
|
for (auto src_it = src.begin(), end = src.end(); src_it != end; ++src_it) {
|
||||||
|
insert(std::move(params_type::element(src_it.slot())));
|
||||||
|
}
|
||||||
|
src.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename T,
|
||||||
|
typename absl::enable_if_t<
|
||||||
|
absl::conjunction<
|
||||||
|
std::is_same<value_type, typename T::value_type>,
|
||||||
|
std::is_same<allocator_type, typename T::allocator_type>,
|
||||||
|
std::is_same<typename params_type::is_map_container,
|
||||||
|
typename T::params_type::is_map_container>>::value,
|
||||||
|
int> = 0>
|
||||||
|
void merge(btree_container<T> &&src) {
|
||||||
|
merge(src);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A base class for btree_multimap.
|
||||||
|
template <typename Tree>
|
||||||
|
class btree_multimap_container : public btree_multiset_container<Tree> {
|
||||||
|
using super_type = btree_multiset_container<Tree>;
|
||||||
|
using params_type = typename Tree::params_type;
|
||||||
|
friend class BtreeNodePeer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using mapped_type = typename params_type::mapped_type;
|
||||||
|
|
||||||
|
// Inherit constructors.
|
||||||
|
using super_type::super_type;
|
||||||
|
btree_multimap_container() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace container_internal
|
||||||
|
ABSL_NAMESPACE_END
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_
|
||||||