diff options
49 files changed, 1197 insertions, 295 deletions
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake new file mode 100644 index 00000000..8184d500 --- /dev/null +++ b/CMake/AbseilDll.cmake @@ -0,0 +1,492 @@ +include(CMakeParseArguments) + +set(ABSL_INTERNAL_DLL_FILES + "algorithm/algorithm.h" + "algorithm/container.h" + "base/attributes.h" + "base/call_once.h" + "base/casts.h" + "base/config.h" + "base/const_init.h" + "base/dynamic_annotations.cc" + "base/dynamic_annotations.h" + "base/internal/atomic_hook.h" + "base/internal/bits.h" + "base/internal/cycleclock.cc" + "base/internal/cycleclock.h" + "base/internal/direct_mmap.h" + "base/internal/endian.h" + "base/internal/exponential_biased.cc" + "base/internal/exponential_biased.h" + "base/internal/hide_ptr.h" + "base/internal/identity.h" + "base/internal/invoke.h" + "base/internal/inline_variable.h" + "base/internal/low_level_alloc.cc" + "base/internal/low_level_alloc.h" + "base/internal/low_level_scheduling.h" + "base/internal/per_thread_tls.h" + "base/internal/periodic_sampler.cc" + "base/internal/periodic_sampler.h" + "base/internal/pretty_function.h" + "base/internal/raw_logging.cc" + "base/internal/raw_logging.h" + "base/internal/scheduling_mode.h" + "base/internal/scoped_set_env.cc" + "base/internal/scoped_set_env.h" + "base/internal/spinlock.cc" + "base/internal/spinlock.h" + "base/internal/spinlock_wait.cc" + "base/internal/spinlock_wait.h" + "base/internal/sysinfo.cc" + "base/internal/sysinfo.h" + "base/internal/thread_annotations.h" + "base/internal/thread_identity.cc" + "base/internal/thread_identity.h" + "base/internal/throw_delegate.cc" + "base/internal/throw_delegate.h" + "base/internal/tsan_mutex_interface.h" + "base/internal/unaligned_access.h" + "base/internal/unscaledcycleclock.cc" + "base/internal/unscaledcycleclock.h" + "base/log_severity.cc" + "base/log_severity.h" + "base/macros.h" + "base/optimization.h" + "base/options.h" + "base/policy_checks.h" + "base/port.h" + "base/thread_annotations.h" + "container/btree_map.h" + "container/btree_set.h" + "container/fixed_array.h" + "container/flat_hash_map.h" + "container/flat_hash_set.h" + "container/inlined_vector.h" + "container/internal/btree.h" + "container/internal/btree_container.h" + "container/internal/common.h" + "container/internal/compressed_tuple.h" + "container/internal/container_memory.h" + "container/internal/counting_allocator.h" + "container/internal/hash_function_defaults.h" + "container/internal/hash_policy_traits.h" + "container/internal/hashtable_debug.h" + "container/internal/hashtable_debug_hooks.h" + "container/internal/hashtablez_sampler.cc" + "container/internal/hashtablez_sampler.h" + "container/internal/hashtablez_sampler_force_weak_definition.cc" + "container/internal/have_sse.h" + "container/internal/inlined_vector.h" + "container/internal/layout.h" + "container/internal/node_hash_policy.h" + "container/internal/raw_hash_map.h" + "container/internal/raw_hash_set.cc" + "container/internal/raw_hash_set.h" + "container/internal/tracked.h" + "container/node_hash_map.h" + "container/node_hash_set.h" + "debugging/failure_signal_handler.cc" + "debugging/failure_signal_handler.h" + "debugging/leak_check.h" + "debugging/leak_check_disable.cc" + "debugging/stacktrace.cc" + "debugging/stacktrace.h" + "debugging/symbolize.cc" + "debugging/symbolize.h" + "debugging/internal/address_is_readable.cc" + "debugging/internal/address_is_readable.h" + "debugging/internal/demangle.cc" + "debugging/internal/demangle.h" + "debugging/internal/elf_mem_image.cc" + "debugging/internal/elf_mem_image.h" + "debugging/internal/examine_stack.cc" + "debugging/internal/examine_stack.h" + "debugging/internal/stack_consumption.cc" + "debugging/internal/stack_consumption.h" + "debugging/internal/stacktrace_config.h" + "debugging/internal/symbolize.h" + "debugging/internal/vdso_support.cc" + "debugging/internal/vdso_support.h" + "functional/function_ref.h" + "functional/internal/function_ref.h" + "hash/hash.h" + "hash/internal/city.h" + "hash/internal/city.cc" + "hash/internal/hash.h" + "hash/internal/hash.cc" + "hash/internal/spy_hash_state.h" + "memory/memory.h" + "meta/type_traits.h" + "numeric/int128.cc" + "numeric/int128.h" + "random/bernoulli_distribution.h" + "random/beta_distribution.h" + "random/bit_gen_ref.h" + "random/discrete_distribution.cc" + "random/discrete_distribution.h" + "random/distribution_format_traits.h" + "random/distributions.h" + "random/exponential_distribution.h" + "random/gaussian_distribution.cc" + "random/gaussian_distribution.h" + "random/internal/distributions.h" + "random/internal/distribution_caller.h" + "random/internal/fast_uniform_bits.h" + "random/internal/fastmath.h" + "random/internal/gaussian_distribution_gentables.cc" + "random/internal/generate_real.h" + "random/internal/iostream_state_saver.h" + "random/internal/nonsecure_base.h" + "random/internal/pcg_engine.h" + "random/internal/platform.h" + "random/internal/pool_urbg.cc" + "random/internal/pool_urbg.h" + "random/internal/randen.cc" + "random/internal/randen.h" + "random/internal/randen_detect.cc" + "random/internal/randen_detect.h" + "random/internal/randen_engine.h" + "random/internal/randen_hwaes.cc" + "random/internal/randen_hwaes.h" + "random/internal/randen_slow.cc" + "random/internal/randen_slow.h" + "random/internal/randen_traits.h" + "random/internal/salted_seed_seq.h" + "random/internal/seed_material.cc" + "random/internal/seed_material.h" + "random/internal/sequence_urbg.h" + "random/internal/traits.h" + "random/internal/uniform_helper.h" + "random/internal/wide_multiply.h" + "random/log_uniform_int_distribution.h" + "random/poisson_distribution.h" + "random/random.h" + "random/seed_gen_exception.cc" + "random/seed_gen_exception.h" + "random/seed_sequences.cc" + "random/seed_sequences.h" + "random/uniform_int_distribution.h" + "random/uniform_real_distribution.h" + "random/zipf_distribution.h" + "strings/ascii.cc" + "strings/ascii.h" + "strings/charconv.cc" + "strings/charconv.h" + "strings/escaping.cc" + "strings/escaping.h" + "strings/internal/charconv_bigint.cc" + "strings/internal/charconv_bigint.h" + "strings/internal/charconv_parse.cc" + "strings/internal/charconv_parse.h" + "strings/internal/escaping.cc" + "strings/internal/escaping.h" + "strings/internal/stl_type_traits.h" + "strings/match.cc" + "strings/match.h" + "strings/numbers.cc" + "strings/numbers.h" + "strings/str_format.h" + "strings/str_cat.cc" + "strings/str_cat.h" + "strings/str_join.h" + "strings/str_replace.cc" + "strings/str_replace.h" + "strings/str_split.cc" + "strings/str_split.h" + "strings/string_view.cc" + "strings/string_view.h" + "strings/strip.h" + "strings/substitute.cc" + "strings/substitute.h" + "strings/internal/char_map.h" + "strings/internal/memutil.cc" + "strings/internal/memutil.h" + "strings/internal/ostringstream.cc" + "strings/internal/ostringstream.h" + "strings/internal/pow10_helper.cc" + "strings/internal/pow10_helper.h" + "strings/internal/resize_uninitialized.h" + "strings/internal/str_format/arg.cc" + "strings/internal/str_format/arg.h" + "strings/internal/str_format/bind.cc" + "strings/internal/str_format/bind.h" + "strings/internal/str_format/checker.h" + "strings/internal/str_format/extension.cc" + "strings/internal/str_format/extension.h" + "strings/internal/str_format/float_conversion.cc" + "strings/internal/str_format/float_conversion.h" + "strings/internal/str_format/output.cc" + "strings/internal/str_format/output.h" + "strings/internal/str_format/parser.cc" + "strings/internal/str_format/parser.h" + "strings/internal/str_join_internal.h" + "strings/internal/str_split_internal.h" + "strings/internal/utf8.cc" + "strings/internal/utf8.h" + "synchronization/barrier.cc" + "synchronization/barrier.h" + "synchronization/blocking_counter.cc" + "synchronization/blocking_counter.h" + "synchronization/mutex.cc" + "synchronization/mutex.h" + "synchronization/notification.cc" + "synchronization/notification.h" + "synchronization/internal/create_thread_identity.cc" + "synchronization/internal/create_thread_identity.h" + "synchronization/internal/graphcycles.cc" + "synchronization/internal/graphcycles.h" + "synchronization/internal/kernel_timeout.h" + "synchronization/internal/per_thread_sem.cc" + "synchronization/internal/per_thread_sem.h" + "synchronization/internal/thread_pool.h" + "synchronization/internal/waiter.cc" + "synchronization/internal/waiter.h" + "time/civil_time.cc" + "time/civil_time.h" + "time/clock.cc" + "time/clock.h" + "time/duration.cc" + "time/format.cc" + "time/time.cc" + "time/time.h" + "time/internal/cctz/include/cctz/civil_time.h" + "time/internal/cctz/include/cctz/civil_time_detail.h" + "time/internal/cctz/include/cctz/time_zone.h" + "time/internal/cctz/include/cctz/zone_info_source.h" + "time/internal/cctz/src/civil_time_detail.cc" + "time/internal/cctz/src/time_zone_fixed.cc" + "time/internal/cctz/src/time_zone_fixed.h" + "time/internal/cctz/src/time_zone_format.cc" + "time/internal/cctz/src/time_zone_if.cc" + "time/internal/cctz/src/time_zone_if.h" + "time/internal/cctz/src/time_zone_impl.cc" + "time/internal/cctz/src/time_zone_impl.h" + "time/internal/cctz/src/time_zone_info.cc" + "time/internal/cctz/src/time_zone_info.h" + "time/internal/cctz/src/time_zone_libc.cc" + "time/internal/cctz/src/time_zone_libc.h" + "time/internal/cctz/src/time_zone_lookup.cc" + "time/internal/cctz/src/time_zone_posix.cc" + "time/internal/cctz/src/time_zone_posix.h" + "time/internal/cctz/src/tzfile.h" + "time/internal/cctz/src/zone_info_source.cc" + "types/any.h" + "types/bad_any_cast.cc" + "types/bad_any_cast.h" + "types/bad_optional_access.cc" + "types/bad_optional_access.h" + "types/bad_variant_access.cc" + "types/bad_variant_access.h" + "types/compare.h" + "types/internal/conformance_aliases.h" + "types/internal/conformance_archetype.h" + "types/internal/conformance_profile.h" + "types/internal/variant.h" + "types/optional.h" + "types/internal/optional.h" + "types/span.h" + "types/internal/span.h" + "types/variant.h" + "utility/utility.h" +) + +set(ABSL_INTERNAL_DLL_TARGETS + "stacktrace" + "symbolize" + "examine_stack" + "failure_signal_handler" + "debugging_internal" + "demangle_internal" + "leak_check" + "leak_check_disable" + "stack_consumption" + "debugging" + "hash" + "spy_hash_state" + "city" + "memory" + "strings" + "strings_internal" + "str_format" + "str_format_internal" + "pow10_helper" + "int128" + "numeric" + "utility" + "any" + "bad_any_cast" + "bad_any_cast_impl" + "span" + "optional" + "bad_optional_access" + "bad_variant_access" + "variant" + "compare" + "algorithm" + "algorithm_container" + "graphcycles_internal" + "kernel_timeout_internal" + "synchronization" + "thread_pool" + "bind_front" + "function_ref" + "atomic_hook" + "log_severity" + "raw_logging_internal" + "spinlock_wait" + "config" + "dynamic_annotations" + "core_headers" + "malloc_internal" + "base_internal" + "base" + "throw_delegate" + "pretty_function" + "endian" + "bits" + "exponential_biased" + "periodic_sampler" + "scoped_set_env" + "type_traits" + "meta" + "random_random" + "random_bit_gen_ref" + "random_distributions" + "random_seed_gen_exception" + "random_seed_sequences" + "random_internal_traits" + "random_internal_distribution_caller" + "random_internal_distributions" + "random_internal_fast_uniform_bits" + "random_internal_seed_material" + "random_internal_pool_urbg" + "random_internal_explicit_seed_seq" + "random_internal_sequence_urbg" + "random_internal_salted_seed_seq" + "random_internal_iostream_state_saver" + "random_internal_generate_real" + "random_internal_wide_multiply" + "random_internal_fastmath" + "random_internal_nonsecure_base" + "random_internal_pcg_engine" + "random_internal_randen_engine" + "random_internal_platform" + "random_internal_randen" + "random_internal_randen_slow" + "random_internal_randen_hwaes" + "random_internal_randen_hwaes_impl" + "random_internal_uniform_helper" + "time" + "civil_time" + "time_zone" + "container" + "btree" + "compressed_tuple" + "fixed_array" + "inlined_vector_internal" + "inlined_vector" + "counting_allocator" + "flat_hash_map" + "flat_hash_set" + "node_hash_map" + "node_hash_set" + "container_memory" + "hash_function_defaults" + "hash_policy_traits" + "hashtablez_sampler" + "hashtable_debug" + "hashtable_debug_hooks" + "have_sse" + "node_hash_policy" + "raw_hash_map" + "container_common" + "raw_hash_set" + "layout" + "tracked" +) + +function(absl_internal_dll_contains) + cmake_parse_arguments(ABSL_INTERNAL_DLL + "" + "OUTPUT;TARGET" + "" + ${ARGN} + ) + + STRING(REGEX REPLACE "^absl::" "" _target ${ABSL_INTERNAL_DLL_TARGET}) + + list(FIND + ABSL_INTERNAL_DLL_TARGETS + "${_target}" + _index) + + if (${_index} GREATER -1) + set(${ABSL_INTERNAL_DLL_OUTPUT} 1 PARENT_SCOPE) + else() + set(${ABSL_INTERNAL_DLL_OUTPUT} 0 PARENT_SCOPE) + endif() +endfunction() + +function(absl_internal_dll_targets) + cmake_parse_arguments(ABSL_INTERNAL_DLL + "" + "OUTPUT" + "DEPS" + ${ARGN} + ) + + set(_deps "") + foreach(dep IN LISTS ABSL_INTERNAL_DLL_DEPS) + absl_internal_dll_contains(TARGET ${dep} OUTPUT _contains) + if (_contains) + list(APPEND _deps abseil_dll) + else() + list(APPEND _deps ${dep}) + endif() + endforeach() + + # Because we may have added the DLL multiple times + list(REMOVE_DUPLICATES _deps) + set(${ABSL_INTERNAL_DLL_OUTPUT} "${_deps}" PARENT_SCOPE) +endfunction() + +function(absl_make_dll) + add_library( + abseil_dll + SHARED + "${ABSL_INTERNAL_DLL_FILES}" + ) + target_link_libraries( + abseil_dll + PRIVATE + ${ABSL_DEFAULT_LINKOPTS} + ) + set_property(TARGET abseil_dll PROPERTY LINKER_LANGUAGE "CXX") + target_include_directories( + abseil_dll + PUBLIC + "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" + $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}> + ) + + target_compile_options( + abseil_dll + PRIVATE + ${ABSL_DEFAULT_COPTS} + ) + + target_compile_definitions( + abseil_dll + PRIVATE + ABSL_BUILD_DLL + NOMINMAX + INTERFACE + ${ABSL_CC_LIB_DEFINES} + ) + install(TARGETS abseil_dll EXPORT ${PROJECT_NAME}Targets + RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR} + LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR} + ) +endfunction() diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake index 28fefaa6..7571ef1b 100644 --- a/CMake/AbseilHelpers.cmake +++ b/CMake/AbseilHelpers.cmake @@ -16,6 +16,7 @@ include(CMakeParseArguments) include(AbseilConfigureCopts) +include(AbseilDll) include(AbseilInstallDirs) # The IDE folder for Abseil that will be used if Abseil is included in a CMake @@ -80,98 +81,169 @@ function(absl_cc_library) ${ARGN} ) - if(NOT ABSL_CC_LIB_TESTONLY OR ABSL_RUN_TESTS) - if(ABSL_ENABLE_INSTALL) - set(_NAME "${ABSL_CC_LIB_NAME}") - else() - set(_NAME "absl_${ABSL_CC_LIB_NAME}") + if(ABSL_CC_LIB_TESTONLY AND NOT ABSL_RUN_TESTS) + return() + endif() + + if(ABSL_ENABLE_INSTALL) + set(_NAME "${ABSL_CC_LIB_NAME}") + else() + set(_NAME "absl_${ABSL_CC_LIB_NAME}") + endif() + + # Check if this is a header-only library + # Note that as of February 2019, many popular OS's (for example, Ubuntu + # 16.04 LTS) only come with cmake 3.5 by default. For this reason, we can't + # use list(FILTER...) + set(ABSL_CC_SRCS "${ABSL_CC_LIB_SRCS}") + foreach(src_file IN LISTS ABSL_CC_SRCS) + if(${src_file} MATCHES ".*\\.(h|inc)") + list(REMOVE_ITEM ABSL_CC_SRCS "${src_file}") endif() + endforeach() - # Check if this is a header-only library - # Note that as of February 2019, many popular OS's (for example, Ubuntu - # 16.04 LTS) only come with cmake 3.5 by default. For this reason, we can't - # use list(FILTER...) - set(ABSL_CC_SRCS "${ABSL_CC_LIB_SRCS}") - foreach(src_file IN LISTS ABSL_CC_SRCS) - if(${src_file} MATCHES ".*\\.(h|inc)") - list(REMOVE_ITEM ABSL_CC_SRCS "${src_file}") - endif() - endforeach() - if("${ABSL_CC_SRCS}" STREQUAL "") + if("${ABSL_CC_SRCS}" STREQUAL "") + set(ABSL_CC_LIB_IS_INTERFACE 1) + else() + set(ABSL_CC_LIB_IS_INTERFACE 0) + endif() + + # Determine this build target's relationship to the DLL. It's one of three things: + # 1. "dll" -- This target is part of the DLL + # 2. "dll_dep" -- This target is not part of the DLL, but depends on the DLL. + # Note that we assume any target not in the DLL depends on the + # DLL. This is not a technical necessity but a convenience + # which happens to be true, because nearly every target is + # part of the DLL. + # 3. "static" -- This target does not depend on the DLL and should be built + # statically. + if (${ABSL_BUILD_DLL}) + absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll) + if (${_in_dll}) + # This target should be replaced by the DLL + set(_build_type "dll") set(ABSL_CC_LIB_IS_INTERFACE 1) else() - set(ABSL_CC_LIB_IS_INTERFACE 0) + # Building a DLL, but this target is not part of the DLL + set(_build_type "dll_dep") endif() + else() + set(_build_type "static") + endif() - if(NOT ABSL_CC_LIB_IS_INTERFACE) - # CMake creates static libraries by default. Users can specify - # -DBUILD_SHARED_LIBS=ON during initial configuration to build shared - # libraries instead. - add_library(${_NAME} "") + if(NOT ABSL_CC_LIB_IS_INTERFACE) + if(${_build_type} STREQUAL "dll_dep") + # This target depends on the DLL. When adding dependencies to this target, + # any depended-on-target which is contained inside the DLL is replaced + # with a dependency on the DLL. + add_library(${_NAME} STATIC "") target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS}) - target_include_directories(${_NAME} - PUBLIC - "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" - $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}> + absl_internal_dll_targets( + DEPS ${ABSL_CC_LIB_DEPS} + OUTPUT _dll_deps ) - target_compile_options(${_NAME} - PRIVATE ${ABSL_CC_LIB_COPTS}) target_link_libraries(${_NAME} - PUBLIC ${ABSL_CC_LIB_DEPS} + PUBLIC ${_dll_deps} PRIVATE ${ABSL_CC_LIB_LINKOPTS} ${ABSL_DEFAULT_LINKOPTS} ) - target_compile_definitions(${_NAME} PUBLIC ${ABSL_CC_LIB_DEFINES}) - # Add all Abseil targets to a a folder in the IDE for organization. - if(ABSL_CC_LIB_PUBLIC) - set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}) - elseif(ABSL_CC_LIB_TESTONLY) - set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test) + if (ABSL_CC_LIB_TESTONLY) + set(_gtest_link_define "GTEST_LINKED_AS_SHARED_LIBRARY=1") else() - set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal) + set(_gtest_link_define) endif() - # INTERFACE libraries can't have the CXX_STANDARD property set - set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD}) - set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) - - # When being installed, we lose the absl_ prefix. We want to put it back - # to have properly named lib files. This is a no-op when we are not being - # installed. - set_target_properties(${_NAME} PROPERTIES - OUTPUT_NAME "absl_${_NAME}" + target_compile_definitions(${_NAME} + PUBLIC + ABSL_CONSUME_DLL + "${_gtest_link_define}" ) - else() - # Generating header-only library - add_library(${_NAME} INTERFACE) - target_include_directories(${_NAME} - INTERFACE - "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" - $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}> - ) + + elseif(${_build_type} STREQUAL "static") + add_library(${_NAME} STATIC "") + target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS}) target_link_libraries(${_NAME} - INTERFACE - ${ABSL_CC_LIB_DEPS} - ${ABSL_CC_LIB_LINKOPTS} - ${ABSL_DEFAULT_LINKOPTS} + PUBLIC ${ABSL_CC_LIB_DEPS} + PRIVATE + ${ABSL_CC_LIB_LINKOPTS} + ${ABSL_DEFAULT_LINKOPTS} ) - target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES}) + else() + message(FATAL_ERROR "Invalid build type: ${_build_type}") endif() - # TODO currently we don't install googletest alongside abseil sources, so - # installed abseil can't be tested. - if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL) - install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets - RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR} - LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR} + # Linker language can be inferred from sources, but in the case of DLLs we + # don't have any .cc files so it would be ambiguous. We could set it + # explicitly only in the case of DLLs but, because "CXX" is always the + # correct linker language for static or for shared libraries, we set it + # unconditionally. + set_property(TARGET ${_NAME} PROPERTY LINKER_LANGUAGE "CXX") + + target_include_directories(${_NAME} + PUBLIC + "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" + $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}> + ) + target_compile_options(${_NAME} + PRIVATE ${ABSL_CC_LIB_COPTS}) + target_compile_definitions(${_NAME} PUBLIC ${ABSL_CC_LIB_DEFINES}) + + # Add all Abseil targets to a a folder in the IDE for organization. + if(ABSL_CC_LIB_PUBLIC) + set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}) + elseif(ABSL_CC_LIB_TESTONLY) + set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test) + else() + set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal) + endif() + + # INTERFACE libraries can't have the CXX_STANDARD property set + set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD}) + set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) + + # When being installed, we lose the absl_ prefix. We want to put it back + # to have properly named lib files. This is a no-op when we are not being + # installed. + if(ABSL_ENABLE_INSTALL) + set_target_properties(${_NAME} PROPERTIES + OUTPUT_NAME "absl_${_NAME}" ) endif() + else() + # Generating header-only library + add_library(${_NAME} INTERFACE) + target_include_directories(${_NAME} + INTERFACE + "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" + $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}> + ) - add_library(absl::${ABSL_CC_LIB_NAME} ALIAS ${_NAME}) + if (${_build_type} STREQUAL "dll") + set(ABSL_CC_LIB_DEPS abseil_dll) + endif() + + target_link_libraries(${_NAME} + INTERFACE + ${ABSL_CC_LIB_DEPS} + ${ABSL_CC_LIB_LINKOPTS} + ${ABSL_DEFAULT_LINKOPTS} + ) + target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES}) + endif() + + # TODO currently we don't install googletest alongside abseil sources, so + # installed abseil can't be tested. + if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL) + install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets + RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR} + LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR} + ) endif() + + add_library(absl::${ABSL_CC_LIB_NAME} ALIAS ${_NAME}) endfunction() # absl_cc_test() @@ -224,23 +296,42 @@ function(absl_cc_test) ) set(_NAME "absl_${ABSL_CC_TEST_NAME}") + add_executable(${_NAME} "") target_sources(${_NAME} PRIVATE ${ABSL_CC_TEST_SRCS}) target_include_directories(${_NAME} PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} ) - target_compile_definitions(${_NAME} - PUBLIC ${ABSL_CC_TEST_DEFINES} - ) + + if (${ABSL_BUILD_DLL}) + target_compile_definitions(${_NAME} + PUBLIC + ${ABSL_CC_TEST_DEFINES} + ABSL_CONSUME_DLL + GTEST_LINKED_AS_SHARED_LIBRARY=1 + ) + + # Replace dependencies on targets inside the DLL with abseil_dll itself. + absl_internal_dll_targets( + DEPS ${ABSL_CC_TEST_DEPS} + OUTPUT ABSL_CC_TEST_DEPS + ) + else() + target_compile_definitions(${_NAME} + PUBLIC + ${ABSL_CC_TEST_DEFINES} + ) + endif() target_compile_options(${_NAME} PRIVATE ${ABSL_CC_TEST_COPTS} ) + target_link_libraries(${_NAME} PUBLIC ${ABSL_CC_TEST_DEPS} PRIVATE ${ABSL_CC_TEST_LINKOPTS} ) - # Add all Abseil targets to a a folder in the IDE for organization. + # Add all Abseil targets to a folder in the IDE for organization. set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test) set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD}) diff --git a/CMake/Googletest/DownloadGTest.cmake b/CMake/Googletest/DownloadGTest.cmake index 3c682aef..8a00b455 100644 --- a/CMake/Googletest/DownloadGTest.cmake +++ b/CMake/Googletest/DownloadGTest.cmake @@ -7,6 +7,13 @@ configure_file( ${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt ) +set(ABSL_SAVE_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) +set(ABSL_SAVE_CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +if (BUILD_SHARED_LIBS) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_CREATE_SHARED_LIBRARY=1") +endif() + # Configure and build the downloaded googletest source execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . RESULT_VARIABLE result @@ -22,6 +29,9 @@ if(result) message(FATAL_ERROR "Build step for googletest failed: ${result}") endif() +set(CMAKE_CXX_FLAGS ${ABSL_SAVE_CMAKE_CXX_FLAGS}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${ABSL_SAVE_CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + # Prevent overriding the parent project's compiler/linker settings on Windows set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86f56344..fdfb2cfa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,12 @@ cmake_policy(SET CMP0048 NEW) project(absl CXX) +# Output directory is correct by default for most build setups. However, when +# building Abseil as a DLL, it is important to have the DLL in the same +# directory as the executable using it. Thus, we put all executables in a single +# /bin directory. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + # when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp)) # in the source tree of a project that uses it, install rules are disabled. if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$") @@ -47,6 +53,7 @@ list(APPEND CMAKE_MODULE_PATH include(AbseilInstallDirs) include(CMakePackageConfigHelpers) +include(AbseilDll) include(AbseilHelpers) diff --git a/absl/CMakeLists.txt b/absl/CMakeLists.txt index 3e78397c..a1b1f8d8 100644 --- a/absl/CMakeLists.txt +++ b/absl/CMakeLists.txt @@ -14,8 +14,6 @@ # limitations under the License. # - - add_subdirectory(base) add_subdirectory(algorithm) add_subdirectory(container) @@ -31,3 +29,7 @@ add_subdirectory(synchronization) add_subdirectory(time) add_subdirectory(types) add_subdirectory(utility) + +if (${ABSL_BUILD_DLL}) + absl_make_dll() +endif() diff --git a/absl/base/attributes.h b/absl/base/attributes.h index acd1c526..8f77db77 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h @@ -563,7 +563,19 @@ // ABSL_ATTRIBUTE_PACKED // -// Prevents the compiler from padding a structure to natural alignment +// Instructs the compiler not to use natural alignment for a tagged data +// structure, but instead to reduce its alignment to 1. 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 microprosessor supports non-aligned accesses. #if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__)) #define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__)) #else diff --git a/absl/base/config.h b/absl/base/config.h index c4e8dce4..eac5d268 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -643,4 +643,23 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #undef ABSL_INTERNAL_HAS_KEYWORD +// 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) + #endif // ABSL_BASE_CONFIG_H_ diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc index d79c5486..e36eb29a 100644 --- a/absl/base/internal/raw_logging.cc +++ b/absl/base/internal/raw_logging.cc @@ -225,8 +225,9 @@ bool RawLoggingFullySupported() { #endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED } -ABSL_CONST_INIT absl::base_internal::AtomicHook<InternalLogFunction> - internal_log_function(DefaultInternalLog); +ABSL_CONST_INIT ABSL_DLL + absl::base_internal::AtomicHook<InternalLogFunction> + internal_log_function(DefaultInternalLog); void RegisterInternalLogFunction(InternalLogFunction func) { internal_log_function.Store(func); diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h index cff45058..ac74f97d 100644 --- a/absl/base/internal/raw_logging.h +++ b/absl/base/internal/raw_logging.h @@ -22,9 +22,11 @@ #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 @@ -168,7 +170,8 @@ using InternalLogFunction = void (*)(absl::LogSeverity severity, const char* file, int line, const std::string& message); -extern base_internal::AtomicHook<InternalLogFunction> internal_log_function; +ABSL_DLL extern base_internal::AtomicHook<InternalLogFunction> + internal_log_function; void RegisterInternalLogFunction(InternalLogFunction func); diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc index 7945322f..a0930e97 100644 --- a/absl/base/internal/sysinfo.cc +++ b/absl/base/internal/sysinfo.cc @@ -58,10 +58,6 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace base_internal { -static once_flag init_system_info_once; -static int num_cpus = 0; -static double nominal_cpu_frequency = 1.0; // 0.0 might be dangerous. - static int GetNumCPUs() { #if defined(__myriad2__) return 1; @@ -265,21 +261,27 @@ static double GetNominalCPUFrequency() { #endif -// InitializeSystemInfo() may be called before main() and before -// malloc is properly initialized, therefore this must not allocate -// memory. -static void InitializeSystemInfo() { - num_cpus = GetNumCPUs(); - nominal_cpu_frequency = GetNominalCPUFrequency(); -} +ABSL_CONST_INIT static once_flag init_num_cpus_once; +ABSL_CONST_INIT static int num_cpus = 0; +// NumCPUs() may be called before main() and before malloc is properly +// initialized, therefore this must not allocate memory. int NumCPUs() { - base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo); + base_internal::LowLevelCallOnce( + &init_num_cpus_once, []() { num_cpus = GetNumCPUs(); }); return num_cpus; } +// A default frequency of 0.0 might be dangerous if it is used in division. +ABSL_CONST_INIT static once_flag init_nominal_cpu_frequency_once; +ABSL_CONST_INIT static double nominal_cpu_frequency = 1.0; + +// NominalCPUFrequency() may be called before main() and before malloc is +// properly initialized, therefore this must not allocate memory. double NominalCPUFrequency() { - base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo); + base_internal::LowLevelCallOnce( + &init_nominal_cpu_frequency_once, + []() { nominal_cpu_frequency = GetNominalCPUFrequency(); }); return nominal_cpu_frequency; } diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc index 6a28f246..d63a04ae 100644 --- a/absl/base/internal/thread_identity.cc +++ b/absl/base/internal/thread_identity.cc @@ -113,6 +113,18 @@ void SetCurrentThreadIdentity( #endif } +#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \ + ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11 + +// Please see the comment on `CurrentThreadIdentityIfPresent` in +// thread_identity.h. Because DLLs cannot expose thread_local variables in +// headers, we opt for the correct-but-slower option of placing the definition +// of this function only in a translation unit inside DLL. +#if defined(ABSL_BUILD_DLL) || defined(ABSL_CONSUME_DLL) +ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; } +#endif +#endif + void ClearCurrentThreadIdentity() { #if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \ ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11 diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h index 5dfd0715..ceb109b4 100644 --- a/absl/base/internal/thread_identity.h +++ b/absl/base/internal/thread_identity.h @@ -30,6 +30,7 @@ #include <atomic> #include <cstdint> +#include "absl/base/config.h" #include "absl/base/internal/per_thread_tls.h" namespace absl { @@ -234,9 +235,17 @@ ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr; #error Thread-local storage not detected on this platform #endif +// thread_local variables cannot be in headers exposed by DLLs. However, it is +// important for performance reasons in general that +// `CurrentThreadIdentityIfPresent` be inlined. This is not possible across a +// DLL boundary so, with DLLs, we opt to have the function not be inlined. Note +// that `CurrentThreadIdentityIfPresent` is declared above so we can exclude +// this entire inline definition when compiling as a DLL. +#if !defined(ABSL_BUILD_DLL) && !defined(ABSL_CONSUME_DLL) inline ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; } +#endif #elif ABSL_THREAD_IDENTITY_MODE != \ ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC diff --git a/absl/base/options.h b/absl/base/options.h index 592b33b7..6868c77b 100644 --- a/absl/base/options.h +++ b/absl/base/options.h @@ -66,7 +66,13 @@ // 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. -// + +// Include a standard library header to allow configuration based on the +// standard library in use. +#ifdef __cplusplus +#include <ciso646> +#endif + // ----------------------------------------------------------------------------- // Type Compatibility Options // ----------------------------------------------------------------------------- @@ -158,7 +164,6 @@ #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 diff --git a/absl/container/btree_map.h b/absl/container/btree_map.h index cbfcb58c..d23f4ee5 100644 --- a/absl/container/btree_map.h +++ b/absl/container/btree_map.h @@ -226,6 +226,30 @@ class btree_map // 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 diff --git a/absl/container/btree_test.cc b/absl/container/btree_test.cc index 8692b9c2..af8ee00b 100644 --- a/absl/container/btree_test.cc +++ b/absl/container/btree_test.cc @@ -2345,6 +2345,65 @@ TEST(Btree, EraseIf) { } } +TEST(Btree, InsertOrAssign) { + absl::btree_map<int, int> m = {{1, 1}, {3, 3}}; + using value_type = typename decltype(m)::value_type; + + auto ret = m.insert_or_assign(4, 4); + EXPECT_EQ(*ret.first, value_type(4, 4)); + EXPECT_TRUE(ret.second); + ret = m.insert_or_assign(3, 100); + EXPECT_EQ(*ret.first, value_type(3, 100)); + EXPECT_FALSE(ret.second); + + auto hint_ret = m.insert_or_assign(ret.first, 3, 200); + EXPECT_EQ(*hint_ret, value_type(3, 200)); + hint_ret = m.insert_or_assign(m.find(1), 0, 1); + EXPECT_EQ(*hint_ret, value_type(0, 1)); + // Test with bad hint. + hint_ret = m.insert_or_assign(m.end(), -1, 1); + EXPECT_EQ(*hint_ret, value_type(-1, 1)); + + EXPECT_THAT(m, ElementsAre(Pair(-1, 1), Pair(0, 1), Pair(1, 1), Pair(3, 200), + Pair(4, 4))); +} + +TEST(Btree, InsertOrAssignMovableOnly) { + absl::btree_map<int, MovableOnlyInstance> m; + using value_type = typename decltype(m)::value_type; + + auto ret = m.insert_or_assign(4, MovableOnlyInstance(4)); + EXPECT_EQ(*ret.first, value_type(4, MovableOnlyInstance(4))); + EXPECT_TRUE(ret.second); + ret = m.insert_or_assign(4, MovableOnlyInstance(100)); + EXPECT_EQ(*ret.first, value_type(4, MovableOnlyInstance(100))); + EXPECT_FALSE(ret.second); + + auto hint_ret = m.insert_or_assign(ret.first, 3, MovableOnlyInstance(200)); + EXPECT_EQ(*hint_ret, value_type(3, MovableOnlyInstance(200))); + + EXPECT_EQ(m.size(), 2); +} + +TEST(Btree, BitfieldArgument) { + union { + int n : 1; + }; + n = 0; + absl::btree_map<int, int> m; + m.erase(n); + m.count(n); + m.find(n); + m.contains(n); + m.equal_range(n); + m.insert_or_assign(n, n); + m.insert_or_assign(m.end(), n, n); + m.try_emplace(n); + m.try_emplace(m.end(), n); + m.at(n); + m[n]; +} + } // namespace } // namespace container_internal ABSL_NAMESPACE_END diff --git a/absl/container/internal/btree_container.h b/absl/container/internal/btree_container.h index 04795c2e..3e6ff4b8 100644 --- a/absl/container/internal/btree_container.h +++ b/absl/container/internal/btree_container.h @@ -372,7 +372,7 @@ class btree_map_container : public btree_set_container<Tree> { using super_type = btree_set_container<Tree>; using params_type = typename Tree::params_type; - protected: + private: template <class K> using key_arg = typename super_type::template key_arg<K>; @@ -390,6 +390,69 @@ class btree_map_container : public btree_set_container<Tree> { btree_map_container() {} // Insertion routines. + // Note: the nullptr template arguments and extra `const M&` overloads allow + // for supporting bitfield arguments. + // 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 M> + std::pair<iterator, bool> insert_or_assign(const key_type &k, const M &obj) { + const std::pair<iterator, bool> ret = this->tree_.insert_unique(k, k, obj); + if (!ret.second) ret.first->second = obj; + return ret; + } + template <class M, key_type * = nullptr> + std::pair<iterator, bool> insert_or_assign(key_type &&k, const M &obj) { + const std::pair<iterator, bool> ret = + this->tree_.insert_unique(k, std::move(k), obj); + if (!ret.second) ret.first->second = obj; + return ret; + } + template <class M, M * = nullptr> + std::pair<iterator, bool> insert_or_assign(const key_type &k, M &&obj) { + const std::pair<iterator, bool> ret = + this->tree_.insert_unique(k, k, std::forward<M>(obj)); + if (!ret.second) ret.first->second = std::forward<M>(obj); + return ret; + } + template <class M, key_type * = nullptr, M * = nullptr> + std::pair<iterator, bool> insert_or_assign(key_type &&k, M &&obj) { + const std::pair<iterator, bool> ret = + this->tree_.insert_unique(k, std::move(k), std::forward<M>(obj)); + if (!ret.second) ret.first->second = std::forward<M>(obj); + return ret; + } + template <class M> + iterator insert_or_assign(const_iterator position, const key_type &k, + const M &obj) { + const std::pair<iterator, bool> ret = + this->tree_.insert_hint_unique(iterator(position), k, k, obj); + if (!ret.second) ret.first->second = obj; + return ret.first; + } + template <class M, key_type * = nullptr> + iterator insert_or_assign(const_iterator position, key_type &&k, + const M &obj) { + const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique( + iterator(position), k, std::move(k), obj); + if (!ret.second) ret.first->second = obj; + return ret.first; + } + template <class M, M * = nullptr> + iterator insert_or_assign(const_iterator position, const key_type &k, + M &&obj) { + const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique( + iterator(position), k, k, std::forward<M>(obj)); + if (!ret.second) ret.first->second = std::forward<M>(obj); + return ret.first; + } + template <class M, key_type * = nullptr, M * = nullptr> + iterator insert_or_assign(const_iterator position, key_type &&k, M &&obj) { + const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique( + iterator(position), k, std::move(k), std::forward<M>(obj)); + if (!ret.second) ret.first->second = std::forward<M>(obj); + return ret.first; + } template <typename... Args> std::pair<iterator, bool> try_emplace(const key_type &k, Args &&... args) { return this->tree_.insert_unique( diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc index e15f4444..56447251 100644 --- a/absl/container/internal/hashtablez_sampler.cc +++ b/absl/container/internal/hashtablez_sampler.cc @@ -39,17 +39,16 @@ ABSL_CONST_INIT std::atomic<bool> g_hashtablez_enabled{ ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_sample_parameter{1 << 10}; ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_max_samples{1 << 20}; -#if ABSL_PER_THREAD_TLS == 1 +#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) ABSL_PER_THREAD_TLS_KEYWORD absl::base_internal::ExponentialBiased g_exponential_biased_generator; #endif } // namespace -#if ABSL_PER_THREAD_TLS == 1 +#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0; -#endif // ABSL_PER_THREAD_TLS == 1 - +#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) HashtablezSampler& HashtablezSampler::Global() { static auto* sampler = new HashtablezSampler(); @@ -192,7 +191,7 @@ HashtablezInfo* SampleSlow(int64_t* next_sample) { return HashtablezSampler::Global().Register(); } -#if ABSL_PER_THREAD_TLS == 0 +#if !defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) *next_sample = std::numeric_limits<int64_t>::max(); return nullptr; #else diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h index c4f9629f..34d5e572 100644 --- a/absl/container/internal/hashtablez_sampler.h +++ b/absl/container/internal/hashtablez_sampler.h @@ -180,14 +180,23 @@ class HashtablezInfoHandle { HashtablezInfo* info_; }; -#if ABSL_PER_THREAD_TLS == 1 +#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) +#error ABSL_INTERNAL_HASHTABLEZ_SAMPLE cannot be directly set +#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) + +#if (ABSL_PER_THREAD_TLS == 1) && !defined(ABSL_BUILD_DLL) && \ + !defined(ABSL_CONSUME_DLL) +#define ABSL_INTERNAL_HASHTABLEZ_SAMPLE +#endif + +#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample; #endif // ABSL_PER_THREAD_TLS // Returns an RAII sampling handle that manages registration and unregistation // with the global sampler. inline HashtablezInfoHandle Sample() { -#if ABSL_PER_THREAD_TLS == 1 +#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) { return HashtablezInfoHandle(nullptr); } diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc index 102b2375..36f5ccdd 100644 --- a/absl/container/internal/hashtablez_sampler_test.cc +++ b/absl/container/internal/hashtablez_sampler_test.cc @@ -169,7 +169,7 @@ TEST(HashtablezInfoTest, RecordRehash) { EXPECT_EQ(info.num_erases.load(), 0); } -#if ABSL_PER_THREAD_TLS == 1 +#if defined(ABSL_HASHTABLEZ_SAMPLE) TEST(HashtablezSamplerTest, SmallSampleParameter) { SetHashtablezEnabled(true); SetHashtablezSampleParameter(100); diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index 38e5e0e8..a96ae68a 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -418,53 +418,6 @@ TEST(Table, Empty) { EXPECT_TRUE(t.empty()); } -#ifdef __GNUC__ -template <class T> -ABSL_ATTRIBUTE_ALWAYS_INLINE inline void DoNotOptimize(const T& v) { - asm volatile("" : : "r,m"(v) : "memory"); -} -#endif - -TEST(Table, Prefetch) { - IntTable t; - t.emplace(1); - // Works for both present and absent keys. - t.prefetch(1); - t.prefetch(2); - - // Do not run in debug mode, when prefetch is not implemented, or when - // sanitizers are enabled, or on WebAssembly. -#if defined(NDEBUG) && defined(__GNUC__) && defined(__x86_64__) && \ - !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \ - !defined(THREAD_SANITIZER) && !defined(UNDEFINED_BEHAVIOR_SANITIZER) && \ - !defined(__EMSCRIPTEN__) - const auto now = [] { return absl::base_internal::CycleClock::Now(); }; - - // Make size enough to not fit in L2 cache (16.7 Mb) - static constexpr int size = 1 << 22; - for (int i = 0; i < size; ++i) t.insert(i); - - int64_t no_prefetch = 0, prefetch = 0; - for (int iter = 0; iter < 10; ++iter) { - int64_t time = now(); - for (int i = 0; i < size; ++i) { - DoNotOptimize(t.find(i)); - } - no_prefetch += now() - time; - - time = now(); - for (int i = 0; i < size; ++i) { - t.prefetch(i + 20); - DoNotOptimize(t.find(i)); - } - prefetch += now() - time; - } - - // no_prefetch is at least 30% slower. - EXPECT_GE(1.0 * no_prefetch / prefetch, 1.3); -#endif -} - TEST(Table, LookupEmpty) { IntTable t; auto it = t.find(0); @@ -1842,7 +1795,7 @@ TEST(TableDeathTest, EraseOfEndAsserts) { EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()), kDeathMsg); } -#if ABSL_PER_THREAD_TLS == 1 +#if defined(ABSL_HASHTABLEZ_SAMPLE) TEST(RawHashSamplerTest, Sample) { // Enable the feature even if the prod default is off. SetHashtablezEnabled(true); @@ -1863,7 +1816,7 @@ TEST(RawHashSamplerTest, Sample) { EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()), 0.01, 0.005); } -#endif +#endif // ABSL_HASHTABLEZ_SAMPLER TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) { // Enable the feature even if the prod default is off. diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake index 7543928a..77d4ace8 100644 --- a/absl/copts/AbseilConfigureCopts.cmake +++ b/absl/copts/AbseilConfigureCopts.cmake @@ -5,6 +5,13 @@ set(ABSL_LSAN_LINKOPTS "") set(ABSL_HAVE_LSAN OFF) set(ABSL_DEFAULT_LINKOPTS "") +if (BUILD_SHARED_LIBS AND MSVC) + set(ABSL_BUILD_DLL TRUE) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +else() + set(ABSL_BUILD_DLL FALSE) +endif() + if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64") if (MSVC) set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_MSVC_X64_FLAGS}") diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index 0bac60b9..a1d03aab 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc @@ -473,6 +473,7 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { } #elif defined(_WIN32) +#if !defined(ABSL_CONSUME_DLL) TEST(Symbolize, Basics) { EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func))); @@ -511,6 +512,7 @@ TEST(Symbolize, SymbolizeWithDemangling) { EXPECT_TRUE(strstr(result, "Foo::func") != nullptr) << result; } +#endif // !defined(ABSL_CONSUME_DLL) #else // Symbolizer unimplemented TEST(Symbolize, Unimplemented) { diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 6c7b2b6e..cbdbae52 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -324,6 +324,23 @@ cc_test( ], ) +cc_binary( + name = "flag_benchmark", + testonly = 1, + srcs = [ + "flag_benchmark.cc", + ], + copts = ABSL_TEST_COPTS, + tags = ["benchmark"], + visibility = ["//visibility:private"], + deps = [ + ":flag", + "//absl/time", + "//absl/types:optional", + "@com_github_google_benchmark//:benchmark_main", + ], +) + cc_test( name = "marshalling_test", size = "small", diff --git a/absl/flags/flag.cc b/absl/flags/flag.cc index 9af80079..e67f7304 100644 --- a/absl/flags/flag.cc +++ b/absl/flags/flag.cc @@ -22,7 +22,14 @@ namespace absl { ABSL_NAMESPACE_BEGIN -// This global nutex protects on-demand construction of flag objects in MSVC +#ifndef NDEBUG +#define ABSL_FLAGS_GET(T) \ + T GetFlag(const absl::Flag<T>& flag) { return flag.Get(); } +ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(ABSL_FLAGS_GET) +#undef ABSL_FLAGS_GET +#endif + +// This global mutex protects on-demand construction of flag objects in MSVC // builds. #if defined(_MSC_VER) && !defined(__clang__) diff --git a/absl/flags/flag.h b/absl/flags/flag.h index cc22cdb9..bd61668f 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h @@ -186,25 +186,29 @@ class Flag { // // // FLAGS_firstname is a Flag of type `std::string` // std::string first_name = absl::GetFlag(FLAGS_firstname); -template <typename T, - typename std::enable_if< - !flags_internal::IsAtomicFlagTypeTrait<T>::value, int>::type = 0> -ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag) { - return flag.Get(); -} - +#ifndef NDEBUG // We want to validate the type mismatch between type definition and // declaration. The lock-free implementation does not allow us to do it, // so in debug builds we always use the slower implementation, which always // validates the type. -#ifndef NDEBUG +template <typename T> +ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag) { + return flag.Get(); +} +// We currently need an external linkage for built-in types because shared +// libraries have different addresses of flags_internal::FlagOps<T> which +// might cause log spam when checking the same flag type. +#define ABSL_FLAGS_INTERNAL_BUILT_IN_EXPORT(T) \ + ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag); +ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(ABSL_FLAGS_INTERNAL_BUILT_IN_EXPORT) +#undef ABSL_FLAGS_INTERNAL_BUILT_IN_EXPORT +#else template <typename T, typename std::enable_if< - flags_internal::IsAtomicFlagTypeTrait<T>::value, int>::type = 0> + !flags_internal::IsAtomicFlagTypeTrait<T>::value, int>::type = 0> ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag) { return flag.Get(); } -#else // Overload for `GetFlag()` for types that support lock-free reads. template <typename T, typename std::enable_if< diff --git a/absl/flags/flag_benchmark.cc b/absl/flags/flag_benchmark.cc new file mode 100644 index 00000000..87f73170 --- /dev/null +++ b/absl/flags/flag_benchmark.cc @@ -0,0 +1,111 @@ +// +// 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. + +#include "absl/flags/flag.h" +#include "absl/time/time.h" +#include "absl/types/optional.h" +#include "benchmark/benchmark.h" + +namespace { +using String = std::string; +using VectorOfStrings = std::vector<std::string>; +using AbslDuration = absl::Duration; + +// We do not want to take over marshalling for the types absl::optional<int>, +// absl::optional<std::string> which we do not own. Instead we introduce unique +// "aliases" to these types, which we do. +using AbslOptionalInt = absl::optional<int>; +struct OptionalInt : AbslOptionalInt { + using AbslOptionalInt::AbslOptionalInt; +}; +// Next two functions represent Abseil Flags marshalling for OptionalInt. +bool AbslParseFlag(absl::string_view src, OptionalInt* flag, + std::string* error) { + int val; + if (src.empty()) + flag->reset(); + else if (!absl::ParseFlag(src, &val, error)) + return false; + *flag = val; + return true; +} +std::string AbslUnparseFlag(const OptionalInt& flag) { + return !flag ? "" : absl::UnparseFlag(*flag); +} + +using AbslOptionalString = absl::optional<std::string>; +struct OptionalString : AbslOptionalString { + using AbslOptionalString::AbslOptionalString; +}; +// Next two functions represent Abseil Flags marshalling for OptionalString. +bool AbslParseFlag(absl::string_view src, OptionalString* flag, + std::string* error) { + std::string val; + if (src.empty()) + flag->reset(); + else if (!absl::ParseFlag(src, &val, error)) + return false; + *flag = val; + return true; +} +std::string AbslUnparseFlag(const OptionalString& flag) { + return !flag ? "" : absl::UnparseFlag(*flag); +} + +struct UDT { + UDT() = default; + UDT(const UDT&) {} + UDT& operator=(const UDT&) { return *this; } +}; +// Next two functions represent Abseil Flags marshalling for UDT. +bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; } +std::string AbslUnparseFlag(const UDT&) { return ""; } + +} // namespace + +#define BENCHMARKED_TYPES(A) \ + A(bool) \ + A(int16_t) \ + A(uint16_t) \ + A(int32_t) \ + A(uint32_t) \ + A(int64_t) \ + A(uint64_t) \ + A(double) \ + A(float) \ + A(String) \ + A(VectorOfStrings) \ + A(OptionalInt) \ + A(OptionalString) \ + A(AbslDuration) \ + A(UDT) + +#define FLAG_DEF(T) ABSL_FLAG(T, T##_flag, {}, ""); + +BENCHMARKED_TYPES(FLAG_DEF) + +namespace { + +#define BM_GetFlag(T) \ + void BM_GetFlag_##T(benchmark::State& state) { \ + for (auto _ : state) { \ + benchmark::DoNotOptimize(absl::GetFlag(FLAGS_##T##_flag)); \ + } \ + } \ + BENCHMARK(BM_GetFlag_##T); + +BENCHMARKED_TYPES(BM_GetFlag) + +} // namespace diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index 8639181f..ae7a60cd 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h @@ -708,7 +708,8 @@ struct is_hashable : std::integral_constant<bool, HashSelect::template Apply<T>::value> {}; // CityHashState -class CityHashState : public HashStateBase<CityHashState> { +class ABSL_DLL CityHashState + : public HashStateBase<CityHashState> { // absl::uint128 is not an alias or a thin wrapper around the intrinsic. // We use the intrinsic when available to improve performance. #ifdef ABSL_HAVE_INTRINSIC_INT128 diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc index a20a77e7..b605a870 100644 --- a/absl/numeric/int128.cc +++ b/absl/numeric/int128.cc @@ -25,8 +25,8 @@ namespace absl { ABSL_NAMESPACE_BEGIN -const uint128 kuint128max = MakeUint128(std::numeric_limits<uint64_t>::max(), - std::numeric_limits<uint64_t>::max()); +ABSL_DLL const uint128 kuint128max = MakeUint128( + std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max()); namespace { diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h index 718f70b1..636e3a5b 100644 --- a/absl/numeric/int128.h +++ b/absl/numeric/int128.h @@ -234,7 +234,7 @@ class // Prefer to use the constexpr `Uint128Max()`. // // TODO(absl-team) deprecate kuint128max once migration tool is released. -extern const uint128 kuint128max; +ABSL_DLL extern const uint128 kuint128max; // allow uint128 to be logged std::ostream& operator<<(std::ostream& os, uint128 v); diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel index 2585b397..f78fbc7e 100644 --- a/absl/random/BUILD.bazel +++ b/absl/random/BUILD.bazel @@ -67,6 +67,7 @@ cc_library( linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:base_internal", + "//absl/base:config", "//absl/base:core_headers", "//absl/meta:type_traits", "//absl/random/internal:distributions", @@ -183,6 +184,7 @@ cc_test( timeout = "eternal", # Android can take a very long time srcs = ["beta_distribution_test.cc"], copts = ABSL_TEST_COPTS, + flaky = 1, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":distributions", diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt index 46dbc3ef..efa55d8f 100644 --- a/absl/random/CMakeLists.txt +++ b/absl/random/CMakeLists.txt @@ -183,6 +183,7 @@ absl_cc_library( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::base_internal + absl::config absl::core_headers absl::random_internal_generate_real absl::random_internal_distributions diff --git a/absl/random/gaussian_distribution.h b/absl/random/gaussian_distribution.h index c1427b06..4b07a5c0 100644 --- a/absl/random/gaussian_distribution.h +++ b/absl/random/gaussian_distribution.h @@ -28,6 +28,7 @@ #include <limits> #include <type_traits> +#include "absl/base/config.h" #include "absl/random/internal/fast_uniform_bits.h" #include "absl/random/internal/generate_real.h" #include "absl/random/internal/iostream_state_saver.h" @@ -43,7 +44,7 @@ namespace random_internal { // The specific algorithm has some of the improvements suggested by the // 2005 paper, "An Improved Ziggurat Method to Generate Normal Random Samples", // Jurgen A Doornik. (https://www.doornik.com/research/ziggurat.pdf) -class gaussian_distribution_base { +class ABSL_DLL gaussian_distribution_base { public: template <typename URBG> inline double zignor(URBG& g); // NOLINT(runtime/references) diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index dc7e1bfd..d5a362d0 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -37,7 +37,6 @@ cc_library( "internal/charconv_bigint.h", "internal/charconv_parse.cc", "internal/charconv_parse.h", - "internal/escaping.cc", "internal/memutil.cc", "internal/memutil.h", "internal/stl_type_traits.h", @@ -55,7 +54,6 @@ cc_library( "ascii.h", "charconv.h", "escaping.h", - "internal/escaping.h", "match.h", "numbers.h", "str_cat.h", @@ -85,11 +83,13 @@ cc_library( cc_library( name = "internal", srcs = [ + "internal/escaping.cc", "internal/ostringstream.cc", "internal/utf8.cc", ], hdrs = [ "internal/char_map.h", + "internal/escaping.h", "internal/ostringstream.h", "internal/resize_uninitialized.h", "internal/utf8.h", @@ -99,6 +99,7 @@ cc_library( "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", + "//absl/base:raw_logging_internal", "//absl/meta:type_traits", ], ) diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 36702f71..3feb5e94 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -38,8 +38,6 @@ absl_cc_library( "internal/charconv_bigint.h" "internal/charconv_parse.cc" "internal/charconv_parse.h" - "internal/escaping.cc" - "internal/escaping.h" "internal/memutil.cc" "internal/memutil.h" "internal/stl_type_traits.h" @@ -74,6 +72,8 @@ absl_cc_library( strings_internal HDRS "internal/char_map.h" + "internal/escaping.cc" + "internal/escaping.h" "internal/ostringstream.h" "internal/resize_uninitialized.h" "internal/utf8.h" @@ -86,6 +86,7 @@ absl_cc_library( absl::config absl::core_headers absl::endian + absl::raw_logging_internal absl::type_traits ) diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc index abea3e4f..93bb03e9 100644 --- a/absl/strings/ascii.cc +++ b/absl/strings/ascii.cc @@ -57,7 +57,7 @@ namespace ascii_internal { // of these bits is tightly coupled to this implementation, the individual bits // are not named. Note that bitfields for all characters above ASCII 127 are // zero-initialized. -const unsigned char kPropertyBits[256] = { +ABSL_DLL const unsigned char kPropertyBits[256] = { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10 @@ -79,7 +79,7 @@ const unsigned char kPropertyBits[256] = { // Array of characters for the ascii_tolower() function. For values 'A' // through 'Z', return the lower-case character; otherwise, return the // identity of the passed character. -const char kToLower[256] = { +ABSL_DLL const char kToLower[256] = { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', @@ -117,7 +117,7 @@ const char kToLower[256] = { // Array of characters for the ascii_toupper() function. For values 'a' // through 'z', return the upper-case character; otherwise, return the // identity of the passed character. -const char kToUpper[256] = { +ABSL_DLL const char kToUpper[256] = { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h index 792aabe5..b46bc71f 100644 --- a/absl/strings/ascii.h +++ b/absl/strings/ascii.h @@ -56,6 +56,7 @@ #include <string> #include "absl/base/attributes.h" +#include "absl/base/config.h" #include "absl/strings/string_view.h" namespace absl { @@ -63,13 +64,13 @@ ABSL_NAMESPACE_BEGIN namespace ascii_internal { // Declaration for an array of bitfields holding character information. -extern const unsigned char kPropertyBits[256]; +ABSL_DLL extern const unsigned char kPropertyBits[256]; // Declaration for the array of characters to upper-case characters. -extern const char kToUpper[256]; +ABSL_DLL extern const char kToUpper[256]; // Declaration for the array of characters to lower-case characters. -extern const char kToLower[256]; +ABSL_DLL extern const char kToLower[256]; } // namespace ascii_internal diff --git a/absl/strings/internal/charconv_bigint.cc b/absl/strings/internal/charconv_bigint.cc index 860c27b2..66f33e72 100644 --- a/absl/strings/internal/charconv_bigint.cc +++ b/absl/strings/internal/charconv_bigint.cc @@ -158,12 +158,12 @@ const uint32_t* LargePowerOfFiveData(int i) { int LargePowerOfFiveSize(int i) { return 2 * i; } } // namespace -const uint32_t kFiveToNth[14] = { +ABSL_DLL const uint32_t kFiveToNth[14] = { 1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125, }; -const uint32_t kTenToNth[10] = { +ABSL_DLL const uint32_t kTenToNth[10] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, }; diff --git a/absl/strings/internal/charconv_bigint.h b/absl/strings/internal/charconv_bigint.h index 108e1eb2..999e9ae3 100644 --- a/absl/strings/internal/charconv_bigint.h +++ b/absl/strings/internal/charconv_bigint.h @@ -20,6 +20,7 @@ #include <iostream> #include <string> +#include "absl/base/config.h" #include "absl/strings/ascii.h" #include "absl/strings/internal/charconv_parse.h" #include "absl/strings/string_view.h" @@ -33,8 +34,9 @@ constexpr int kMaxSmallPowerOfFive = 13; // The largest power that 10 that can be raised to, and still fit in a uint32_t. constexpr int kMaxSmallPowerOfTen = 9; -extern const uint32_t kFiveToNth[kMaxSmallPowerOfFive + 1]; -extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1]; +ABSL_DLL extern const uint32_t + kFiveToNth[kMaxSmallPowerOfFive + 1]; +ABSL_DLL extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1]; // Large, fixed-width unsigned integer. // diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h index 2bf0c085..cf41b197 100644 --- a/absl/strings/internal/str_format/bind.h +++ b/absl/strings/internal/str_format/bind.h @@ -122,8 +122,8 @@ class FormatSpecTemplate #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER template <Conv... C, typename = typename std::enable_if< - sizeof...(C) == sizeof...(Args) && - AllOf(Contains(ArgumentToConv<Args>(), + AllOf(sizeof...(C) == sizeof...(Args), + Contains(ArgumentToConv<Args>(), C)...)>::type> FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT : Base(&pc) {} diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h index 51d7dd6f..0a764035 100644 --- a/absl/strings/internal/str_format/extension.h +++ b/absl/strings/internal/str_format/extension.h @@ -17,10 +17,12 @@ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ #include <limits.h> + #include <cstddef> #include <cstring> #include <ostream> +#include "absl/base/config.h" #include "absl/base/port.h" #include "absl/strings/internal/str_format/output.h" #include "absl/strings/string_view.h" @@ -134,7 +136,7 @@ struct Flags { } }; -struct LengthMod { +struct ABSL_DLL LengthMod { public: enum Id : uint8_t { h, hh, l, ll, L, j, z, t, q, none @@ -196,7 +198,7 @@ struct LengthMod { X_VAL(n) X_SEP X_VAL(p) // clang-format on -struct ConversionChar { +struct ABSL_DLL ConversionChar { public: enum Id : uint8_t { c, C, s, S, // text diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index a0e5a7fd..68c26dd6 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc @@ -900,9 +900,10 @@ inline bool safe_uint_internal(absl::string_view text, IntType* value_p, namespace numbers_internal { // Digit conversion. -ABSL_CONST_INIT const char kHexChar[] = "0123456789abcdef"; +ABSL_CONST_INIT ABSL_DLL const char kHexChar[] = + "0123456789abcdef"; -ABSL_CONST_INIT const char kHexTable[513] = +ABSL_CONST_INIT ABSL_DLL const char kHexTable[513] = "000102030405060708090a0b0c0d0e0f" "101112131415161718191a1b1c1d1e1f" "202122232425262728292a2b2c2d2e2f" @@ -920,7 +921,7 @@ ABSL_CONST_INIT const char kHexTable[513] = "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; -ABSL_CONST_INIT const char two_ASCII_digits[100][2] = { +ABSL_CONST_INIT ABSL_DLL const char two_ASCII_digits[100][2] = { {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h index 61204683..d872cca5 100644 --- a/absl/strings/numbers.h +++ b/absl/strings/numbers.h @@ -36,6 +36,7 @@ #include <string> #include <type_traits> +#include "absl/base/config.h" #include "absl/base/internal/bits.h" #ifdef __SSE4_2__ // TODO(jorg): Remove this when we figure out the right way @@ -106,9 +107,11 @@ ABSL_NAMESPACE_BEGIN namespace numbers_internal { // Digit conversion. -extern const char kHexChar[17]; // 0123456789abcdef -extern const char kHexTable[513]; // 000102030405060708090a0b0c0d0e0f1011... -extern const char two_ASCII_digits[100][2]; // 00, 01, 02, 03... +ABSL_DLL extern const char kHexChar[17]; // 0123456789abcdef +ABSL_DLL extern const char + kHexTable[513]; // 000102030405060708090a0b0c0d0e0f1011... +ABSL_DLL extern const char + two_ASCII_digits[100][2]; // 00, 01, 02, 03... // Writes a two-character representation of 'i' to 'buf'. 'i' must be in the // range 0 <= i < 100, and buf must have space for two characters. Example: diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index 4f7dd6b3..01965b0e 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h @@ -28,7 +28,19 @@ #define ABSL_STRINGS_STRING_VIEW_H_ #include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstring> +#include <iosfwd> +#include <iterator> +#include <limits> +#include <string> + #include "absl/base/config.h" +#include "absl/base/internal/throw_delegate.h" +#include "absl/base/macros.h" +#include "absl/base/optimization.h" +#include "absl/base/port.h" #ifdef ABSL_USES_STD_STRING_VIEW @@ -49,19 +61,6 @@ ABSL_NAMESPACE_END #define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp #endif // ABSL_HAVE_BUILTIN(__builtin_memcmp) -#include <cassert> -#include <cstddef> -#include <cstring> -#include <iosfwd> -#include <iterator> -#include <limits> -#include <string> - -#include "absl/base/internal/throw_delegate.h" -#include "absl/base/macros.h" -#include "absl/base/optimization.h" -#include "absl/base/port.h" - namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/time/format.cc b/absl/time/format.cc index 5997ef0c..ee088f33 100644 --- a/absl/time/format.cc +++ b/absl/time/format.cc @@ -24,11 +24,14 @@ namespace cctz = absl::time_internal::cctz; namespace absl { ABSL_NAMESPACE_BEGIN -extern const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez"; -extern const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez"; - -extern const char RFC1123_full[] = "%a, %d %b %E4Y %H:%M:%S %z"; -extern const char RFC1123_no_wday[] = "%d %b %E4Y %H:%M:%S %z"; +ABSL_DLL extern const char RFC3339_full[] = + "%Y-%m-%dT%H:%M:%E*S%Ez"; +ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez"; + +ABSL_DLL extern const char RFC1123_full[] = + "%a, %d %b %E4Y %H:%M:%S %z"; +ABSL_DLL extern const char RFC1123_no_wday[] = + "%d %b %E4Y %H:%M:%S %z"; namespace { diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc index a342e37d..303c0244 100644 --- a/absl/time/internal/cctz/src/time_zone_fixed.cc +++ b/absl/time/internal/cctz/src/time_zone_fixed.cc @@ -89,29 +89,29 @@ std::string FixedOffsetToName(const seconds& offset) { // offsets and to (somewhat) limit the total number of zones. return "UTC"; } - int seconds = static_cast<int>(offset.count()); - const char sign = (seconds < 0 ? '-' : '+'); - int minutes = seconds / 60; - seconds %= 60; + int offset_seconds = static_cast<int>(offset.count()); + const char sign = (offset_seconds < 0 ? '-' : '+'); + int offset_minutes = offset_seconds / 60; + offset_seconds %= 60; if (sign == '-') { - if (seconds > 0) { - seconds -= 60; - minutes += 1; + if (offset_seconds > 0) { + offset_seconds -= 60; + offset_minutes += 1; } - seconds = -seconds; - minutes = -minutes; + offset_seconds = -offset_seconds; + offset_minutes = -offset_minutes; } - int hours = minutes / 60; - minutes %= 60; + int offset_hours = offset_minutes / 60; + offset_minutes %= 60; const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1; char buf[prefix_len + sizeof("-24:00:00")]; char* ep = std::copy(kFixedZonePrefix, kFixedZonePrefix + prefix_len, buf); *ep++ = sign; - ep = Format02d(ep, hours); + ep = Format02d(ep, offset_hours); *ep++ = ':'; - ep = Format02d(ep, minutes); + ep = Format02d(ep, offset_minutes); *ep++ = ':'; - ep = Format02d(ep, seconds); + ep = Format02d(ep, offset_seconds); *ep++ = '\0'; assert(ep == buf + sizeof(buf)); return buf; diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc index de75629a..caebcc4d 100644 --- a/absl/time/internal/cctz/src/time_zone_format_test.cc +++ b/absl/time/internal/cctz/src/time_zone_format_test.cc @@ -1252,9 +1252,9 @@ TEST(Parse, ExtendedSubecondsScan) { const auto expected = chrono::system_clock::from_time_t(0) + chrono::nanoseconds(micros * 1000 + ns); for (int ps = 0; ps < 1000; ps += 250) { - std::ostringstream oss; + std::ostringstream ps_oss; oss << std::setfill('0') << std::setw(3) << ps; - const std::string input = nanos + oss.str() + "999"; + const std::string input = nanos + ps_oss.str() + "999"; EXPECT_TRUE(parse("%E*f", input, tz, &tp)); EXPECT_EQ(expected + chrono::nanoseconds(ps) / 1000, tp) << input; } diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc index 971542d0..f1697cdf 100644 --- a/absl/time/internal/cctz/src/time_zone_info.cc +++ b/absl/time/internal/cctz/src/time_zone_info.cc @@ -641,9 +641,9 @@ std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open( if (fp == nullptr) return nullptr; std::size_t length = 0; if (fseek(fp, 0, SEEK_END) == 0) { - long pos = ftell(fp); - if (pos >= 0) { - length = static_cast<std::size_t>(pos); + long offset = ftell(fp); + if (offset >= 0) { + length = static_cast<std::size_t>(offset); } rewind(fp); } diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index 227b1278..99137a08 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -1028,16 +1028,17 @@ TEST(MakeTime, LocalTimeLibC) { ASSERT_EQ(0, setenv("TZ", *np, 1)); // change what "localtime" means const auto zi = local_time_zone(); const auto lc = LoadZone("libc:localtime"); - time_zone::civil_transition trans; + time_zone::civil_transition transition; for (auto tp = zi.lookup(civil_second()).trans; - zi.next_transition(tp, &trans); tp = zi.lookup(trans.to).trans) { - const auto fcl = zi.lookup(trans.from); - const auto tcl = zi.lookup(trans.to); + zi.next_transition(tp, &transition); + tp = zi.lookup(transition.to).trans) { + const auto fcl = zi.lookup(transition.from); + const auto tcl = zi.lookup(transition.to); civil_second cs; // compare cs in zi and lc if (fcl.kind == time_zone::civil_lookup::UNIQUE) { if (tcl.kind == time_zone::civil_lookup::UNIQUE) { // Both unique; must be an is_dst or abbr change. - ASSERT_EQ(trans.from, trans.to); + ASSERT_EQ(transition.from, transition.to); const auto trans = fcl.trans; const auto tal = zi.lookup(trans); const auto tprev = trans - absl::time_internal::cctz::seconds(1); @@ -1048,11 +1049,11 @@ TEST(MakeTime, LocalTimeLibC) { continue; } ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind); - cs = trans.to; + cs = transition.to; } else { ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind); ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind); - cs = trans.from; + cs = transition.from; } if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t) const auto cl_zi = zi.lookup(cs); diff --git a/absl/time/time.h b/absl/time/time.h index 1be5727c..33a4a630 100644 --- a/absl/time/time.h +++ b/absl/time/time.h @@ -527,59 +527,30 @@ std::chrono::seconds ToChronoSeconds(Duration d); std::chrono::minutes ToChronoMinutes(Duration d); std::chrono::hours ToChronoHours(Duration d); - // FormatDuration() // -// Returns a string represention of the duration in a format consisting of a -// possibly-signed prefix and a sequence of decimal numbers, each with an -// optional fractional part and a unit suffix. -// -// Valid unit suffixes are "ns", "us" "ms", "s", "m", and "h". -// -// Simple examples include "300ms", "-1.5h", and "2h45m". Returns "inf" or -// "-inf" for +/- `InfiniteDuration()` values and "0" for `ZeroDuration()` -// values. -// -// This string format is used both as an input for parsing (when handling -// command-line flags of type `absl::Duration`) and as an output in -// `FormatDuration()` +// Returns a string representing the duration in the form "72h3m0.5s". +// Returns "inf" or "-inf" for +/- `InfiniteDuration()`. std::string FormatDuration(Duration d); +// Output stream operator. +inline std::ostream& operator<<(std::ostream& os, Duration d) { + return os << FormatDuration(d); +} + // ParseDuration() // -// Parses a `dur_string` of the format noted above into an `absl::Duration` -// value. -// -// Parses "0" as a zero-length duration value. Parses "-inf" or "+inf" as -// infinite durations values. +// Parses a duration string consisting of a possibly signed sequence of +// decimal numbers, each with an optional fractional part and a unit +// suffix. The valid suffixes are "ns", "us" "ms", "s", "m", and "h". +// Simple examples include "300ms", "-1.5h", and "2h45m". Parses "0" as +// `ZeroDuration()`. Parses "inf" and "-inf" as +/- `InfiniteDuration()`. bool ParseDuration(const std::string& dur_string, Duration* d); -// AbslParseFlag() -// -// Parses the command-line flag string representation `text` (using the format -// noted above) into an `absl::Duration` destination, setting `error` on -// failure. -// -// Example: -// -// --timeout=6h30m -// --timeout=inf // Equivalent to `InfiniteDuration()` -// --timeout=0 // Equivalent to `ZeroDuration()` +// Support for flag values of type Duration. Duration flags must be specified +// in a format that is valid input for absl::ParseDuration(). bool AbslParseFlag(absl::string_view text, Duration* dst, std::string* error); - -// AbslUnparseFlag() -// -// Unparses an `absl::Duration` into a command-line string representation using -// the format noted above. std::string AbslUnparseFlag(Duration d); - -// operator<<() -// -// Output stream operator, returning a stream in the format noted above. -inline std::ostream& operator<<(std::ostream& os, Duration d) { - return os << FormatDuration(d); -} - ABSL_DEPRECATED("Use AbslParseFlag() instead.") bool ParseFlag(const std::string& text, Duration* dst, std::string* error); ABSL_DEPRECATED("Use AbslUnparseFlag() instead.") @@ -842,29 +813,18 @@ Time FromChrono(const std::chrono::system_clock::time_point& tp); // // tp == std::chrono::system_clock::from_time_t(123); std::chrono::system_clock::time_point ToChronoTime(Time); -// AbslParseFlag() -// -// Parses the command-line flag string representation `text` into an -// `absl::Time` destination, setting `error` on failure. Time flag string -// representations must be specified in a format that matches -// `absl::RFC3339_full`. -// -// Example: +// Support for flag values of type Time. Time flags must be specified in a +// format that matches absl::RFC3339_full. For example: // // --start_time=2016-01-02T03:04:05.678+08:00 // // Note: A UTC offset (or 'Z' indicating a zero-offset from UTC) is required. // // Additionally, if you'd like to specify a time as a count of -// seconds/milliseconds/etc from the Unix epoch, use an `absl::Duration` flag -// and add that duration to `absl::UnixEpoch()` to get an `absl::Time`. +// seconds/milliseconds/etc from the Unix epoch, use an absl::Duration flag +// and add that duration to absl::UnixEpoch() to get an absl::Time. bool AbslParseFlag(absl::string_view text, Time* t, std::string* error); - -// AbslUnparseFlag() -// -// Unparses an `absl::Time` into a command-line string format as noted above. std::string AbslUnparseFlag(Time t); - ABSL_DEPRECATED("Use AbslParseFlag() instead.") bool ParseFlag(const std::string& text, Time* t, std::string* error); ABSL_DEPRECATED("Use AbslUnparseFlag() instead.") @@ -1243,15 +1203,18 @@ struct tm ToTM(Time t, TimeZone tz); // time with UTC offset. Also note the use of "%Y": RFC3339 mandates that // years have exactly four digits, but we allow them to take their natural // width. -extern const char RFC3339_full[]; // %Y-%m-%dT%H:%M:%E*S%Ez -extern const char RFC3339_sec[]; // %Y-%m-%dT%H:%M:%S%Ez +ABSL_DLL extern const char + RFC3339_full[]; // %Y-%m-%dT%H:%M:%E*S%Ez +ABSL_DLL extern const char RFC3339_sec[]; // %Y-%m-%dT%H:%M:%S%Ez // RFC1123_full // RFC1123_no_wday // // FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings. -extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z -extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z +ABSL_DLL extern const char + RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z +ABSL_DLL extern const char + RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z // FormatTime() // |