mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Update webrtc
This commit is contained in:
parent
c90f551614
commit
f55ba47e74
1105 changed files with 48591 additions and 15472 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit f76a9290fa502a8df473dd872aedf9a553b089cc
|
||||
Subproject commit 0f0ba327d636ab3f933624f11b5ef5678841c548
|
||||
140
third-party/webrtc/BUILD
vendored
140
third-party/webrtc/BUILD
vendored
|
|
@ -9,8 +9,11 @@ config_setting(
|
|||
)
|
||||
|
||||
optimization_flags = select({
|
||||
":debug_build": ["-O2", "-DNDEBUG"],
|
||||
#":debug_build": [],
|
||||
":debug_build": [
|
||||
#"-O2",
|
||||
#"-DNDEBUG",
|
||||
"-DRTC_DCHECK_IS_ON",
|
||||
],
|
||||
"//conditions:default": ["-DNDEBUG"],
|
||||
})
|
||||
|
||||
|
|
@ -32,7 +35,6 @@ absl_sources = [ "dependencies/third_party/abseil-cpp/" + x for x in [
|
|||
"absl/container/internal/hashtable_debug_hooks.h",
|
||||
"absl/strings/internal/cord_internal.h",
|
||||
"absl/base/internal/inline_variable.h",
|
||||
"absl/base/dynamic_annotations.cc",
|
||||
"absl/base/internal/cycleclock.cc",
|
||||
"absl/base/internal/exponential_biased.cc",
|
||||
"absl/base/internal/low_level_alloc.cc",
|
||||
|
|
@ -68,8 +70,6 @@ absl_sources = [ "dependencies/third_party/abseil-cpp/" + x for x in [
|
|||
"absl/flags/internal/commandlineflag.cc",
|
||||
"absl/flags/internal/flag.cc",
|
||||
"absl/flags/internal/program_name.cc",
|
||||
"absl/flags/internal/registry.cc",
|
||||
"absl/flags/internal/type_erased.cc",
|
||||
"absl/flags/internal/usage.cc",
|
||||
"absl/flags/marshalling.cc",
|
||||
"absl/flags/parse.cc",
|
||||
|
|
@ -201,7 +201,6 @@ absl_sources = [ "dependencies/third_party/abseil-cpp/" + x for x in [
|
|||
"absl/numeric/int128.h",
|
||||
"absl/flags/marshalling.h",
|
||||
"absl/flags/parse.h",
|
||||
"absl/flags/internal/type_erased.h",
|
||||
"absl/flags/internal/commandlineflag.h",
|
||||
"absl/flags/internal/program_name.h",
|
||||
"absl/flags/internal/usage.h",
|
||||
|
|
@ -260,7 +259,6 @@ absl_sources = [ "dependencies/third_party/abseil-cpp/" + x for x in [
|
|||
"absl/base/call_once.h",
|
||||
"absl/base/const_init.h",
|
||||
"absl/base/internal/atomic_hook.h",
|
||||
"absl/base/internal/bits.h",
|
||||
"absl/base/internal/endian.h",
|
||||
"absl/base/internal/errno_saver.h",
|
||||
"absl/base/internal/fast_type_id.h",
|
||||
|
|
@ -301,7 +299,6 @@ absl_sources = [ "dependencies/third_party/abseil-cpp/" + x for x in [
|
|||
"absl/hash/hash.h",
|
||||
"absl/random/internal/generate_real.h",
|
||||
"absl/random/internal/iostream_state_saver.h",
|
||||
"absl/random/internal/randen-keys.inc",
|
||||
"absl/random/internal/randen_engine.h",
|
||||
"absl/random/internal/randen_traits.h",
|
||||
"absl/strings/internal/resize_uninitialized.h",
|
||||
|
|
@ -607,7 +604,6 @@ webrtc_sources = [
|
|||
"api/neteq/neteq.cc",
|
||||
"api/neteq/tick_timer.cc",
|
||||
"api/peer_connection_interface.cc",
|
||||
"api/proxy.cc",
|
||||
"api/rtc_error.cc",
|
||||
"api/rtc_event_log/rtc_event.cc",
|
||||
"api/rtc_event_log/rtc_event_log.cc",
|
||||
|
|
@ -653,7 +649,6 @@ webrtc_sources = [
|
|||
"api/video_codecs/sdp_video_format.cc",
|
||||
"api/video_codecs/video_codec.cc",
|
||||
"api/video_codecs/video_decoder.cc",
|
||||
"api/video_codecs/video_decoder_factory.cc",
|
||||
"api/video_codecs/video_decoder_software_fallback_wrapper.cc",
|
||||
"api/video_codecs/video_encoder.cc",
|
||||
"api/video_codecs/video_encoder_config.cc",
|
||||
|
|
@ -726,16 +721,13 @@ webrtc_sources = [
|
|||
"media/base/media_constants.cc",
|
||||
"media/base/media_engine.cc",
|
||||
"media/base/rid_description.cc",
|
||||
"media/base/rtp_data_engine.cc",
|
||||
"media/base/rtp_utils.cc",
|
||||
"media/base/sdp_fmtp_utils.cc",
|
||||
"media/base/stream_params.cc",
|
||||
"media/base/turn_utils.cc",
|
||||
"media/base/video_adapter.cc",
|
||||
"media/base/video_broadcaster.cc",
|
||||
"media/base/video_common.cc",
|
||||
"media/base/video_source_base.cc",
|
||||
"media/base/vp9_profile.cc",
|
||||
"media/base/adapted_video_track_source.h",
|
||||
"media/engine/adm_helpers.cc",
|
||||
"media/engine/encoder_simulcast_proxy.cc",
|
||||
|
|
@ -753,8 +745,6 @@ webrtc_sources = [
|
|||
"media/engine/webrtc_video_engine.cc",
|
||||
"media/engine/webrtc_voice_engine.h",
|
||||
"media/engine/webrtc_voice_engine.cc",
|
||||
"media/sctp/noop.cc",
|
||||
"media/sctp/sctp_transport.cc",
|
||||
"system_wrappers/source/clock.cc",
|
||||
"system_wrappers/source/cpu_features.cc",
|
||||
"system_wrappers/source/cpu_info.cc",
|
||||
|
|
@ -1165,7 +1155,6 @@ webrtc_sources = [
|
|||
"modules/pacing/task_queue_paced_sender.cc",
|
||||
"modules/rtp_rtcp/include/report_block_data.cc",
|
||||
"modules/rtp_rtcp/include/rtp_rtcp_defines.cc",
|
||||
"modules/rtp_rtcp/source/absolute_capture_time_receiver.cc",
|
||||
"modules/rtp_rtcp/source/absolute_capture_time_sender.cc",
|
||||
"modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc",
|
||||
"modules/rtp_rtcp/source/dtmf_queue.cc",
|
||||
|
|
@ -1218,7 +1207,6 @@ webrtc_sources = [
|
|||
"modules/rtp_rtcp/source/rtp_descriptor_authentication.cc",
|
||||
"modules/rtp_rtcp/source/rtp_format.cc",
|
||||
"modules/rtp_rtcp/source/rtp_format_h264.cc",
|
||||
"modules/rtp_rtcp/source/rtp_format_h265.cc",
|
||||
"modules/rtp_rtcp/source/rtp_format_video_generic.cc",
|
||||
"modules/rtp_rtcp/source/rtp_format_vp8.cc",
|
||||
"modules/rtp_rtcp/source/rtp_format_vp9.cc",
|
||||
|
|
@ -1239,7 +1227,6 @@ webrtc_sources = [
|
|||
"modules/rtp_rtcp/source/rtp_sender_video.cc",
|
||||
"modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.cc",
|
||||
"modules/rtp_rtcp/source/rtp_sequence_number_map.cc",
|
||||
"modules/rtp_rtcp/source/rtp_utility.cc",
|
||||
"modules/rtp_rtcp/source/rtp_video_header.cc",
|
||||
"modules/rtp_rtcp/source/source_tracker.cc",
|
||||
"modules/rtp_rtcp/source/time_util.cc",
|
||||
|
|
@ -1251,7 +1238,6 @@ webrtc_sources = [
|
|||
"modules/rtp_rtcp/source/video_rtp_depacketizer_av1.cc",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_generic.cc",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_h264.cc",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_h265.cc",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_raw.cc",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_vp8.cc",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_vp9.cc",
|
||||
|
|
@ -1285,7 +1271,6 @@ webrtc_sources = [
|
|||
"modules/video_coding/generic_decoder.cc",
|
||||
"modules/video_coding/h264_sprop_parameter_sets.cc",
|
||||
"modules/video_coding/h264_sps_pps_tracker.cc",
|
||||
"modules/video_coding/h265_vps_sps_pps_tracker.cc",
|
||||
"modules/video_coding/histogram.cc",
|
||||
"modules/video_coding/include/video_codec_interface.cc",
|
||||
"modules/video_coding/inter_frame_delay.cc",
|
||||
|
|
@ -1418,14 +1403,8 @@ webrtc_sources = [
|
|||
"common_video/h264/h264_bitstream_parser.cc",
|
||||
"common_video/h264/h264_common.cc",
|
||||
"common_video/h264/pps_parser.cc",
|
||||
"common_video/h264/prefix_parser.cc",
|
||||
"common_video/h264/sps_parser.cc",
|
||||
"common_video/h264/sps_vui_rewriter.cc",
|
||||
"common_video/h265/h265_bitstream_parser.cc",
|
||||
"common_video/h265/h265_common.cc",
|
||||
"common_video/h265/h265_pps_parser.cc",
|
||||
"common_video/h265/h265_sps_parser.cc",
|
||||
"common_video/h265/h265_vps_parser.cc",
|
||||
"common_video/incoming_video_stream.cc",
|
||||
"common_video/libyuv/webrtc_libyuv.cc",
|
||||
"common_video/video_frame_buffer.cc",
|
||||
|
|
@ -1442,7 +1421,6 @@ webrtc_sources = [
|
|||
"p2p/base/ice_controller_interface.cc",
|
||||
"p2p/base/ice_credentials_iterator.cc",
|
||||
"p2p/base/ice_transport_internal.cc",
|
||||
"p2p/base/mdns_message.cc",
|
||||
"p2p/base/p2p_constants.cc",
|
||||
"p2p/base/p2p_transport_channel.cc",
|
||||
"p2p/base/packet_transport_internal.cc",
|
||||
|
|
@ -1608,7 +1586,6 @@ webrtc_sources = [
|
|||
"api/neteq/neteq.h",
|
||||
"api/neteq/tick_timer.h",
|
||||
"api/peer_connection_interface.h",
|
||||
"api/proxy.h",
|
||||
"api/rtc_error.h",
|
||||
"api/rtc_event_log/rtc_event.h",
|
||||
"api/rtc_event_log/rtc_event_log.h",
|
||||
|
|
@ -1728,12 +1705,8 @@ webrtc_sources = [
|
|||
"common_video/h264/h264_bitstream_parser.h",
|
||||
"common_video/h264/h264_common.h",
|
||||
"common_video/h264/pps_parser.h",
|
||||
"common_video/h264/prefix_parser.h",
|
||||
"common_video/h264/sps_parser.h",
|
||||
"common_video/h264/sps_vui_rewriter.h",
|
||||
"common_video/h265/h265_bitstream_parser.h",
|
||||
"common_video/h265/h265_common.h",
|
||||
"common_video/h265/h265_pps_parser.h",
|
||||
"common_video/include/bitrate_adjuster.h",
|
||||
"common_video/include/incoming_video_stream.h",
|
||||
"common_video/include/video_frame_buffer.h",
|
||||
|
|
@ -1778,9 +1751,7 @@ webrtc_sources = [
|
|||
"media/base/media_constants.h",
|
||||
"media/base/media_engine.h",
|
||||
"media/base/rid_description.h",
|
||||
"media/base/rtp_data_engine.h",
|
||||
"media/base/rtp_utils.h",
|
||||
"media/base/sdp_fmtp_utils.h",
|
||||
"media/base/stream_params.h",
|
||||
"media/base/turn_utils.h",
|
||||
"media/base/video_adapter.h",
|
||||
|
|
@ -2121,7 +2092,6 @@ webrtc_sources = [
|
|||
"modules/rtp_rtcp/include/report_block_data.h",
|
||||
"modules/rtp_rtcp/include/rtp_header_extension_map.h",
|
||||
"modules/rtp_rtcp/include/rtp_rtcp_defines.h",
|
||||
"modules/rtp_rtcp/source/absolute_capture_time_receiver.h",
|
||||
"modules/rtp_rtcp/source/absolute_capture_time_sender.h",
|
||||
"modules/rtp_rtcp/source/create_video_rtp_depacketizer.h",
|
||||
"modules/rtp_rtcp/source/dtmf_queue.h",
|
||||
|
|
@ -2191,7 +2161,6 @@ webrtc_sources = [
|
|||
"modules/rtp_rtcp/source/rtp_sender_video.h",
|
||||
"modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.h",
|
||||
"modules/rtp_rtcp/source/rtp_sequence_number_map.h",
|
||||
"modules/rtp_rtcp/source/rtp_utility.h",
|
||||
"modules/rtp_rtcp/source/rtp_video_header.h",
|
||||
"modules/rtp_rtcp/source/source_tracker.h",
|
||||
"modules/rtp_rtcp/source/time_util.h",
|
||||
|
|
@ -2203,7 +2172,6 @@ webrtc_sources = [
|
|||
"modules/rtp_rtcp/source/video_rtp_depacketizer_av1.h",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_generic.h",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_h264.h",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_h265.h",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_raw.h",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_vp8.h",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_vp9.h",
|
||||
|
|
@ -2229,7 +2197,6 @@ webrtc_sources = [
|
|||
"modules/video_coding/codecs/vp8/screenshare_layers.h",
|
||||
"modules/video_coding/codecs/vp9/include/vp9.h",
|
||||
"modules/video_coding/codecs/vp9/svc_config.h",
|
||||
"modules/video_coding/codecs/vp9/svc_rate_allocator.h",
|
||||
"modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h",
|
||||
"modules/video_coding/decoder_database.h",
|
||||
"modules/video_coding/decoding_state.h",
|
||||
|
|
@ -2243,7 +2210,6 @@ webrtc_sources = [
|
|||
"modules/video_coding/generic_decoder.h",
|
||||
"modules/video_coding/h264_sprop_parameter_sets.h",
|
||||
"modules/video_coding/h264_sps_pps_tracker.h",
|
||||
"modules/video_coding/h265_vps_sps_pps_tracker.h",
|
||||
"modules/video_coding/histogram.h",
|
||||
"modules/video_coding/include/video_codec_initializer.h",
|
||||
"modules/video_coding/include/video_codec_interface.h",
|
||||
|
|
@ -2293,7 +2259,6 @@ webrtc_sources = [
|
|||
"p2p/base/ice_controller_interface.h",
|
||||
"p2p/base/ice_credentials_iterator.h",
|
||||
"p2p/base/ice_transport_internal.h",
|
||||
"p2p/base/mdns_message.h",
|
||||
"p2p/base/p2p_constants.h",
|
||||
"p2p/base/p2p_transport_channel.h",
|
||||
"p2p/base/packet_transport_internal.h",
|
||||
|
|
@ -2482,9 +2447,6 @@ webrtc_sources = [
|
|||
"audio/remix_resample.h",
|
||||
"audio/utility/audio_frame_operations.h",
|
||||
"common_audio/fir_filter.h",
|
||||
"common_video/h264/profile_level_id.h",
|
||||
"common_video/h265/h265_sps_parser.h",
|
||||
"common_video/h265/h265_vps_parser.h",
|
||||
"common_video/include/quality_limitation_reason.h",
|
||||
"modules/audio_coding/codecs/ilbc/abs_quant.h",
|
||||
"modules/audio_coding/codecs/ilbc/abs_quant_loop.h",
|
||||
|
|
@ -2533,7 +2495,6 @@ webrtc_sources = [
|
|||
"modules/video_coding/codecs/vp9/include/vp9_globals.h",
|
||||
"pc/rtp_transport_internal.h",
|
||||
"rtc_base/mdns_responder_interface.h",
|
||||
"rtc_base/message_buffer_reader.h",
|
||||
"rtc_base/numerics/running_statistics.h",
|
||||
"rtc_base/numerics/sequence_number_util.h",
|
||||
"rtc_base/openssl.h",
|
||||
|
|
@ -2564,7 +2525,6 @@ webrtc_sources = [
|
|||
"api/video_codecs/bitstream_parser.h",
|
||||
"api/video_codecs/vp8_frame_buffer_controller.h",
|
||||
"media/base/delayable.h",
|
||||
"media/sctp/sctp_transport.h",
|
||||
"media/sctp/sctp_transport_internal.h",
|
||||
"modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h",
|
||||
"modules/audio_coding/codecs/ilbc/decoder_interpolate_lsf.h",
|
||||
|
|
@ -2597,7 +2557,6 @@ webrtc_sources = [
|
|||
"modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h",
|
||||
"modules/rtp_rtcp/include/rtcp_statistics.h",
|
||||
"modules/rtp_rtcp/include/rtp_rtcp.h",
|
||||
"modules/rtp_rtcp/source/rtp_format_h265.h",
|
||||
"modules/video_capture/video_capture_defines.h",
|
||||
"modules/video_coding/fec_rate_table.h",
|
||||
"p2p/base/candidate_pair_interface.h",
|
||||
|
|
@ -2614,7 +2573,6 @@ webrtc_sources = [
|
|||
"api/audio_codecs/isac/audio_encoder_isac.h",
|
||||
"api/task_queue/default_task_queue_factory.h",
|
||||
"api/video/video_stream_encoder_settings.h",
|
||||
"api/video_track_source_proxy.h",
|
||||
"call/audio_sender.h",
|
||||
"call/rtp_transport_controller_send_interface.h",
|
||||
"call/rtp_video_sender_interface.h",
|
||||
|
|
@ -2629,10 +2587,8 @@ webrtc_sources = [
|
|||
"modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h",
|
||||
"modules/audio_processing/agc/gain_map_internal.h",
|
||||
"modules/video_capture/video_capture_config.h",
|
||||
"modules/video_coding/codecs/h265/include/h265_globals.h",
|
||||
"modules/video_coding/codecs/vp8/include/vp8.h",
|
||||
"p2p/base/p2p_transport_channel_ice_field_trials.h",
|
||||
"pc/jitter_buffer_delay_interface.h",
|
||||
"rtc_base/swap_queue.h",
|
||||
"rtc_base/system/ignore_warnings.h",
|
||||
"logging/rtc_event_log/encoder/rtc_event_log_encoder.h",
|
||||
|
|
@ -2660,7 +2616,6 @@ webrtc_sources = [
|
|||
"modules/audio_coding/codecs/ilbc/enhancer_interface.h",
|
||||
"modules/rtp_rtcp/include/rtp_cvo.h",
|
||||
"call/simulated_packet_receiver.h",
|
||||
"api/media_stream_proxy.h",
|
||||
"logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h",
|
||||
"modules/audio_coding/codecs/ilbc/cb_search.h",
|
||||
"modules/audio_coding/codecs/ilbc/decode.h",
|
||||
|
|
@ -2682,17 +2637,13 @@ webrtc_sources = [
|
|||
"modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.h",
|
||||
"modules/audio_coding/codecs/ilbc/unpack_bits.h",
|
||||
"modules/audio_coding/codecs/ilbc/index_conv_enc.h",
|
||||
"api/media_stream_track_proxy.h",
|
||||
"pc/stream_collection.h",
|
||||
"api/peer_connection_factory_proxy.h",
|
||||
"api/uma_metrics.h",
|
||||
"logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h",
|
||||
"modules/audio_coding/codecs/ilbc/cb_search_core.h",
|
||||
"modules/audio_coding/codecs/ilbc/pack_bits.h",
|
||||
"modules/audio_coding/codecs/ilbc/swap_bytes.h",
|
||||
"modules/audio_processing/common.h",
|
||||
"pc/jitter_buffer_delay_proxy.h",
|
||||
"api/peer_connection_proxy.h",
|
||||
"modules/audio_coding/codecs/ilbc/hp_input.h",
|
||||
"api/adaptation/resource.h",
|
||||
"api/adaptation/resource.cc",
|
||||
|
|
@ -2770,8 +2721,6 @@ webrtc_sources = [
|
|||
"pc/connection_context.cc",
|
||||
"pc/data_channel_utils.h",
|
||||
"pc/data_channel_utils.cc",
|
||||
"pc/rtp_data_channel.h",
|
||||
"pc/rtp_data_channel.cc",
|
||||
"rtc_base/boringssl_certificate.h",
|
||||
"rtc_base/boringssl_certificate.cc",
|
||||
"rtc_base/strings/string_format.h",
|
||||
|
|
@ -2859,8 +2808,6 @@ webrtc_sources = [
|
|||
"video/rtp_video_stream_receiver2.cc",
|
||||
"video/video_stream_decoder2.h",
|
||||
"video/video_stream_decoder2.cc",
|
||||
"modules/video_coding/nack_module2.h",
|
||||
"modules/video_coding/nack_module2.cc",
|
||||
"api/sequence_checker.h",
|
||||
"common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h",
|
||||
"common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h",
|
||||
|
|
@ -2891,6 +2838,59 @@ webrtc_sources = [
|
|||
"modules/audio_processing/capture_levels_adjuster/audio_samples_scaler.cc",
|
||||
"rtc_base/system/gcd_helpers.h",
|
||||
"rtc_base/system/gcd_helpers.m",
|
||||
"modules/rtp_rtcp/source/rtp_util.h",
|
||||
"modules/rtp_rtcp/source/rtp_util.cc",
|
||||
"pc/jsep_transport_collection.h",
|
||||
"pc/jsep_transport_collection.cc",
|
||||
"modules/video_coding/nack_requester.h",
|
||||
"modules/video_coding/nack_requester.cc",
|
||||
"modules/congestion_controller/remb_throttler.h",
|
||||
"modules/congestion_controller/remb_throttler.cc",
|
||||
"modules/congestion_controller/goog_cc/loss_based_bwe_v2.h",
|
||||
"modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc",
|
||||
"system_wrappers/include/denormal_disabler.h",
|
||||
"system_wrappers/source/denormal_disabler.cc",
|
||||
"api/video_codecs/vp9_profile.h",
|
||||
"api/video_codecs/vp9_profile.cc",
|
||||
"api/video_codecs/h264_profile_level_id.h",
|
||||
"api/video_codecs/h264_profile_level_id.cc",
|
||||
"modules/remote_bitrate_estimator/packet_arrival_map.h",
|
||||
"modules/remote_bitrate_estimator/packet_arrival_map.cc",
|
||||
"modules/audio_processing/agc/clipping_predictor.h",
|
||||
"modules/audio_processing/agc/clipping_predictor.cc",
|
||||
"modules/rtp_rtcp/source/capture_clock_offset_updater.h",
|
||||
"modules/rtp_rtcp/source/capture_clock_offset_updater.cc",
|
||||
"pc/video_track_source_proxy.h",
|
||||
"pc/video_track_source_proxy.cc",
|
||||
"modules/rtp_rtcp/source/absolute_capture_time_interpolator.h",
|
||||
"modules/rtp_rtcp/source/absolute_capture_time_interpolator.cc",
|
||||
"media/base/sdp_video_format_utils.h",
|
||||
"media/base/sdp_video_format_utils.cc",
|
||||
"modules/audio_processing/agc/clipping_predictor_evaluator.h",
|
||||
"modules/audio_processing/agc/clipping_predictor_evaluator.cc",
|
||||
"modules/audio_processing/agc/clipping_predictor_level_buffer.h",
|
||||
"modules/audio_processing/agc/clipping_predictor_level_buffer.cc",
|
||||
"modules/rtp_rtcp/source/rtp_format_h265.cc",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_h265.cc",
|
||||
"modules/video_coding/h265_vps_sps_pps_tracker.cc",
|
||||
"common_video/h265/h265_bitstream_parser.cc",
|
||||
"common_video/h265/h265_common.cc",
|
||||
"common_video/h265/h265_pps_parser.cc",
|
||||
"common_video/h265/h265_sps_parser.cc",
|
||||
"common_video/h265/h265_vps_parser.cc",
|
||||
"common_video/h265/h265_bitstream_parser.h",
|
||||
"common_video/h265/h265_common.h",
|
||||
"common_video/h265/h265_pps_parser.h",
|
||||
"modules/rtp_rtcp/source/video_rtp_depacketizer_h265.h",
|
||||
"modules/video_coding/h265_vps_sps_pps_tracker.h",
|
||||
"common_video/h265/h265_sps_parser.h",
|
||||
"common_video/h265/h265_vps_parser.h",
|
||||
"modules/rtp_rtcp/source/rtp_format_h265.h",
|
||||
"modules/video_coding/codecs/h265/include/h265_globals.h",
|
||||
"media/sctp/sctp_transport_factory.h",
|
||||
"media/sctp/sctp_transport_factory.cc",
|
||||
"media/sctp/usrsctp_transport.h",
|
||||
"media/sctp/usrsctp_transport.cc",
|
||||
]
|
||||
|
||||
ios_objc_sources = [
|
||||
|
|
@ -2916,6 +2916,15 @@ ios_objc_sources = [
|
|||
"objc/components/video_codec/RTCVideoEncoderFactoryH264.m",
|
||||
"objc/components/video_codec/RTCVideoDecoderFactoryH264.h",
|
||||
"objc/components/video_codec/RTCVideoDecoderFactoryH264.m",
|
||||
"objc/components/video_codec/RTCCodecSpecificInfoH265.h",
|
||||
"objc/components/video_codec/RTCCodecSpecificInfoH265.mm",
|
||||
"objc/components/video_codec/RTCH265ProfileLevelId.h",
|
||||
"objc/components/video_codec/RTCH265ProfileLevelId.mm",
|
||||
"objc/components/video_codec/RTCVideoDecoderH265.h",
|
||||
"objc/components/video_codec/RTCVideoDecoderH265.mm",
|
||||
"objc/components/video_codec/RTCVideoEncoderH265.h",
|
||||
"objc/components/video_codec/RTCVideoEncoderH265.mm",
|
||||
"objc/components/video_codec/RTCCodecSpecificInfoH265+Private.h",
|
||||
]
|
||||
|
||||
ios_sources = [
|
||||
|
|
@ -2983,18 +2992,10 @@ ios_sources = [
|
|||
"objc/components/video_codec/RTCCodecSpecificInfoH264.mm",
|
||||
"objc/components/video_codec/RTCH264ProfileLevelId.h",
|
||||
"objc/components/video_codec/RTCH264ProfileLevelId.mm",
|
||||
"objc/components/video_codec/RTCCodecSpecificInfoH265.h",
|
||||
"objc/components/video_codec/RTCCodecSpecificInfoH265.mm",
|
||||
"objc/components/video_codec/RTCH265ProfileLevelId.h",
|
||||
"objc/components/video_codec/RTCH265ProfileLevelId.mm",
|
||||
"objc/components/video_codec/RTCVideoDecoderH264.h",
|
||||
"objc/components/video_codec/RTCVideoDecoderH264.mm",
|
||||
"objc/components/video_codec/RTCVideoEncoderH264.h",
|
||||
"objc/components/video_codec/RTCVideoEncoderH264.mm",
|
||||
"objc/components/video_codec/RTCVideoDecoderH265.h",
|
||||
"objc/components/video_codec/RTCVideoDecoderH265.mm",
|
||||
"objc/components/video_codec/RTCVideoEncoderH265.h",
|
||||
"objc/components/video_codec/RTCVideoEncoderH265.mm",
|
||||
"objc/api/video_codec/RTCVideoCodecConstants.h",
|
||||
"objc/api/video_codec/RTCVideoCodecConstants.mm",
|
||||
"objc/components/video_codec/helpers.cc",
|
||||
|
|
@ -3050,7 +3051,6 @@ ios_sources = [
|
|||
"objc/api/peerconnection/RTCAudioSource+Private.h",
|
||||
"objc/api/peerconnection/RTCAudioTrack+Private.h",
|
||||
"objc/api/peerconnection/RTCCertificate.h",
|
||||
"objc/components/video_codec/RTCCodecSpecificInfoH265+Private.h",
|
||||
"objc/api/peerconnection/RTCConfiguration+Private.h",
|
||||
"objc/api/peerconnection/RTCCryptoOptions.h",
|
||||
"objc/api/peerconnection/RTCDataChannel+Private.h",
|
||||
|
|
@ -3221,6 +3221,7 @@ common_flags = [
|
|||
"-DRTC_ENABLE_VP9",
|
||||
"-DWEBRTC_USE_H264",
|
||||
"-DHAVE_SCTP",
|
||||
"-DWEBRTC_HAVE_USRSCTP",
|
||||
"-Ithird-party/openh264",
|
||||
"-DWEBRTC_NS_FLOAT",
|
||||
"-DRTC_DISABLE_TRACE_EVENTS",
|
||||
|
|
@ -3229,7 +3230,7 @@ common_flags = [
|
|||
"-DBWE_TEST_LOGGING_COMPILE_TIME_ENABLE=0",
|
||||
"-DABSL_ALLOCATOR_NOTHROW=1",
|
||||
"-DDYNAMIC_ANNOTATIONS_ENABLED=0",
|
||||
"-DNS_BLOCK_ASSERTIONS=1",
|
||||
#"-DNS_BLOCK_ASSERTIONS=1",
|
||||
"-DWEBRTC_ENABLE_PROTOBUF=0",
|
||||
"-DWEBRTC_ENABLE_AVX2",
|
||||
"-DWEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=0",
|
||||
|
|
@ -3353,6 +3354,7 @@ cc_library(
|
|||
"-D__Userspace_os_Darwin",
|
||||
"-DPACKAGE_VERSION=''",
|
||||
"-DHAVE_SCTP",
|
||||
"-DWEBRTC_HAVE_USRSCTP",
|
||||
"-DNON_WINDOWS_DEFINE",
|
||||
] + arch_specific_cflags + optimization_flags,
|
||||
visibility = ["//visibility:public"],
|
||||
|
|
@ -3432,6 +3434,7 @@ cc_library(
|
|||
"-DHAVE_UNISTD_H",
|
||||
"-DPACKAGE_STRING='\"\"'",
|
||||
"-DHAVE_SCTP",
|
||||
"-DWEBRTC_HAVE_USRSCTP",
|
||||
] + arch_specific_cflags + optimization_flags,
|
||||
deps = [
|
||||
"//third-party/boringssl:crypto",
|
||||
|
|
@ -3481,6 +3484,7 @@ objc_library(
|
|||
"-D__Userspace_os_Darwin",
|
||||
"-DPACKAGE_VERSION='\"\"'",
|
||||
"-DHAVE_SCTP",
|
||||
"-DWEBRTC_HAVE_USRSCTP",
|
||||
"-DNO_MAIN_THREAD_WRAPPING",
|
||||
"-DRTC_DISABLE_TRACE_EVENTS",
|
||||
"-DRTC_DISABLE_METRICS",
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
# Copyright (c) 2018 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# Flags specified here must not impact ABI. Code compiled with and without these
|
||||
# opts will be linked together, and in some cases headers compiled with and
|
||||
# without these options will be part of the same program.
|
||||
|
||||
import("//build/toolchain/toolchain.gni")
|
||||
|
||||
group("default") {
|
||||
deps = [
|
||||
"absl/types:any",
|
||||
"absl/types:bad_any_cast",
|
||||
"absl/types:bad_optional_access",
|
||||
"absl/types:optional",
|
||||
"absl/types:span",
|
||||
]
|
||||
}
|
||||
|
||||
config("absl_include_config") {
|
||||
include_dirs = [ "." ]
|
||||
}
|
||||
|
||||
config("absl_define_config") {
|
||||
defines = [ "ABSL_ALLOCATOR_NOTHROW=1" ]
|
||||
}
|
||||
|
||||
config("absl_default_cflags_cc") {
|
||||
cflags_cc = []
|
||||
if (is_clang) {
|
||||
cflags_cc += [
|
||||
# TODO(crbug.com/588506): Explicitly enable conversion warnings.
|
||||
"-Wbool-conversion",
|
||||
"-Wconstant-conversion",
|
||||
"-Wenum-conversion",
|
||||
"-Wint-conversion",
|
||||
"-Wliteral-conversion",
|
||||
"-Wnon-literal-null-conversion",
|
||||
"-Wnull-conversion",
|
||||
"-Wobjc-literal-conversion",
|
||||
"-Wno-sign-conversion",
|
||||
"-Wstring-conversion",
|
||||
]
|
||||
if (!is_nacl && !use_xcode_clang) {
|
||||
cflags_cc += [ "-Wbitfield-enum-conversion" ]
|
||||
}
|
||||
}
|
||||
if (is_win) {
|
||||
cflags_cc += [
|
||||
"/wd4005", # macro-redefinition
|
||||
"/wd4018", # sign-compare
|
||||
"/wd4068", # unknown pragma
|
||||
"/wd4702", # unreachable code
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
config("absl_test_cflags_cc") {
|
||||
cflags_cc = []
|
||||
if (is_clang || !is_win) {
|
||||
cflags_cc += [
|
||||
"-Wno-conversion-null",
|
||||
"-Wno-missing-declarations",
|
||||
"-Wno-sign-compare",
|
||||
"-Wno-unused-function",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-unused-private-field",
|
||||
]
|
||||
}
|
||||
if (is_win) {
|
||||
cflags_cc += [
|
||||
"/wd4018", # signed/unsigned mismatch
|
||||
"/wd4101", # unreferenced local variable
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
include(CMakeParseArguments)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(ABSL_INTERNAL_DLL_FILES
|
||||
"algorithm/algorithm.h"
|
||||
|
|
@ -8,13 +9,12 @@ set(ABSL_INTERNAL_DLL_FILES
|
|||
"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/dynamic_annotations.h"
|
||||
"base/internal/endian.h"
|
||||
"base/internal/errno_saver.h"
|
||||
"base/internal/exponential_biased.cc"
|
||||
|
|
@ -61,6 +61,8 @@ set(ABSL_INTERNAL_DLL_FILES
|
|||
"base/policy_checks.h"
|
||||
"base/port.h"
|
||||
"base/thread_annotations.h"
|
||||
"cleanup/cleanup.h"
|
||||
"cleanup/internal/cleanup.h"
|
||||
"container/btree_map.h"
|
||||
"container/btree_set.h"
|
||||
"container/fixed_array.h"
|
||||
|
|
@ -122,10 +124,16 @@ set(ABSL_INTERNAL_DLL_FILES
|
|||
"hash/internal/hash.h"
|
||||
"hash/internal/hash.cc"
|
||||
"hash/internal/spy_hash_state.h"
|
||||
"hash/internal/low_level_hash.h"
|
||||
"hash/internal/low_level_hash.cc"
|
||||
"memory/memory.h"
|
||||
"meta/type_traits.h"
|
||||
"numeric/bits.h"
|
||||
"numeric/int128.cc"
|
||||
"numeric/int128.h"
|
||||
"numeric/internal/bits.h"
|
||||
"numeric/internal/representation.h"
|
||||
"profiling/internal/sample_recorder.h"
|
||||
"random/bernoulli_distribution.h"
|
||||
"random/beta_distribution.h"
|
||||
"random/bit_gen_ref.h"
|
||||
|
|
@ -135,13 +143,12 @@ set(ABSL_INTERNAL_DLL_FILES
|
|||
"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/fast_uniform_bits.h"
|
||||
"random/internal/generate_real.h"
|
||||
"random/internal/iostream_state_saver.h"
|
||||
"random/internal/mock_helpers.h"
|
||||
"random/internal/nonsecure_base.h"
|
||||
"random/internal/pcg_engine.h"
|
||||
"random/internal/platform.h"
|
||||
|
|
@ -154,6 +161,7 @@ set(ABSL_INTERNAL_DLL_FILES
|
|||
"random/internal/randen_engine.h"
|
||||
"random/internal/randen_hwaes.cc"
|
||||
"random/internal/randen_hwaes.h"
|
||||
"random/internal/randen_round_keys.cc"
|
||||
"random/internal/randen_slow.cc"
|
||||
"random/internal/randen_slow.h"
|
||||
"random/internal/randen_traits.h"
|
||||
|
|
@ -174,8 +182,12 @@ set(ABSL_INTERNAL_DLL_FILES
|
|||
"random/uniform_int_distribution.h"
|
||||
"random/uniform_real_distribution.h"
|
||||
"random/zipf_distribution.h"
|
||||
"status/internal/status_internal.h"
|
||||
"status/internal/statusor_internal.h"
|
||||
"status/status.h"
|
||||
"status/status.cc"
|
||||
"status/statusor.h"
|
||||
"status/statusor.cc"
|
||||
"status/status_payload_printer.h"
|
||||
"status/status_payload_printer.cc"
|
||||
"strings/ascii.cc"
|
||||
|
|
@ -186,12 +198,37 @@ set(ABSL_INTERNAL_DLL_FILES
|
|||
"strings/cord.h"
|
||||
"strings/escaping.cc"
|
||||
"strings/escaping.h"
|
||||
"strings/internal/cord_internal.h"
|
||||
"strings/internal/charconv_bigint.cc"
|
||||
"strings/internal/charconv_bigint.h"
|
||||
"strings/internal/charconv_parse.cc"
|
||||
"strings/internal/charconv_parse.h"
|
||||
"strings/internal/cord_internal.cc"
|
||||
"strings/internal/cord_internal.h"
|
||||
"strings/internal/cord_rep_consume.h"
|
||||
"strings/internal/cord_rep_consume.cc"
|
||||
"strings/internal/cord_rep_btree.cc"
|
||||
"strings/internal/cord_rep_btree.h"
|
||||
"strings/internal/cord_rep_btree_navigator.cc"
|
||||
"strings/internal/cord_rep_btree_navigator.h"
|
||||
"strings/internal/cord_rep_btree_reader.cc"
|
||||
"strings/internal/cord_rep_btree_reader.h"
|
||||
"strings/internal/cord_rep_flat.h"
|
||||
"strings/internal/cord_rep_ring.cc"
|
||||
"strings/internal/cord_rep_ring.h"
|
||||
"strings/internal/cord_rep_ring_reader.h"
|
||||
"strings/internal/cordz_functions.cc"
|
||||
"strings/internal/cordz_functions.h"
|
||||
"strings/internal/cordz_handle.cc"
|
||||
"strings/internal/cordz_handle.h"
|
||||
"strings/internal/cordz_info.cc"
|
||||
"strings/internal/cordz_info.h"
|
||||
"strings/internal/cordz_sample_token.cc"
|
||||
"strings/internal/cordz_sample_token.h"
|
||||
"strings/internal/cordz_statistics.h"
|
||||
"strings/internal/cordz_update_scope.h"
|
||||
"strings/internal/cordz_update_tracker.h"
|
||||
"strings/internal/stl_type_traits.h"
|
||||
"strings/internal/string_constant.h"
|
||||
"strings/match.cc"
|
||||
"strings/match.h"
|
||||
"strings/numbers.cc"
|
||||
|
|
@ -246,6 +283,7 @@ set(ABSL_INTERNAL_DLL_FILES
|
|||
"synchronization/notification.h"
|
||||
"synchronization/internal/create_thread_identity.cc"
|
||||
"synchronization/internal/create_thread_identity.h"
|
||||
"synchronization/internal/futex.h"
|
||||
"synchronization/internal/graphcycles.cc"
|
||||
"synchronization/internal/graphcycles.h"
|
||||
"synchronization/internal/kernel_timeout.h"
|
||||
|
|
@ -294,6 +332,8 @@ set(ABSL_INTERNAL_DLL_FILES
|
|||
"types/internal/conformance_aliases.h"
|
||||
"types/internal/conformance_archetype.h"
|
||||
"types/internal/conformance_profile.h"
|
||||
"types/internal/parentheses.h"
|
||||
"types/internal/transform_args.h"
|
||||
"types/internal/variant.h"
|
||||
"types/optional.h"
|
||||
"types/internal/optional.h"
|
||||
|
|
@ -418,6 +458,7 @@ set(ABSL_INTERNAL_DLL_TARGETS
|
|||
"raw_hash_set"
|
||||
"layout"
|
||||
"tracked"
|
||||
"sample_recorder"
|
||||
)
|
||||
|
||||
function(absl_internal_dll_contains)
|
||||
|
|
@ -481,7 +522,7 @@ function(absl_make_dll)
|
|||
abseil_dll
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
|
||||
$<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
target_compile_options(
|
||||
|
|
@ -499,8 +540,8 @@ function(absl_make_dll)
|
|||
${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}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
endfunction()
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@
|
|||
include(CMakeParseArguments)
|
||||
include(AbseilConfigureCopts)
|
||||
include(AbseilDll)
|
||||
include(AbseilInstallDirs)
|
||||
|
||||
# The IDE folder for Abseil that will be used if Abseil is included in a CMake
|
||||
# project that sets
|
||||
# set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
# For example, Visual Studio supports folders.
|
||||
set(ABSL_IDE_FOLDER Abseil)
|
||||
if(NOT DEFINED ABSL_IDE_FOLDER)
|
||||
set(ABSL_IDE_FOLDER Abseil)
|
||||
endif()
|
||||
|
||||
# absl_cc_library()
|
||||
#
|
||||
|
|
@ -39,7 +40,7 @@ set(ABSL_IDE_FOLDER Abseil)
|
|||
# LINKOPTS: List of link options
|
||||
# PUBLIC: Add this so that this library will be exported under absl::
|
||||
# Also in IDE, target will appear in Abseil folder while non PUBLIC will be in Abseil/internal.
|
||||
# TESTONLY: When added, this target will only be built if user passes -DABSL_RUN_TESTS=ON to CMake.
|
||||
# TESTONLY: When added, this target will only be built if BUILD_TESTING=ON.
|
||||
#
|
||||
# Note:
|
||||
# By default, absl_cc_library will always create a library named absl_${NAME},
|
||||
|
|
@ -81,7 +82,7 @@ function(absl_cc_library)
|
|||
${ARGN}
|
||||
)
|
||||
|
||||
if(ABSL_CC_LIB_TESTONLY AND NOT ABSL_RUN_TESTS)
|
||||
if(ABSL_CC_LIB_TESTONLY AND NOT BUILD_TESTING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
|
@ -102,7 +103,7 @@ function(absl_cc_library)
|
|||
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)
|
||||
|
|
@ -120,7 +121,11 @@ function(absl_cc_library)
|
|||
# 4. "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(ABSL_ENABLE_INSTALL)
|
||||
absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll)
|
||||
else()
|
||||
absl_internal_dll_contains(TARGET ${ABSL_CC_LIB_NAME} OUTPUT _in_dll)
|
||||
endif()
|
||||
if (${_in_dll})
|
||||
# This target should be replaced by the DLL
|
||||
set(_build_type "dll")
|
||||
|
|
@ -135,8 +140,54 @@ function(absl_cc_library)
|
|||
set(_build_type "static")
|
||||
endif()
|
||||
|
||||
# Generate a pkg-config file for every library:
|
||||
if((_build_type STREQUAL "static" OR _build_type STREQUAL "shared")
|
||||
AND ABSL_ENABLE_INSTALL)
|
||||
if(NOT ABSL_CC_LIB_TESTONLY)
|
||||
if(absl_VERSION)
|
||||
set(PC_VERSION "${absl_VERSION}")
|
||||
else()
|
||||
set(PC_VERSION "head")
|
||||
endif()
|
||||
foreach(dep ${ABSL_CC_LIB_DEPS})
|
||||
if(${dep} MATCHES "^absl::(.*)")
|
||||
# Join deps with commas.
|
||||
if(PC_DEPS)
|
||||
set(PC_DEPS "${PC_DEPS},")
|
||||
endif()
|
||||
set(PC_DEPS "${PC_DEPS} absl_${CMAKE_MATCH_1} = ${PC_VERSION}")
|
||||
endif()
|
||||
endforeach()
|
||||
foreach(cflag ${ABSL_CC_LIB_COPTS})
|
||||
if(${cflag} MATCHES "^(-Wno|/wd)")
|
||||
# These flags are needed to suppress warnings that might fire in our headers.
|
||||
set(PC_CFLAGS "${PC_CFLAGS} ${cflag}")
|
||||
elseif(${cflag} MATCHES "^(-W|/w[1234eo])")
|
||||
# Don't impose our warnings on others.
|
||||
else()
|
||||
set(PC_CFLAGS "${PC_CFLAGS} ${cflag}")
|
||||
endif()
|
||||
endforeach()
|
||||
FILE(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc" CONTENT "\
|
||||
prefix=${CMAKE_INSTALL_PREFIX}\n\
|
||||
exec_prefix=\${prefix}\n\
|
||||
libdir=${CMAKE_INSTALL_FULL_LIBDIR}\n\
|
||||
includedir=${CMAKE_INSTALL_FULL_INCLUDEDIR}\n\
|
||||
\n\
|
||||
Name: absl_${_NAME}\n\
|
||||
Description: Abseil ${_NAME} library\n\
|
||||
URL: https://abseil.io/\n\
|
||||
Version: ${PC_VERSION}\n\
|
||||
Requires:${PC_DEPS}\n\
|
||||
Libs: -L\${libdir} $<JOIN:${ABSL_CC_LIB_LINKOPTS}, > $<$<NOT:$<BOOL:${ABSL_CC_LIB_IS_INTERFACE}>>:-labsl_${_NAME}>\n\
|
||||
Cflags: -I\${includedir}${PC_CFLAGS}\n")
|
||||
INSTALL(FILES "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT ABSL_CC_LIB_IS_INTERFACE)
|
||||
if(${_build_type} STREQUAL "dll_dep")
|
||||
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.
|
||||
|
|
@ -165,7 +216,7 @@ function(absl_cc_library)
|
|||
"${_gtest_link_define}"
|
||||
)
|
||||
|
||||
elseif(${_build_type} STREQUAL "static" OR ${_build_type} STREQUAL "shared")
|
||||
elseif(_build_type STREQUAL "static" OR _build_type STREQUAL "shared")
|
||||
add_library(${_NAME} "")
|
||||
target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
|
||||
target_link_libraries(${_NAME}
|
||||
|
|
@ -188,7 +239,7 @@ function(absl_cc_library)
|
|||
target_include_directories(${_NAME}
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
|
||||
$<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
target_compile_options(${_NAME}
|
||||
PRIVATE ${ABSL_CC_LIB_COPTS})
|
||||
|
|
@ -203,9 +254,23 @@ function(absl_cc_library)
|
|||
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)
|
||||
if(ABSL_PROPAGATE_CXX_STD)
|
||||
# Abseil libraries require C++11 as the current minimum standard.
|
||||
# Top-level application CMake projects should ensure a consistent C++
|
||||
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
|
||||
target_compile_features(${_NAME} PUBLIC cxx_std_11)
|
||||
else()
|
||||
# Note: This is legacy (before CMake 3.8) behavior. Setting the
|
||||
# target-level CXX_STANDARD property to ABSL_CXX_STANDARD (which is
|
||||
# initialized by CMAKE_CXX_STANDARD) should have no real effect, since
|
||||
# that is the default value anyway.
|
||||
#
|
||||
# CXX_STANDARD_REQUIRED does guard against the top-level CMake project
|
||||
# not having enabled CMAKE_CXX_STANDARD_REQUIRED (which prevents
|
||||
# "decaying" to an older standard if the requested one isn't available).
|
||||
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
|
||||
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
# 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
|
||||
|
|
@ -213,6 +278,7 @@ function(absl_cc_library)
|
|||
if(ABSL_ENABLE_INSTALL)
|
||||
set_target_properties(${_NAME} PROPERTIES
|
||||
OUTPUT_NAME "absl_${_NAME}"
|
||||
SOVERSION 0
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
|
|
@ -221,10 +287,10 @@ function(absl_cc_library)
|
|||
target_include_directories(${_NAME}
|
||||
INTERFACE
|
||||
"$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
|
||||
$<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
if (${_build_type} STREQUAL "dll")
|
||||
if (_build_type STREQUAL "dll")
|
||||
set(ABSL_CC_LIB_DEPS abseil_dll)
|
||||
endif()
|
||||
|
||||
|
|
@ -235,15 +301,25 @@ function(absl_cc_library)
|
|||
${ABSL_DEFAULT_LINKOPTS}
|
||||
)
|
||||
target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES})
|
||||
|
||||
if(ABSL_PROPAGATE_CXX_STD)
|
||||
# Abseil libraries require C++11 as the current minimum standard.
|
||||
# Top-level application CMake projects should ensure a consistent C++
|
||||
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
|
||||
target_compile_features(${_NAME} INTERFACE cxx_std_11)
|
||||
|
||||
# (INTERFACE libraries can't have the CXX_STANDARD property set, so there
|
||||
# is no legacy behavior else case).
|
||||
endif()
|
||||
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}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
|
@ -284,11 +360,11 @@ endfunction()
|
|||
# "awesome_test.cc"
|
||||
# DEPS
|
||||
# absl::awesome
|
||||
# gmock
|
||||
# gtest_main
|
||||
# GTest::gmock
|
||||
# GTest::gtest_main
|
||||
# )
|
||||
function(absl_cc_test)
|
||||
if(NOT ABSL_RUN_TESTS)
|
||||
if(NOT BUILD_TESTING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
|
@ -338,8 +414,23 @@ function(absl_cc_test)
|
|||
# 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})
|
||||
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
if(ABSL_PROPAGATE_CXX_STD)
|
||||
# Abseil libraries require C++11 as the current minimum standard.
|
||||
# Top-level application CMake projects should ensure a consistent C++
|
||||
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
|
||||
target_compile_features(${_NAME} PUBLIC cxx_std_11)
|
||||
else()
|
||||
# Note: This is legacy (before CMake 3.8) behavior. Setting the
|
||||
# target-level CXX_STANDARD property to ABSL_CXX_STANDARD (which is
|
||||
# initialized by CMAKE_CXX_STANDARD) should have no real effect, since
|
||||
# that is the default value anyway.
|
||||
#
|
||||
# CXX_STANDARD_REQUIRED does guard against the top-level CMake project
|
||||
# not having enabled CMAKE_CXX_STANDARD_REQUIRED (which prevents
|
||||
# "decaying" to an older standard if the requested one isn't available).
|
||||
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
|
||||
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
add_test(NAME ${_NAME} COMMAND ${_NAME})
|
||||
endfunction()
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
include(GNUInstallDirs)
|
||||
|
||||
# absl_VERSION is only set if we are an LTS release being installed, in which
|
||||
# case it may be into a system directory and so we need to make subdirectories
|
||||
# for each installed version of Abseil. This mechanism is implemented in
|
||||
# Abseil's internal Copybara (https://github.com/google/copybara) workflows and
|
||||
# isn't visible in the CMake buildsystem itself.
|
||||
|
||||
if(absl_VERSION)
|
||||
set(ABSL_SUBDIR "${PROJECT_NAME}_${PROJECT_VERSION}")
|
||||
set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}/${ABSL_SUBDIR}")
|
||||
set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${ABSL_SUBDIR}")
|
||||
set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/{ABSL_SUBDIR}")
|
||||
set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${ABSL_SUBDIR}")
|
||||
else()
|
||||
set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}")
|
||||
set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||
set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
|
|
@ -3,24 +3,12 @@ cmake_minimum_required(VERSION 2.8.2)
|
|||
project(googletest-external NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
if(${ABSL_USE_GOOGLETEST_HEAD})
|
||||
ExternalProject_Add(googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG master
|
||||
SOURCE_DIR "${absl_gtest_src_dir}"
|
||||
BINARY_DIR "${absl_gtest_build_dir}"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
else()
|
||||
ExternalProject_Add(googletest
|
||||
SOURCE_DIR "${absl_gtest_src_dir}"
|
||||
BINARY_DIR "${absl_gtest_build_dir}"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
endif()
|
||||
ExternalProject_Add(googletest
|
||||
URL "${absl_gtest_download_url}" # May be empty
|
||||
SOURCE_DIR "${absl_gtest_src_dir}"
|
||||
BINARY_DIR "${absl_gtest_build_dir}"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
|
|
|
|||
|
|
@ -34,15 +34,16 @@ to include Abseil directly in your CMake project.
|
|||
4. Add the **absl::** target you wish to use to the
|
||||
[`target_link_libraries()`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html)
|
||||
section of your executable or of your library.<br>
|
||||
Here is a short CMakeLists.txt example of a project file using Abseil.
|
||||
Here is a short CMakeLists.txt example of an application project using Abseil.
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(my_project)
|
||||
cmake_minimum_required(VERSION 3.8.2)
|
||||
project(my_app_project)
|
||||
|
||||
# Pick the C++ standard to compile with.
|
||||
# Abseil currently supports C++11, C++14, and C++17.
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_subdirectory(abseil-cpp)
|
||||
|
||||
|
|
@ -50,9 +51,47 @@ add_executable(my_exe source.cpp)
|
|||
target_link_libraries(my_exe absl::base absl::synchronization absl::strings)
|
||||
```
|
||||
|
||||
Note that if you are developing a library designed for use by other clients, you
|
||||
should instead leave `CMAKE_CXX_STANDARD` unset (or only set if being built as
|
||||
the current top-level CMake project) and configure the minimum required C++
|
||||
standard at the target level. If you require a later minimum C++ standard than
|
||||
Abseil does, it's a good idea to also enforce that `CMAKE_CXX_STANDARD` (which
|
||||
will control Abseil library targets) is set to at least that minimum. For
|
||||
example:
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.8.2)
|
||||
project(my_lib_project)
|
||||
|
||||
# Leave C++ standard up to the root application, so set it only if this is the
|
||||
# current top-level CMake project.
|
||||
if(CMAKE_SOURCE_DIR STREQUAL my_lib_project_SOURCE_DIR)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
add_subdirectory(abseil-cpp)
|
||||
|
||||
add_library(my_lib source.cpp)
|
||||
target_link_libraries(my_lib absl::base absl::synchronization absl::strings)
|
||||
|
||||
# Enforce that my_lib requires C++17. Important to document for clients that they
|
||||
# must set CMAKE_CXX_STANDARD to 17 or higher for proper Abseil ABI compatibility
|
||||
# (since otherwise, Abseil library targets could be compiled with a lower C++
|
||||
# standard than my_lib).
|
||||
target_compile_features(my_lib PUBLIC cxx_std_17)
|
||||
if(CMAKE_CXX_STANDARD LESS 17)
|
||||
message(FATAL_ERROR
|
||||
"my_lib_project requires CMAKE_CXX_STANDARD >= 17 (got: ${CMAKE_CXX_STANDARD})")
|
||||
endif()
|
||||
```
|
||||
|
||||
Then the top-level application project that uses your library is responsible for
|
||||
setting a consistent `CMAKE_CXX_STANDARD` that is sufficiently high.
|
||||
|
||||
### Running Abseil Tests with CMake
|
||||
|
||||
Use the `-DABSL_RUN_TESTS=ON` flag to run Abseil tests. Note that if the `-DBUILD_TESTING=OFF` flag is passed then Abseil tests will not be run.
|
||||
Use the `-DBUILD_TESTING=ON` flag to run Abseil tests.
|
||||
|
||||
You will need to provide Abseil with a Googletest dependency. There are two
|
||||
options for how to do this:
|
||||
|
|
@ -70,7 +109,7 @@ For example, to run just the Abseil tests, you could use this script:
|
|||
cd path/to/abseil-cpp
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DABSL_USE_GOOGLETEST_HEAD=ON -DABSL_RUN_TESTS=ON ..
|
||||
cmake -DBUILD_TESTING=ON -DABSL_USE_GOOGLETEST_HEAD=ON ..
|
||||
make -j
|
||||
ctest
|
||||
```
|
||||
|
|
@ -93,9 +132,54 @@ absl::flags
|
|||
absl::memory
|
||||
absl::meta
|
||||
absl::numeric
|
||||
absl::random
|
||||
absl::random_random
|
||||
absl::strings
|
||||
absl::synchronization
|
||||
absl::time
|
||||
absl::utility
|
||||
```
|
||||
|
||||
## Traditional CMake Set-Up
|
||||
|
||||
For larger projects, it may make sense to use the traditional CMake set-up where you build and install projects separately.
|
||||
|
||||
First, you'd need to build and install Google Test:
|
||||
```
|
||||
cmake -S /source/googletest -B /build/googletest -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/installation/dir -DBUILD_GMOCK=ON
|
||||
cmake --build /build/googletest --target install
|
||||
```
|
||||
|
||||
Then you need to configure and build Abseil. Make sure you enable `ABSL_USE_EXTERNAL_GOOGLETEST` and `ABSL_FIND_GOOGLETEST`. You also need to enable `ABSL_ENABLE_INSTALL` so that you can install Abseil itself.
|
||||
```
|
||||
cmake -S /source/abseil-cpp -B /build/abseil-cpp -DCMAKE_PREFIX_PATH=/installation/dir -DCMAKE_INSTALL_PREFIX=/installation/dir -DABSL_ENABLE_INSTALL=ON -DABSL_USE_EXTERNAL_GOOGLETEST=ON -DABSL_FIND_GOOGLETEST=ON
|
||||
cmake --build /temporary/build/abseil-cpp
|
||||
```
|
||||
|
||||
(`CMAKE_PREFIX_PATH` is where you already have Google Test installed; `CMAKE_INSTALL_PREFIX` is where you want to have Abseil installed; they can be different.)
|
||||
|
||||
Run the tests:
|
||||
```
|
||||
ctest --test-dir /temporary/build/abseil-cpp
|
||||
```
|
||||
|
||||
And finally install:
|
||||
```
|
||||
cmake --build /temporary/build/abseil-cpp --target install
|
||||
```
|
||||
|
||||
# CMake Option Synposis
|
||||
|
||||
## Enable Standard CMake Installation
|
||||
|
||||
`-DABSL_ENABLE_INSTALL=ON`
|
||||
|
||||
## Google Test Options
|
||||
|
||||
`-DBUILD_TESTING=ON` must be set to enable testing
|
||||
|
||||
- Have Abseil download and build Google Test for you: `-DABSL_USE_EXTERNAL_GOOGLETEST=OFF` (default)
|
||||
- Download and build latest Google Test: `-DABSL_USE_GOOGLETEST_HEAD=ON`
|
||||
- Download specific Google Test version (ZIP archive): `-DABSL_GOOGLETEST_DOWNLOAD_URL=https://.../version.zip`
|
||||
- Use Google Test from specific local directory: `-DABSL_LOCAL_GOOGLETEST_DIR=/path/to/googletest`
|
||||
- Use Google Test included elsewhere in your project: `-DABSL_USE_EXTERNAL_GOOGLETEST=ON`
|
||||
- Use standard CMake `find_package(CTest)` to find installed Google Test: `-DABSL_USE_EXTERNAL_GOOGLETEST=ON -DABSL_FIND_GOOGLETEST=ON`
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
# absl CMake configuration file.
|
||||
|
||||
include(FindThreads)
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(Threads)
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||
include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
project(absl_cmake_testing CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
add_executable(simple simple.cc)
|
||||
|
||||
find_package(absl REQUIRED)
|
||||
|
||||
target_link_libraries(simple absl::strings)
|
||||
target_link_libraries(simple absl::strings absl::config)
|
||||
|
|
|
|||
|
|
@ -14,8 +14,17 @@
|
|||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/strings/substitute.h"
|
||||
|
||||
#if !defined(ABSL_LTS_RELEASE_VERSION) || ABSL_LTS_RELEASE_VERSION != 99998877
|
||||
#error ABSL_LTS_RELEASE_VERSION is not set correctly.
|
||||
#endif
|
||||
|
||||
#if !defined(ABSL_LTS_RELEASE_PATCH_LEVEL) || ABSL_LTS_RELEASE_PATCH_LEVEL != 0
|
||||
#error ABSL_LTS_RELEASE_PATCH_LEVEL is not set correctly.
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
std::cout << absl::Substitute("Arg $0: $1\n", i, argv[i]);
|
||||
|
|
|
|||
|
|
@ -13,70 +13,60 @@
|
|||
# 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.
|
||||
|
||||
# "Unit" and integration tests for Absl CMake installation
|
||||
|
||||
# TODO(absl-team): This script isn't fully hermetic because
|
||||
# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
|
||||
# version of GoogleTest. This means that an upstream change to GoogleTest could
|
||||
# break this test. Fix this by allowing this script to pin to a known-good
|
||||
# version of GoogleTest.
|
||||
#
|
||||
# Unit and integration tests for Abseil LTS CMake installation
|
||||
|
||||
# Fail on any error. Treat unset variables an error. Print commands as executed.
|
||||
set -euox pipefail
|
||||
|
||||
install_absl() {
|
||||
pushd "${absl_build_dir}"
|
||||
if [[ "${#}" -eq 1 ]]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX="${1}" "${absl_dir}"
|
||||
else
|
||||
cmake "${absl_dir}"
|
||||
fi
|
||||
cmake --build . --target install -- -j
|
||||
popd
|
||||
}
|
||||
|
||||
uninstall_absl() {
|
||||
xargs rm < "${absl_build_dir}"/install_manifest.txt
|
||||
rm -rf "${absl_build_dir}"
|
||||
mkdir -p "${absl_build_dir}"
|
||||
}
|
||||
|
||||
lts_install=""
|
||||
|
||||
while getopts ":l" lts; do
|
||||
case "${lts}" in
|
||||
l )
|
||||
lts_install="true"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
absl_dir=/abseil-cpp
|
||||
absl_build_dir=/buildfs/absl-build
|
||||
absl_build_dir=/buildfs
|
||||
googletest_builddir=/googletest_builddir
|
||||
project_dir="${absl_dir}"/CMake/install_test_project
|
||||
project_build_dir=/buildfs/project-build
|
||||
|
||||
mkdir -p "${absl_build_dir}"
|
||||
build_shared_libs="OFF"
|
||||
if [ "${LINK_TYPE:-}" = "DYNAMIC" ]; then
|
||||
build_shared_libs="ON"
|
||||
fi
|
||||
|
||||
# Build and install GoogleTest
|
||||
mkdir "${googletest_builddir}"
|
||||
pushd "${googletest_builddir}"
|
||||
curl -L "${ABSL_GOOGLETEST_DOWNLOAD_URL}" --output "${ABSL_GOOGLETEST_COMMIT}".zip
|
||||
unzip "${ABSL_GOOGLETEST_COMMIT}".zip
|
||||
pushd "googletest-${ABSL_GOOGLETEST_COMMIT}"
|
||||
mkdir build
|
||||
pushd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS="${build_shared_libs}" ..
|
||||
make -j $(nproc)
|
||||
make install
|
||||
ldconfig
|
||||
popd
|
||||
popd
|
||||
popd
|
||||
|
||||
# Run the LTS transformations
|
||||
./create_lts.py 99998877
|
||||
|
||||
# Build and install Abseil
|
||||
pushd "${absl_build_dir}"
|
||||
cmake "${absl_dir}" \
|
||||
-DABSL_USE_EXTERNAL_GOOGLETEST=ON \
|
||||
-DABSL_FIND_GOOGLETEST=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_TESTING=ON \
|
||||
-DBUILD_SHARED_LIBS="${build_shared_libs}"
|
||||
make -j $(nproc)
|
||||
ctest -j $(nproc)
|
||||
make install
|
||||
ldconfig
|
||||
popd
|
||||
|
||||
# Test the project against the installed Abseil
|
||||
mkdir -p "${project_build_dir}"
|
||||
|
||||
if [[ "${lts_install}" ]]; then
|
||||
install_dir="/usr/local"
|
||||
else
|
||||
install_dir="${project_build_dir}"/install
|
||||
fi
|
||||
mkdir -p "${install_dir}"
|
||||
|
||||
# Test build, install, and link against installed abseil
|
||||
pushd "${project_build_dir}"
|
||||
if [[ "${lts_install}" ]]; then
|
||||
install_absl
|
||||
cmake "${project_dir}"
|
||||
else
|
||||
install_absl "${install_dir}"
|
||||
cmake "${project_dir}" -DCMAKE_PREFIX_PATH="${install_dir}"
|
||||
fi
|
||||
|
||||
cmake "${project_dir}"
|
||||
cmake --build . --target simple
|
||||
|
||||
output="$(${project_build_dir}/simple "printme" 2>&1)"
|
||||
|
|
@ -88,57 +78,35 @@ fi
|
|||
|
||||
popd
|
||||
|
||||
# Test that we haven't accidentally made absl::abslblah
|
||||
pushd "${install_dir}"
|
||||
|
||||
# Starting in CMake 3.12 the default install dir is lib$bit_width
|
||||
if [[ -d lib64 ]]; then
|
||||
libdir="lib64"
|
||||
elif [[ -d lib ]]; then
|
||||
libdir="lib"
|
||||
else
|
||||
echo "ls *, */*, */*/*:"
|
||||
ls *
|
||||
ls */*
|
||||
ls */*/*
|
||||
echo "unknown lib dir"
|
||||
fi
|
||||
|
||||
if [[ "${lts_install}" ]]; then
|
||||
# LTS versions append the date of the release to the subdir.
|
||||
# 9999/99/99 is the dummy date used in the local_lts workflow.
|
||||
absl_subdir="absl_99999999"
|
||||
else
|
||||
absl_subdir="absl"
|
||||
fi
|
||||
|
||||
if ! grep absl::strings "${libdir}/cmake/${absl_subdir}/abslTargets.cmake"; then
|
||||
cat "${libdir}"/cmake/absl/abslTargets.cmake
|
||||
if ! grep absl::strings "/usr/local/lib/cmake/absl/abslTargets.cmake"; then
|
||||
cat "/usr/local/lib/cmake/absl/abslTargets.cmake"
|
||||
echo "CMake targets named incorrectly"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
uninstall_absl
|
||||
popd
|
||||
pushd "${HOME}"
|
||||
cat > hello-abseil.cc << EOF
|
||||
#include <cstdlib>
|
||||
|
||||
if [[ ! "${lts_install}" ]]; then
|
||||
# Test that we warn if installed without a prefix or a system prefix
|
||||
output="$(install_absl 2>&1)"
|
||||
if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then
|
||||
echo "Install without prefix didn't warn as expected. Output:"
|
||||
echo "${output}"
|
||||
exit 1
|
||||
fi
|
||||
uninstall_absl
|
||||
#include "absl/strings/str_format.h"
|
||||
|
||||
output="$(install_absl /usr 2>&1)"
|
||||
if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then
|
||||
echo "Install with /usr didn't warn as expected. Output:"
|
||||
echo "${output}"
|
||||
exit 1
|
||||
fi
|
||||
uninstall_absl
|
||||
int main(int argc, char **argv) {
|
||||
absl::PrintF("Hello Abseil!\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
EOF
|
||||
|
||||
if [ "${LINK_TYPE:-}" != "DYNAMIC" ]; then
|
||||
pc_args=($(pkg-config --cflags --libs --static absl_str_format))
|
||||
g++ -static -o hello-abseil hello-abseil.cc "${pc_args[@]}"
|
||||
else
|
||||
pc_args=($(pkg-config --cflags --libs absl_str_format))
|
||||
g++ -o hello-abseil hello-abseil.cc "${pc_args[@]}"
|
||||
fi
|
||||
hello="$(./hello-abseil)"
|
||||
[[ "${hello}" == "Hello Abseil!" ]]
|
||||
|
||||
popd
|
||||
|
||||
echo "Install test complete!"
|
||||
exit 0
|
||||
|
|
|
|||
|
|
@ -22,15 +22,36 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# Compiler id for Apple Clang is now AppleClang.
|
||||
cmake_policy(SET CMP0025 NEW)
|
||||
if (POLICY CMP0025)
|
||||
cmake_policy(SET CMP0025 NEW)
|
||||
endif (POLICY CMP0025)
|
||||
|
||||
# if command can use IN_LIST
|
||||
cmake_policy(SET CMP0057 NEW)
|
||||
if (POLICY CMP0057)
|
||||
cmake_policy(SET CMP0057 NEW)
|
||||
endif (POLICY CMP0057)
|
||||
|
||||
# Project version variables are the empty string if version is unspecified
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
if (POLICY CMP0048)
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
endif (POLICY CMP0048)
|
||||
|
||||
project(absl CXX)
|
||||
# option() honor variables
|
||||
if (POLICY CMP0077)
|
||||
cmake_policy(SET CMP0077 NEW)
|
||||
endif (POLICY CMP0077)
|
||||
|
||||
# Allow the user to specify the MSVC runtime
|
||||
if (POLICY CMP0091)
|
||||
cmake_policy(SET CMP0091 NEW)
|
||||
endif (POLICY CMP0091)
|
||||
|
||||
# Set BUILD_TESTING to OFF by default.
|
||||
# This must come before the project() and include(CTest) lines.
|
||||
OPTION(BUILD_TESTING "Build tests" OFF)
|
||||
|
||||
project(absl LANGUAGES CXX)
|
||||
include(CTest)
|
||||
|
||||
# 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
|
||||
|
|
@ -40,10 +61,17 @@ 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}$")
|
||||
set(ABSL_ENABLE_INSTALL FALSE)
|
||||
if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
option(ABSL_ENABLE_INSTALL "Enable install rule" OFF)
|
||||
else()
|
||||
set(ABSL_ENABLE_INSTALL TRUE)
|
||||
option(ABSL_ENABLE_INSTALL "Enable install rule" ON)
|
||||
endif()
|
||||
|
||||
option(ABSL_PROPAGATE_CXX_STD
|
||||
"Use CMake C++ standard meta features (e.g. cxx_std_11) that propagate to targets that link to Abseil"
|
||||
OFF) # TODO: Default to ON for CMake 3.8 and greater.
|
||||
if((${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.8) AND (NOT ABSL_PROPAGATE_CXX_STD))
|
||||
message(WARNING "A future Abseil release will default ABSL_PROPAGATE_CXX_STD to ON for CMake 3.8 and up. We recommend enabling this option to ensure your project still builds correctly.")
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
|
|
@ -51,8 +79,8 @@ list(APPEND CMAKE_MODULE_PATH
|
|||
${CMAKE_CURRENT_LIST_DIR}/absl/copts
|
||||
)
|
||||
|
||||
include(AbseilInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
include(AbseilDll)
|
||||
include(AbseilHelpers)
|
||||
|
||||
|
|
@ -81,41 +109,71 @@ endif()
|
|||
## pthread
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
include(CMakeDependentOption)
|
||||
|
||||
option(ABSL_USE_EXTERNAL_GOOGLETEST
|
||||
"If ON, Abseil will assume that the targets for GoogleTest are already provided by the including project. This makes sense when Abseil is used with add_subproject." OFF)
|
||||
|
||||
cmake_dependent_option(ABSL_FIND_GOOGLETEST
|
||||
"If ON, Abseil will use find_package(GTest) rather than assuming that GoogleTest is already provided by the including project."
|
||||
ON
|
||||
"ABSL_USE_EXTERNAL_GOOGLETEST"
|
||||
OFF)
|
||||
|
||||
|
||||
option(ABSL_USE_GOOGLETEST_HEAD
|
||||
"If ON, abseil will download HEAD from googletest at config time." OFF)
|
||||
"If ON, abseil will download HEAD from GoogleTest at config time." OFF)
|
||||
|
||||
set(ABSL_GOOGLETEST_DOWNLOAD_URL "" CACHE STRING "If set, download GoogleTest from this URL")
|
||||
|
||||
set(ABSL_LOCAL_GOOGLETEST_DIR "/usr/src/googletest" CACHE PATH
|
||||
"If ABSL_USE_GOOGLETEST_HEAD is OFF, specifies the directory of a local googletest checkout."
|
||||
"If ABSL_USE_GOOGLETEST_HEAD is OFF and ABSL_GOOGLETEST_URL is not set, specifies the directory of a local GoogleTest checkout."
|
||||
)
|
||||
|
||||
option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF)
|
||||
|
||||
if(${ABSL_RUN_TESTS})
|
||||
# enable CTest. This will set BUILD_TESTING to ON unless otherwise specified
|
||||
# on the command line
|
||||
include(CTest)
|
||||
enable_testing()
|
||||
endif()
|
||||
|
||||
## check targets
|
||||
if(BUILD_TESTING)
|
||||
|
||||
set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build)
|
||||
if(${ABSL_USE_GOOGLETEST_HEAD})
|
||||
set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src)
|
||||
## check targets
|
||||
if (ABSL_USE_EXTERNAL_GOOGLETEST)
|
||||
if (ABSL_FIND_GOOGLETEST)
|
||||
find_package(GTest REQUIRED)
|
||||
else()
|
||||
if (NOT TARGET gtest AND NOT TARGET GTest::gtest)
|
||||
message(FATAL_ERROR "ABSL_USE_EXTERNAL_GOOGLETEST is ON and ABSL_FIND_GOOGLETEST is OFF, which means that the top-level project must build the Google Test project. However, the target gtest was not found.")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
set(absl_gtest_src_dir ${ABSL_LOCAL_GOOGLETEST_DIR})
|
||||
set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build)
|
||||
if(ABSL_USE_GOOGLETEST_HEAD AND ABSL_GOOGLETEST_DOWNLOAD_URL)
|
||||
message(FATAL_ERROR "Do not set both ABSL_USE_GOOGLETEST_HEAD and ABSL_GOOGLETEST_DOWNLOAD_URL")
|
||||
endif()
|
||||
if(ABSL_USE_GOOGLETEST_HEAD)
|
||||
set(absl_gtest_download_url "https://github.com/google/googletest/archive/master.zip")
|
||||
elseif(ABSL_GOOGLETEST_DOWNLOAD_URL)
|
||||
set(absl_gtest_download_url ${ABSL_GOOGLETEST_DOWNLOAD_URL})
|
||||
endif()
|
||||
if(absl_gtest_download_url)
|
||||
set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src)
|
||||
else()
|
||||
set(absl_gtest_src_dir ${ABSL_LOCAL_GOOGLETEST_DIR})
|
||||
endif()
|
||||
include(CMake/Googletest/DownloadGTest.cmake)
|
||||
endif()
|
||||
include(CMake/Googletest/DownloadGTest.cmake)
|
||||
|
||||
check_target(gtest)
|
||||
check_target(gtest_main)
|
||||
check_target(gmock)
|
||||
if (NOT ABSL_FIND_GOOGLETEST)
|
||||
# When Google Test is included directly rather than through find_package, the aliases are missing.
|
||||
add_library(GTest::gtest_main ALIAS gtest_main)
|
||||
add_library(GTest::gtest ALIAS gtest)
|
||||
add_library(GTest::gmock ALIAS gmock)
|
||||
endif()
|
||||
|
||||
check_target(GTest::gtest)
|
||||
check_target(GTest::gtest_main)
|
||||
check_target(GTest::gmock)
|
||||
check_target(GTest::gmock_main)
|
||||
|
||||
list(APPEND ABSL_TEST_COMMON_LIBRARIES
|
||||
gtest_main
|
||||
gtest
|
||||
gmock
|
||||
GTest::gtest_main
|
||||
GTest::gtest
|
||||
GTest::gmock
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
endif()
|
||||
|
|
@ -138,16 +196,16 @@ if(ABSL_ENABLE_INSTALL)
|
|||
# install as a subdirectory only
|
||||
install(EXPORT ${PROJECT_NAME}Targets
|
||||
NAMESPACE absl::
|
||||
DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
|
||||
)
|
||||
|
||||
configure_package_config_file(
|
||||
CMake/abslConfig.cmake.in
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
INSTALL_DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
|
||||
)
|
||||
install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
|
||||
)
|
||||
|
||||
# Abseil only has a version in LTS releases. This mechanism is accomplished
|
||||
|
|
@ -160,14 +218,16 @@ if(ABSL_ENABLE_INSTALL)
|
|||
)
|
||||
|
||||
install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
DESTINATION ${ABSL_INSTALL_CONFIGDIR}
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
|
||||
)
|
||||
endif() # absl_VERSION
|
||||
|
||||
install(DIRECTORY absl
|
||||
DESTINATION ${ABSL_INSTALL_INCLUDEDIR}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
FILES_MATCHING
|
||||
PATTERN "*.inc"
|
||||
PATTERN "*.h"
|
||||
)
|
||||
PATTERN "copts" EXCLUDE
|
||||
PATTERN "testdata" EXCLUDE
|
||||
)
|
||||
endif() # ABSL_ENABLE_INSTALL
|
||||
|
|
|
|||
|
|
@ -27,7 +27,10 @@ compiler, there several ways to do this:
|
|||
file](https://docs.bazel.build/versions/master/guide.html#bazelrc)
|
||||
|
||||
If you are using CMake as the build system, you'll need to add a line like
|
||||
`set(CMAKE_CXX_STANDARD 17)` to your top level `CMakeLists.txt` file. See the
|
||||
`set(CMAKE_CXX_STANDARD 17)` to your top level `CMakeLists.txt` file. If you
|
||||
are developing a library designed to be used by other clients, you should
|
||||
instead leave `CMAKE_CXX_STANDARD` unset and configure the minimum C++ standard
|
||||
required by each of your library targets via `target_compile_features`. See the
|
||||
[CMake build
|
||||
instructions](https://github.com/abseil/abseil-cpp/blob/master/CMake/README.md)
|
||||
for more information.
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
# Long Term Support (LTS) Branches
|
||||
|
||||
This repository contains periodic snapshots of the Abseil codebase that are
|
||||
Long Term Support (LTS) branches. An LTS branch allows you to use a known
|
||||
version of Abseil without interfering with other projects which may also, in
|
||||
turn, use Abseil. (For more information about our releases, see the
|
||||
[Abseil Release Management](https://abseil.io/about/releases) guide.)
|
||||
|
||||
## LTS Branches
|
||||
|
||||
The following lists LTS branches and the dates on which they have been released:
|
||||
|
||||
* [LTS Branch December 18, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_12_18/)
|
||||
* [LTS Branch June 20, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_06_20/)
|
||||
* [LTS Branch August 8, 2019](https://github.com/abseil/abseil-cpp/tree/lts_2019_08_08/)
|
||||
* [LTS Branch February 25, 2020](https://github.com/abseil/abseil-cpp/tree/lts_2020_02_25/)
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
danilchap@chromium.org
|
||||
kwiberg@chromium.org
|
||||
mbonadei@chromium.org
|
||||
phoglund@chromium.org
|
||||
|
||||
# COMPONENT: Internals>Core
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
Name: Abseil
|
||||
Short Name: absl
|
||||
URL: https://github.com/abseil/abseil-cpp
|
||||
License: Apache 2.0
|
||||
License File: LICENSE
|
||||
Version: 0
|
||||
Revision: fba8a316c30690097de5d6127ad307d84a1b74ca
|
||||
Security Critical: yes
|
||||
|
||||
Description:
|
||||
This directory contains the source code of Abseil for C++. This can be used by
|
||||
Chromium's dependencies, but shouldn't be used by Chromium itself.
|
||||
See: https://goo.gl/TgnJb8.
|
||||
|
||||
How to update Abseil:
|
||||
|
||||
1. Download the code from the Abseil git repository (see URL).
|
||||
|
||||
2. Copy the content of the Abseil git repo to //third_party/abseil-cpp.
|
||||
|
||||
3. From //third_party/abseil-cpp/ launch ./rename_annotations.sh.
|
||||
This script will rewrite dynamic_annotations and thread_annotations
|
||||
macros and function inside Abseil in order to avoid ODR violations
|
||||
and macro clashing with Chromium
|
||||
(see: https://github.com/abseil/abseil-cpp/issues/122).
|
||||
|
||||
Local Modifications:
|
||||
|
||||
* absl/copts.bzl has been translated to //third_party/absl-cpp/BUILD.gn. Both
|
||||
files contain lists of compiler flags in order to reduce duplication.
|
||||
|
||||
* All the BUILD.bazel files has been translated to BUILD.gn files.
|
||||
|
||||
* Functions and macros in absl/base/dynamic_annotations.{h,cc} and
|
||||
absl/base/thread_annotations.h have been renamed to avoid ODR
|
||||
violations and macro clashes with Chromium (see step 3).
|
||||
|
|
@ -9,7 +9,9 @@ standard library.
|
|||
- [About Abseil](#about)
|
||||
- [Quickstart](#quickstart)
|
||||
- [Building Abseil](#build)
|
||||
- [Support](#support)
|
||||
- [Codemap](#codemap)
|
||||
- [Releases](#releases)
|
||||
- [License](#license)
|
||||
- [Links](#links)
|
||||
|
||||
|
|
@ -42,14 +44,22 @@ the Abseil code, running tests, and getting a simple binary working.
|
|||
<a name="build"></a>
|
||||
## Building Abseil
|
||||
|
||||
[Bazel](https://bazel.build) is the official build system for Abseil,
|
||||
which is supported on most major platforms (Linux, Windows, macOS, for example)
|
||||
and compilers. See the [quickstart](https://abseil.io/docs/cpp/quickstart) for
|
||||
more information on building Abseil using the Bazel build system.
|
||||
[Bazel](https://bazel.build) and [CMake](https://cmake.org/) are the official
|
||||
build systems for Abseil.
|
||||
|
||||
<a name="cmake"></a>
|
||||
If you require CMake support, please check the
|
||||
[CMake build instructions](CMake/README.md).
|
||||
See the [quickstart](https://abseil.io/docs/cpp/quickstart) for more information
|
||||
on building Abseil using the Bazel build system.
|
||||
|
||||
If you require CMake support, please check the [CMake build
|
||||
instructions](CMake/README.md) and [CMake
|
||||
Quickstart](https://abseil.io/docs/cpp/quickstart-cmake).
|
||||
|
||||
## Support
|
||||
|
||||
Abseil is officially supported on many platforms. See the [Abseil
|
||||
platform support
|
||||
guide](https://abseil.io/docs/cpp/platforms/platforms) for details on
|
||||
supported operating systems, compilers, CPUs, etc.
|
||||
|
||||
## Codemap
|
||||
|
||||
|
|
@ -62,6 +72,9 @@ Abseil contains the following C++ library components:
|
|||
* [`algorithm`](absl/algorithm/)
|
||||
<br /> The `algorithm` library contains additions to the C++ `<algorithm>`
|
||||
library and container-based versions of such algorithms.
|
||||
* [`cleanup`](absl/cleanup/)
|
||||
<br /> The `cleanup` library contains the control-flow-construct-like type
|
||||
`absl::Cleanup` which is used for executing a callback on scope exit.
|
||||
* [`container`](absl/container/)
|
||||
<br /> The `container` library contains additional STL-style containers,
|
||||
including Abseil's unordered "Swiss table" containers.
|
||||
|
|
@ -79,6 +92,12 @@ Abseil contains the following C++ library components:
|
|||
available within C++14 and C++17 versions of the C++ `<type_traits>` library.
|
||||
* [`numeric`](absl/numeric/)
|
||||
<br /> The `numeric` library contains C++11-compatible 128-bit integers.
|
||||
* [`profiling`](absl/profiling/)
|
||||
<br /> The `profiling` library contains utility code for profiling C++
|
||||
entities. It is currently a private dependency of other Abseil libraries.
|
||||
* [`status`](absl/status/)
|
||||
<br /> The `status` contains abstractions for error handling, specifically
|
||||
`absl::Status` and `absl::StatusOr<T>`.
|
||||
* [`strings`](absl/strings/)
|
||||
<br /> The `strings` library contains a variety of strings routines and
|
||||
utilities, including a C++11-compatible version of the C++17
|
||||
|
|
@ -97,6 +116,15 @@ Abseil contains the following C++ library components:
|
|||
* [`utility`](absl/utility/)
|
||||
<br /> The `utility` library contains utility and helper code.
|
||||
|
||||
## Releases
|
||||
|
||||
Abseil recommends users "live-at-head" (update to the latest commit from the
|
||||
master branch as often as possible). However, we realize this philosophy doesn't
|
||||
work for every project, so we also provide [Long Term Support
|
||||
Releases](https://github.com/abseil/abseil-cpp/releases) to which we backport
|
||||
fixes for severe bugs. See our [release
|
||||
management](https://abseil.io/about/releases) document for more details.
|
||||
|
||||
## License
|
||||
|
||||
The Abseil C++ library is licensed under the terms of the Apache
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
workspace(name = "com_google_absl")
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
# GoogleTest/GoogleMock framework. Used by most unit-tests.
|
||||
http_archive(
|
||||
name = "com_google_googletest",
|
||||
urls = ["https://github.com/google/googletest/archive/b6cd405286ed8635ece71c72f118e659f4ade3fb.zip"], # 2019-01-07
|
||||
strip_prefix = "googletest-b6cd405286ed8635ece71c72f118e659f4ade3fb",
|
||||
sha256 = "ff7a82736e158c077e76188232eac77913a15dac0b22508c390ab3f88e6d6d86",
|
||||
)
|
||||
|
||||
# Google benchmark.
|
||||
http_archive(
|
||||
name = "com_github_google_benchmark",
|
||||
urls = ["https://github.com/google/benchmark/archive/16703ff83c1ae6d53e5155df3bb3ab0bc96083be.zip"],
|
||||
strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be",
|
||||
sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3",
|
||||
)
|
||||
|
||||
# C++ rules for Bazel.
|
||||
http_archive(
|
||||
name = "rules_cc",
|
||||
sha256 = "9a446e9dd9c1bb180c86977a8dc1e9e659550ae732ae58bd2e8fd51e15b2c91d",
|
||||
strip_prefix = "rules_cc-262ebec3c2296296526740db4aefce68c80de7fa",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip",
|
||||
"https://github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip",
|
||||
],
|
||||
)
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
# Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# This file contains the definition of the template absl_source_set which
|
||||
# should be the only type of target needed in abseil's BUILD.gn files.
|
||||
# This template will correctly set "configs" and "public_configs" in order
|
||||
# to correctly compile abseil in Chromium.
|
||||
#
|
||||
# Targets that set visibility should set it to something more restrictive than
|
||||
# `absl_visibility` (defined below).
|
||||
#
|
||||
# Usage:
|
||||
# Most of the times its usage will be similar to the example below but all
|
||||
# the arguments avilable in source_set are also available for absl_source_set.
|
||||
#
|
||||
# absl_source_set("foo") {
|
||||
# sources = [ "foo.cc" ]
|
||||
# public = [ "foo.h" ]
|
||||
# deps = [ ":bar" ]
|
||||
# }
|
||||
|
||||
import("//build_overrides/build.gni")
|
||||
|
||||
# Usage of Abseil in Chromium is guarded by an explicit opt-in list, before
|
||||
# adding projects to this list please reach out to cxx@chromium.org and CC:
|
||||
# - https://cs.chromium.org/chromium/src/third_party/abseil-cpp/OWNERS
|
||||
#
|
||||
# More information can be found at:
|
||||
# https://docs.google.com/document/d/1DgS1-A3rzboTLjpf4m1sqkJgWjnY_Ru2dokk1X1vBDU
|
||||
declare_args() {
|
||||
# Additional targets that can depend on absl.
|
||||
# ** DISCLAIMER **
|
||||
#
|
||||
# Using "additional_absl_clients" is highly discouraged because it will break
|
||||
# the component build since Abseil doesn't have export annotations and WebRTC
|
||||
# is already depending on it. Any CL that use "additional_absl_clients" will
|
||||
# have a really high probability of being reverted.
|
||||
additional_absl_clients = []
|
||||
}
|
||||
assert(!is_component_build || additional_absl_clients == [])
|
||||
|
||||
_chromium_absl_clients = [
|
||||
"//libassistant/*",
|
||||
"//third_party/webrtc/*",
|
||||
"//third_party/abseil-cpp/*",
|
||||
"//third_party/googletest:gtest",
|
||||
]
|
||||
|
||||
absl_visibility = _chromium_absl_clients + additional_absl_clients
|
||||
|
||||
template("absl_source_set") {
|
||||
source_set(target_name) {
|
||||
forward_variables_from(invoker, "*")
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
"//build/config/compiler:no_chromium_code",
|
||||
"//third_party/abseil-cpp:absl_default_cflags_cc",
|
||||
]
|
||||
|
||||
if (!defined(public_configs)) {
|
||||
public_configs = []
|
||||
}
|
||||
public_configs += [ "//third_party/abseil-cpp:absl_include_config" ]
|
||||
|
||||
# Usage of Abseil in Chromium is guarded by an explicit opt-in list, before
|
||||
# adding projects to this list please reach out to cxx@chromium.org and CC:
|
||||
# - https://cs.chromium.org/chromium/src/third_party/abseil-cpp/OWNERS
|
||||
#
|
||||
# More information can be found at:
|
||||
# https://docs.google.com/document/d/1DgS1-A3rzboTLjpf4m1sqkJgWjnY_Ru2dokk1X1vBDU
|
||||
if (!defined(visibility)) {
|
||||
if (build_with_chromium) {
|
||||
visibility = absl_visibility
|
||||
} else {
|
||||
visibility = [ "*" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
add_subdirectory(base)
|
||||
add_subdirectory(algorithm)
|
||||
add_subdirectory(cleanup)
|
||||
add_subdirectory(container)
|
||||
add_subdirectory(debugging)
|
||||
add_subdirectory(flags)
|
||||
|
|
@ -24,6 +25,7 @@ add_subdirectory(hash)
|
|||
add_subdirectory(memory)
|
||||
add_subdirectory(meta)
|
||||
add_subdirectory(numeric)
|
||||
add_subdirectory(profiling)
|
||||
add_subdirectory(random)
|
||||
add_subdirectory(status)
|
||||
add_subdirectory(strings)
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ Pod::Spec.new do |s|
|
|||
'USE_HEADERMAP' => 'NO',
|
||||
'ALWAYS_SEARCH_USER_PATHS' => 'NO',
|
||||
}
|
||||
s.ios.deployment_target = '7.0'
|
||||
s.osx.deployment_target = '10.9'
|
||||
s.ios.deployment_target = '9.0'
|
||||
s.osx.deployment_target = '10.10'
|
||||
s.tvos.deployment_target = '9.0'
|
||||
s.watchos.deployment_target = '2.0'
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
# Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//third_party/abseil-cpp/absl.gni")
|
||||
|
||||
absl_source_set("algorithm") {
|
||||
public = [ "algorithm.h" ]
|
||||
deps = [ "../base:config" ]
|
||||
}
|
||||
|
||||
absl_source_set("container") {
|
||||
public = [ "container.h" ]
|
||||
deps = [
|
||||
":algorithm",
|
||||
"../base:core_headers",
|
||||
"../meta:type_traits",
|
||||
]
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ absl_cc_test(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::algorithm
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -65,5 +65,5 @@ absl_cc_test(
|
|||
absl::core_headers
|
||||
absl::memory
|
||||
absl::span
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
|
|
|||
|
|
@ -90,10 +90,10 @@ using ContainerPointerType =
|
|||
// lookup of std::begin and std::end, i.e.
|
||||
// using std::begin;
|
||||
// using std::end;
|
||||
// std::foo(begin(c), end(c);
|
||||
// std::foo(begin(c), end(c));
|
||||
// becomes
|
||||
// std::foo(container_algorithm_internal::begin(c),
|
||||
// container_algorithm_internal::end(c));
|
||||
// container_algorithm_internal::end(c));
|
||||
// These are meant for internal use only.
|
||||
|
||||
template <typename C>
|
||||
|
|
@ -188,7 +188,7 @@ bool c_any_of(const C& c, Pred&& pred) {
|
|||
// c_none_of()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::none_of()` function to
|
||||
// test if no elements in a container fulfil a condition.
|
||||
// test if no elements in a container fulfill a condition.
|
||||
template <typename C, typename Pred>
|
||||
bool c_none_of(const C& c, Pred&& pred) {
|
||||
return std::none_of(container_algorithm_internal::c_begin(c),
|
||||
|
|
@ -340,24 +340,45 @@ container_algorithm_internal::ContainerDifferenceType<const C> c_count_if(
|
|||
// c_mismatch()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::mismatch()` function to
|
||||
// return the first element where two ordered containers differ.
|
||||
// return the first element where two ordered containers differ. Applies `==` to
|
||||
// the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
|
||||
template <typename C1, typename C2>
|
||||
container_algorithm_internal::ContainerIterPairType<C1, C2>
|
||||
c_mismatch(C1& c1, C2& c2) {
|
||||
return std::mismatch(container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2));
|
||||
auto first1 = container_algorithm_internal::c_begin(c1);
|
||||
auto last1 = container_algorithm_internal::c_end(c1);
|
||||
auto first2 = container_algorithm_internal::c_begin(c2);
|
||||
auto last2 = container_algorithm_internal::c_end(c2);
|
||||
|
||||
for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
|
||||
// Negates equality because Cpp17EqualityComparable doesn't require clients
|
||||
// to overload both `operator==` and `operator!=`.
|
||||
if (!(*first1 == *first2)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(first1, first2);
|
||||
}
|
||||
|
||||
// Overload of c_mismatch() for using a predicate evaluation other than `==` as
|
||||
// the function's test condition.
|
||||
// the function's test condition. Applies `pred`to the first N elements of `c1`
|
||||
// and `c2`, where N = min(size(c1), size(c2)).
|
||||
template <typename C1, typename C2, typename BinaryPredicate>
|
||||
container_algorithm_internal::ContainerIterPairType<C1, C2>
|
||||
c_mismatch(C1& c1, C2& c2, BinaryPredicate&& pred) {
|
||||
return std::mismatch(container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2),
|
||||
std::forward<BinaryPredicate>(pred));
|
||||
c_mismatch(C1& c1, C2& c2, BinaryPredicate pred) {
|
||||
auto first1 = container_algorithm_internal::c_begin(c1);
|
||||
auto last1 = container_algorithm_internal::c_end(c1);
|
||||
auto first2 = container_algorithm_internal::c_begin(c2);
|
||||
auto last2 = container_algorithm_internal::c_end(c2);
|
||||
|
||||
for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
|
||||
if (!pred(*first1, *first2)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(first1, first2);
|
||||
}
|
||||
|
||||
// c_equal()
|
||||
|
|
@ -539,12 +560,20 @@ BidirectionalIterator c_move_backward(C&& src, BidirectionalIterator dest) {
|
|||
// c_swap_ranges()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::swap_ranges()` function to
|
||||
// swap a container's elements with another container's elements.
|
||||
// swap a container's elements with another container's elements. Swaps the
|
||||
// first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
|
||||
template <typename C1, typename C2>
|
||||
container_algorithm_internal::ContainerIter<C2> c_swap_ranges(C1& c1, C2& c2) {
|
||||
return std::swap_ranges(container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2));
|
||||
auto first1 = container_algorithm_internal::c_begin(c1);
|
||||
auto last1 = container_algorithm_internal::c_end(c1);
|
||||
auto first2 = container_algorithm_internal::c_begin(c2);
|
||||
auto last2 = container_algorithm_internal::c_end(c2);
|
||||
|
||||
using std::swap;
|
||||
for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
|
||||
swap(*first1, *first2);
|
||||
}
|
||||
return first2;
|
||||
}
|
||||
|
||||
// c_transform()
|
||||
|
|
@ -562,16 +591,23 @@ OutputIterator c_transform(const InputSequence& input, OutputIterator output,
|
|||
}
|
||||
|
||||
// Overload of c_transform() for performing a transformation using a binary
|
||||
// predicate.
|
||||
// predicate. Applies `binary_op` to the first N elements of `c1` and `c2`,
|
||||
// where N = min(size(c1), size(c2)).
|
||||
template <typename InputSequence1, typename InputSequence2,
|
||||
typename OutputIterator, typename BinaryOp>
|
||||
OutputIterator c_transform(const InputSequence1& input1,
|
||||
const InputSequence2& input2, OutputIterator output,
|
||||
BinaryOp&& binary_op) {
|
||||
return std::transform(container_algorithm_internal::c_begin(input1),
|
||||
container_algorithm_internal::c_end(input1),
|
||||
container_algorithm_internal::c_begin(input2), output,
|
||||
std::forward<BinaryOp>(binary_op));
|
||||
auto first1 = container_algorithm_internal::c_begin(input1);
|
||||
auto last1 = container_algorithm_internal::c_end(input1);
|
||||
auto first2 = container_algorithm_internal::c_begin(input2);
|
||||
auto last2 = container_algorithm_internal::c_end(input2);
|
||||
for (; first1 != last1 && first2 != last2;
|
||||
++first1, (void)++first2, ++output) {
|
||||
*output = binary_op(*first1, *first2);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// c_replace()
|
||||
|
|
@ -869,11 +905,11 @@ void c_sort(C& c) {
|
|||
|
||||
// Overload of c_sort() for performing a `comp` comparison other than the
|
||||
// default `operator<`.
|
||||
template <typename C, typename Compare>
|
||||
void c_sort(C& c, Compare&& comp) {
|
||||
template <typename C, typename LessThan>
|
||||
void c_sort(C& c, LessThan&& comp) {
|
||||
std::sort(container_algorithm_internal::c_begin(c),
|
||||
container_algorithm_internal::c_end(c),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_stable_sort()
|
||||
|
|
@ -889,11 +925,11 @@ void c_stable_sort(C& c) {
|
|||
|
||||
// Overload of c_stable_sort() for performing a `comp` comparison other than the
|
||||
// default `operator<`.
|
||||
template <typename C, typename Compare>
|
||||
void c_stable_sort(C& c, Compare&& comp) {
|
||||
template <typename C, typename LessThan>
|
||||
void c_stable_sort(C& c, LessThan&& comp) {
|
||||
std::stable_sort(container_algorithm_internal::c_begin(c),
|
||||
container_algorithm_internal::c_end(c),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_is_sorted()
|
||||
|
|
@ -908,11 +944,11 @@ bool c_is_sorted(const C& c) {
|
|||
|
||||
// c_is_sorted() overload for performing a `comp` comparison other than the
|
||||
// default `operator<`.
|
||||
template <typename C, typename Compare>
|
||||
bool c_is_sorted(const C& c, Compare&& comp) {
|
||||
template <typename C, typename LessThan>
|
||||
bool c_is_sorted(const C& c, LessThan&& comp) {
|
||||
return std::is_sorted(container_algorithm_internal::c_begin(c),
|
||||
container_algorithm_internal::c_end(c),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_partial_sort()
|
||||
|
|
@ -930,22 +966,23 @@ void c_partial_sort(
|
|||
|
||||
// Overload of c_partial_sort() for performing a `comp` comparison other than
|
||||
// the default `operator<`.
|
||||
template <typename RandomAccessContainer, typename Compare>
|
||||
template <typename RandomAccessContainer, typename LessThan>
|
||||
void c_partial_sort(
|
||||
RandomAccessContainer& sequence,
|
||||
container_algorithm_internal::ContainerIter<RandomAccessContainer> middle,
|
||||
Compare&& comp) {
|
||||
LessThan&& comp) {
|
||||
std::partial_sort(container_algorithm_internal::c_begin(sequence), middle,
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_partial_sort_copy()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::partial_sort_copy()`
|
||||
// function to sort elements within a container such that elements before
|
||||
// `middle` are sorted in ascending order, and return the result within an
|
||||
// iterator.
|
||||
// function to sort the elements in the given range `result` within the larger
|
||||
// `sequence` in ascending order (and using `result` as the output parameter).
|
||||
// At most min(result.last - result.first, sequence.last - sequence.first)
|
||||
// elements from the sequence will be stored in the result.
|
||||
template <typename C, typename RandomAccessContainer>
|
||||
container_algorithm_internal::ContainerIter<RandomAccessContainer>
|
||||
c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) {
|
||||
|
|
@ -957,15 +994,15 @@ c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) {
|
|||
|
||||
// Overload of c_partial_sort_copy() for performing a `comp` comparison other
|
||||
// than the default `operator<`.
|
||||
template <typename C, typename RandomAccessContainer, typename Compare>
|
||||
template <typename C, typename RandomAccessContainer, typename LessThan>
|
||||
container_algorithm_internal::ContainerIter<RandomAccessContainer>
|
||||
c_partial_sort_copy(const C& sequence, RandomAccessContainer& result,
|
||||
Compare&& comp) {
|
||||
LessThan&& comp) {
|
||||
return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
container_algorithm_internal::c_begin(result),
|
||||
container_algorithm_internal::c_end(result),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_is_sorted_until()
|
||||
|
|
@ -981,12 +1018,12 @@ container_algorithm_internal::ContainerIter<C> c_is_sorted_until(C& c) {
|
|||
|
||||
// Overload of c_is_sorted_until() for performing a `comp` comparison other than
|
||||
// the default `operator<`.
|
||||
template <typename C, typename Compare>
|
||||
template <typename C, typename LessThan>
|
||||
container_algorithm_internal::ContainerIter<C> c_is_sorted_until(
|
||||
C& c, Compare&& comp) {
|
||||
C& c, LessThan&& comp) {
|
||||
return std::is_sorted_until(container_algorithm_internal::c_begin(c),
|
||||
container_algorithm_internal::c_end(c),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_nth_element()
|
||||
|
|
@ -1006,14 +1043,14 @@ void c_nth_element(
|
|||
|
||||
// Overload of c_nth_element() for performing a `comp` comparison other than
|
||||
// the default `operator<`.
|
||||
template <typename RandomAccessContainer, typename Compare>
|
||||
template <typename RandomAccessContainer, typename LessThan>
|
||||
void c_nth_element(
|
||||
RandomAccessContainer& sequence,
|
||||
container_algorithm_internal::ContainerIter<RandomAccessContainer> nth,
|
||||
Compare&& comp) {
|
||||
LessThan&& comp) {
|
||||
std::nth_element(container_algorithm_internal::c_begin(sequence), nth,
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -1035,12 +1072,12 @@ container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
|
|||
|
||||
// Overload of c_lower_bound() for performing a `comp` comparison other than
|
||||
// the default `operator<`.
|
||||
template <typename Sequence, typename T, typename Compare>
|
||||
template <typename Sequence, typename T, typename LessThan>
|
||||
container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
|
||||
Sequence& sequence, T&& value, Compare&& comp) {
|
||||
Sequence& sequence, T&& value, LessThan&& comp) {
|
||||
return std::lower_bound(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<T>(value), std::forward<Compare>(comp));
|
||||
std::forward<T>(value), std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_upper_bound()
|
||||
|
|
@ -1058,12 +1095,12 @@ container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
|
|||
|
||||
// Overload of c_upper_bound() for performing a `comp` comparison other than
|
||||
// the default `operator<`.
|
||||
template <typename Sequence, typename T, typename Compare>
|
||||
template <typename Sequence, typename T, typename LessThan>
|
||||
container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
|
||||
Sequence& sequence, T&& value, Compare&& comp) {
|
||||
Sequence& sequence, T&& value, LessThan&& comp) {
|
||||
return std::upper_bound(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<T>(value), std::forward<Compare>(comp));
|
||||
std::forward<T>(value), std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_equal_range()
|
||||
|
|
@ -1081,12 +1118,12 @@ c_equal_range(Sequence& sequence, T&& value) {
|
|||
|
||||
// Overload of c_equal_range() for performing a `comp` comparison other than
|
||||
// the default `operator<`.
|
||||
template <typename Sequence, typename T, typename Compare>
|
||||
template <typename Sequence, typename T, typename LessThan>
|
||||
container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
|
||||
c_equal_range(Sequence& sequence, T&& value, Compare&& comp) {
|
||||
c_equal_range(Sequence& sequence, T&& value, LessThan&& comp) {
|
||||
return std::equal_range(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<T>(value), std::forward<Compare>(comp));
|
||||
std::forward<T>(value), std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_binary_search()
|
||||
|
|
@ -1103,12 +1140,12 @@ bool c_binary_search(Sequence&& sequence, T&& value) {
|
|||
|
||||
// Overload of c_binary_search() for performing a `comp` comparison other than
|
||||
// the default `operator<`.
|
||||
template <typename Sequence, typename T, typename Compare>
|
||||
bool c_binary_search(Sequence&& sequence, T&& value, Compare&& comp) {
|
||||
template <typename Sequence, typename T, typename LessThan>
|
||||
bool c_binary_search(Sequence&& sequence, T&& value, LessThan&& comp) {
|
||||
return std::binary_search(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<T>(value),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -1129,14 +1166,14 @@ OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result) {
|
|||
|
||||
// Overload of c_merge() for performing a `comp` comparison other than
|
||||
// the default `operator<`.
|
||||
template <typename C1, typename C2, typename OutputIterator, typename Compare>
|
||||
template <typename C1, typename C2, typename OutputIterator, typename LessThan>
|
||||
OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result,
|
||||
Compare&& comp) {
|
||||
LessThan&& comp) {
|
||||
return std::merge(container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2),
|
||||
container_algorithm_internal::c_end(c2), result,
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_inplace_merge()
|
||||
|
|
@ -1152,13 +1189,13 @@ void c_inplace_merge(C& c,
|
|||
|
||||
// Overload of c_inplace_merge() for performing a merge using a `comp` other
|
||||
// than `operator<`.
|
||||
template <typename C, typename Compare>
|
||||
template <typename C, typename LessThan>
|
||||
void c_inplace_merge(C& c,
|
||||
container_algorithm_internal::ContainerIter<C> middle,
|
||||
Compare&& comp) {
|
||||
LessThan&& comp) {
|
||||
std::inplace_merge(container_algorithm_internal::c_begin(c), middle,
|
||||
container_algorithm_internal::c_end(c),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_includes()
|
||||
|
|
@ -1176,13 +1213,13 @@ bool c_includes(const C1& c1, const C2& c2) {
|
|||
|
||||
// Overload of c_includes() for performing a merge using a `comp` other than
|
||||
// `operator<`.
|
||||
template <typename C1, typename C2, typename Compare>
|
||||
bool c_includes(const C1& c1, const C2& c2, Compare&& comp) {
|
||||
template <typename C1, typename C2, typename LessThan>
|
||||
bool c_includes(const C1& c1, const C2& c2, LessThan&& comp) {
|
||||
return std::includes(container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2),
|
||||
container_algorithm_internal::c_end(c2),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_set_union()
|
||||
|
|
@ -1206,7 +1243,7 @@ OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
|
|||
|
||||
// Overload of c_set_union() for performing a merge using a `comp` other than
|
||||
// `operator<`.
|
||||
template <typename C1, typename C2, typename OutputIterator, typename Compare,
|
||||
template <typename C1, typename C2, typename OutputIterator, typename LessThan,
|
||||
typename = typename std::enable_if<
|
||||
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
|
||||
void>::type,
|
||||
|
|
@ -1214,18 +1251,18 @@ template <typename C1, typename C2, typename OutputIterator, typename Compare,
|
|||
!container_algorithm_internal::IsUnorderedContainer<C2>::value,
|
||||
void>::type>
|
||||
OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output,
|
||||
Compare&& comp) {
|
||||
LessThan&& comp) {
|
||||
return std::set_union(container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2),
|
||||
container_algorithm_internal::c_end(c2), output,
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_set_intersection()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::set_intersection()` function
|
||||
// to return an iterator containing the intersection of two containers.
|
||||
// to return an iterator containing the intersection of two sorted containers.
|
||||
template <typename C1, typename C2, typename OutputIterator,
|
||||
typename = typename std::enable_if<
|
||||
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
|
||||
|
|
@ -1235,6 +1272,11 @@ template <typename C1, typename C2, typename OutputIterator,
|
|||
void>::type>
|
||||
OutputIterator c_set_intersection(const C1& c1, const C2& c2,
|
||||
OutputIterator output) {
|
||||
// In debug builds, ensure that both containers are sorted with respect to the
|
||||
// default comparator. std::set_intersection requires the containers be sorted
|
||||
// using operator<.
|
||||
assert(absl::c_is_sorted(c1));
|
||||
assert(absl::c_is_sorted(c2));
|
||||
return std::set_intersection(container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2),
|
||||
|
|
@ -1243,7 +1285,7 @@ OutputIterator c_set_intersection(const C1& c1, const C2& c2,
|
|||
|
||||
// Overload of c_set_intersection() for performing a merge using a `comp` other
|
||||
// than `operator<`.
|
||||
template <typename C1, typename C2, typename OutputIterator, typename Compare,
|
||||
template <typename C1, typename C2, typename OutputIterator, typename LessThan,
|
||||
typename = typename std::enable_if<
|
||||
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
|
||||
void>::type,
|
||||
|
|
@ -1251,12 +1293,17 @@ template <typename C1, typename C2, typename OutputIterator, typename Compare,
|
|||
!container_algorithm_internal::IsUnorderedContainer<C2>::value,
|
||||
void>::type>
|
||||
OutputIterator c_set_intersection(const C1& c1, const C2& c2,
|
||||
OutputIterator output, Compare&& comp) {
|
||||
OutputIterator output, LessThan&& comp) {
|
||||
// In debug builds, ensure that both containers are sorted with respect to the
|
||||
// default comparator. std::set_intersection requires the containers be sorted
|
||||
// using the same comparator.
|
||||
assert(absl::c_is_sorted(c1, comp));
|
||||
assert(absl::c_is_sorted(c2, comp));
|
||||
return std::set_intersection(container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2),
|
||||
container_algorithm_internal::c_end(c2), output,
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_set_difference()
|
||||
|
|
@ -1281,7 +1328,7 @@ OutputIterator c_set_difference(const C1& c1, const C2& c2,
|
|||
|
||||
// Overload of c_set_difference() for performing a merge using a `comp` other
|
||||
// than `operator<`.
|
||||
template <typename C1, typename C2, typename OutputIterator, typename Compare,
|
||||
template <typename C1, typename C2, typename OutputIterator, typename LessThan,
|
||||
typename = typename std::enable_if<
|
||||
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
|
||||
void>::type,
|
||||
|
|
@ -1289,12 +1336,12 @@ template <typename C1, typename C2, typename OutputIterator, typename Compare,
|
|||
!container_algorithm_internal::IsUnorderedContainer<C2>::value,
|
||||
void>::type>
|
||||
OutputIterator c_set_difference(const C1& c1, const C2& c2,
|
||||
OutputIterator output, Compare&& comp) {
|
||||
OutputIterator output, LessThan&& comp) {
|
||||
return std::set_difference(container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2),
|
||||
container_algorithm_internal::c_end(c2), output,
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_set_symmetric_difference()
|
||||
|
|
@ -1320,7 +1367,7 @@ OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
|
|||
|
||||
// Overload of c_set_symmetric_difference() for performing a merge using a
|
||||
// `comp` other than `operator<`.
|
||||
template <typename C1, typename C2, typename OutputIterator, typename Compare,
|
||||
template <typename C1, typename C2, typename OutputIterator, typename LessThan,
|
||||
typename = typename std::enable_if<
|
||||
!container_algorithm_internal::IsUnorderedContainer<C1>::value,
|
||||
void>::type,
|
||||
|
|
@ -1329,13 +1376,13 @@ template <typename C1, typename C2, typename OutputIterator, typename Compare,
|
|||
void>::type>
|
||||
OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
|
||||
OutputIterator output,
|
||||
Compare&& comp) {
|
||||
LessThan&& comp) {
|
||||
return std::set_symmetric_difference(
|
||||
container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2),
|
||||
container_algorithm_internal::c_end(c2), output,
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -1354,11 +1401,11 @@ void c_push_heap(RandomAccessContainer& sequence) {
|
|||
|
||||
// Overload of c_push_heap() for performing a push operation on a heap using a
|
||||
// `comp` other than `operator<`.
|
||||
template <typename RandomAccessContainer, typename Compare>
|
||||
void c_push_heap(RandomAccessContainer& sequence, Compare&& comp) {
|
||||
template <typename RandomAccessContainer, typename LessThan>
|
||||
void c_push_heap(RandomAccessContainer& sequence, LessThan&& comp) {
|
||||
std::push_heap(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_pop_heap()
|
||||
|
|
@ -1373,11 +1420,11 @@ void c_pop_heap(RandomAccessContainer& sequence) {
|
|||
|
||||
// Overload of c_pop_heap() for performing a pop operation on a heap using a
|
||||
// `comp` other than `operator<`.
|
||||
template <typename RandomAccessContainer, typename Compare>
|
||||
void c_pop_heap(RandomAccessContainer& sequence, Compare&& comp) {
|
||||
template <typename RandomAccessContainer, typename LessThan>
|
||||
void c_pop_heap(RandomAccessContainer& sequence, LessThan&& comp) {
|
||||
std::pop_heap(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_make_heap()
|
||||
|
|
@ -1392,11 +1439,11 @@ void c_make_heap(RandomAccessContainer& sequence) {
|
|||
|
||||
// Overload of c_make_heap() for performing heap comparisons using a
|
||||
// `comp` other than `operator<`
|
||||
template <typename RandomAccessContainer, typename Compare>
|
||||
void c_make_heap(RandomAccessContainer& sequence, Compare&& comp) {
|
||||
template <typename RandomAccessContainer, typename LessThan>
|
||||
void c_make_heap(RandomAccessContainer& sequence, LessThan&& comp) {
|
||||
std::make_heap(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_sort_heap()
|
||||
|
|
@ -1411,11 +1458,11 @@ void c_sort_heap(RandomAccessContainer& sequence) {
|
|||
|
||||
// Overload of c_sort_heap() for performing heap comparisons using a
|
||||
// `comp` other than `operator<`
|
||||
template <typename RandomAccessContainer, typename Compare>
|
||||
void c_sort_heap(RandomAccessContainer& sequence, Compare&& comp) {
|
||||
template <typename RandomAccessContainer, typename LessThan>
|
||||
void c_sort_heap(RandomAccessContainer& sequence, LessThan&& comp) {
|
||||
std::sort_heap(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_is_heap()
|
||||
|
|
@ -1430,11 +1477,11 @@ bool c_is_heap(const RandomAccessContainer& sequence) {
|
|||
|
||||
// Overload of c_is_heap() for performing heap comparisons using a
|
||||
// `comp` other than `operator<`
|
||||
template <typename RandomAccessContainer, typename Compare>
|
||||
bool c_is_heap(const RandomAccessContainer& sequence, Compare&& comp) {
|
||||
template <typename RandomAccessContainer, typename LessThan>
|
||||
bool c_is_heap(const RandomAccessContainer& sequence, LessThan&& comp) {
|
||||
return std::is_heap(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_is_heap_until()
|
||||
|
|
@ -1450,12 +1497,12 @@ c_is_heap_until(RandomAccessContainer& sequence) {
|
|||
|
||||
// Overload of c_is_heap_until() for performing heap comparisons using a
|
||||
// `comp` other than `operator<`
|
||||
template <typename RandomAccessContainer, typename Compare>
|
||||
template <typename RandomAccessContainer, typename LessThan>
|
||||
container_algorithm_internal::ContainerIter<RandomAccessContainer>
|
||||
c_is_heap_until(RandomAccessContainer& sequence, Compare&& comp) {
|
||||
c_is_heap_until(RandomAccessContainer& sequence, LessThan&& comp) {
|
||||
return std::is_heap_until(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -1476,12 +1523,12 @@ container_algorithm_internal::ContainerIter<Sequence> c_min_element(
|
|||
|
||||
// Overload of c_min_element() for performing a `comp` comparison other than
|
||||
// `operator<`.
|
||||
template <typename Sequence, typename Compare>
|
||||
template <typename Sequence, typename LessThan>
|
||||
container_algorithm_internal::ContainerIter<Sequence> c_min_element(
|
||||
Sequence& sequence, Compare&& comp) {
|
||||
Sequence& sequence, LessThan&& comp) {
|
||||
return std::min_element(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_max_element()
|
||||
|
|
@ -1498,12 +1545,12 @@ container_algorithm_internal::ContainerIter<Sequence> c_max_element(
|
|||
|
||||
// Overload of c_max_element() for performing a `comp` comparison other than
|
||||
// `operator<`.
|
||||
template <typename Sequence, typename Compare>
|
||||
template <typename Sequence, typename LessThan>
|
||||
container_algorithm_internal::ContainerIter<Sequence> c_max_element(
|
||||
Sequence& sequence, Compare&& comp) {
|
||||
Sequence& sequence, LessThan&& comp) {
|
||||
return std::max_element(container_algorithm_internal::c_begin(sequence),
|
||||
container_algorithm_internal::c_end(sequence),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_minmax_element()
|
||||
|
|
@ -1521,12 +1568,12 @@ c_minmax_element(C& c) {
|
|||
|
||||
// Overload of c_minmax_element() for performing `comp` comparisons other than
|
||||
// `operator<`.
|
||||
template <typename C, typename Compare>
|
||||
template <typename C, typename LessThan>
|
||||
container_algorithm_internal::ContainerIterPairType<C, C>
|
||||
c_minmax_element(C& c, Compare&& comp) {
|
||||
c_minmax_element(C& c, LessThan&& comp) {
|
||||
return std::minmax_element(container_algorithm_internal::c_begin(c),
|
||||
container_algorithm_internal::c_end(c),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -1551,15 +1598,15 @@ bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2) {
|
|||
|
||||
// Overload of c_lexicographical_compare() for performing a lexicographical
|
||||
// comparison using a `comp` operator instead of `operator<`.
|
||||
template <typename Sequence1, typename Sequence2, typename Compare>
|
||||
template <typename Sequence1, typename Sequence2, typename LessThan>
|
||||
bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2,
|
||||
Compare&& comp) {
|
||||
LessThan&& comp) {
|
||||
return std::lexicographical_compare(
|
||||
container_algorithm_internal::c_begin(sequence1),
|
||||
container_algorithm_internal::c_end(sequence1),
|
||||
container_algorithm_internal::c_begin(sequence2),
|
||||
container_algorithm_internal::c_end(sequence2),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_next_permutation()
|
||||
|
|
@ -1575,11 +1622,11 @@ bool c_next_permutation(C& c) {
|
|||
|
||||
// Overload of c_next_permutation() for performing a lexicographical
|
||||
// comparison using a `comp` operator instead of `operator<`.
|
||||
template <typename C, typename Compare>
|
||||
bool c_next_permutation(C& c, Compare&& comp) {
|
||||
template <typename C, typename LessThan>
|
||||
bool c_next_permutation(C& c, LessThan&& comp) {
|
||||
return std::next_permutation(container_algorithm_internal::c_begin(c),
|
||||
container_algorithm_internal::c_end(c),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
// c_prev_permutation()
|
||||
|
|
@ -1595,11 +1642,11 @@ bool c_prev_permutation(C& c) {
|
|||
|
||||
// Overload of c_prev_permutation() for performing a lexicographical
|
||||
// comparison using a `comp` operator instead of `operator<`.
|
||||
template <typename C, typename Compare>
|
||||
bool c_prev_permutation(C& c, Compare&& comp) {
|
||||
template <typename C, typename LessThan>
|
||||
bool c_prev_permutation(C& c, LessThan&& comp) {
|
||||
return std::prev_permutation(container_algorithm_internal::c_begin(c),
|
||||
container_algorithm_internal::c_end(c),
|
||||
std::forward<Compare>(comp));
|
||||
std::forward<LessThan>(comp));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -57,9 +57,7 @@ class NonMutatingTest : public testing::Test {
|
|||
};
|
||||
|
||||
struct AccumulateCalls {
|
||||
void operator()(int value) {
|
||||
calls.push_back(value);
|
||||
}
|
||||
void operator()(int value) { calls.push_back(value); }
|
||||
std::vector<int> calls;
|
||||
};
|
||||
|
||||
|
|
@ -68,7 +66,6 @@ bool BinPredicate(int v1, int v2) { return v1 < v2; }
|
|||
bool Equals(int v1, int v2) { return v1 == v2; }
|
||||
bool IsOdd(int x) { return x % 2 != 0; }
|
||||
|
||||
|
||||
TEST_F(NonMutatingTest, Distance) {
|
||||
EXPECT_EQ(container_.size(), absl::c_distance(container_));
|
||||
EXPECT_EQ(sequence_.size(), absl::c_distance(sequence_));
|
||||
|
|
@ -151,13 +148,90 @@ TEST_F(NonMutatingTest, CountIf) {
|
|||
}
|
||||
|
||||
TEST_F(NonMutatingTest, Mismatch) {
|
||||
absl::c_mismatch(container_, sequence_);
|
||||
absl::c_mismatch(sequence_, container_);
|
||||
// Testing necessary as absl::c_mismatch executes logic.
|
||||
{
|
||||
auto result = absl::c_mismatch(vector_, sequence_);
|
||||
EXPECT_EQ(result.first, vector_.end());
|
||||
EXPECT_EQ(result.second, sequence_.end());
|
||||
}
|
||||
{
|
||||
auto result = absl::c_mismatch(sequence_, vector_);
|
||||
EXPECT_EQ(result.first, sequence_.end());
|
||||
EXPECT_EQ(result.second, vector_.end());
|
||||
}
|
||||
|
||||
sequence_.back() = 5;
|
||||
{
|
||||
auto result = absl::c_mismatch(vector_, sequence_);
|
||||
EXPECT_EQ(result.first, std::prev(vector_.end()));
|
||||
EXPECT_EQ(result.second, std::prev(sequence_.end()));
|
||||
}
|
||||
{
|
||||
auto result = absl::c_mismatch(sequence_, vector_);
|
||||
EXPECT_EQ(result.first, std::prev(sequence_.end()));
|
||||
EXPECT_EQ(result.second, std::prev(vector_.end()));
|
||||
}
|
||||
|
||||
sequence_.pop_back();
|
||||
{
|
||||
auto result = absl::c_mismatch(vector_, sequence_);
|
||||
EXPECT_EQ(result.first, std::prev(vector_.end()));
|
||||
EXPECT_EQ(result.second, sequence_.end());
|
||||
}
|
||||
{
|
||||
auto result = absl::c_mismatch(sequence_, vector_);
|
||||
EXPECT_EQ(result.first, sequence_.end());
|
||||
EXPECT_EQ(result.second, std::prev(vector_.end()));
|
||||
}
|
||||
{
|
||||
struct NoNotEquals {
|
||||
constexpr bool operator==(NoNotEquals) const { return true; }
|
||||
constexpr bool operator!=(NoNotEquals) const = delete;
|
||||
};
|
||||
std::vector<NoNotEquals> first;
|
||||
std::list<NoNotEquals> second;
|
||||
|
||||
// Check this still compiles.
|
||||
absl::c_mismatch(first, second);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(NonMutatingTest, MismatchWithPredicate) {
|
||||
absl::c_mismatch(container_, sequence_, BinPredicate);
|
||||
absl::c_mismatch(sequence_, container_, BinPredicate);
|
||||
// Testing necessary as absl::c_mismatch executes logic.
|
||||
{
|
||||
auto result = absl::c_mismatch(vector_, sequence_, BinPredicate);
|
||||
EXPECT_EQ(result.first, vector_.begin());
|
||||
EXPECT_EQ(result.second, sequence_.begin());
|
||||
}
|
||||
{
|
||||
auto result = absl::c_mismatch(sequence_, vector_, BinPredicate);
|
||||
EXPECT_EQ(result.first, sequence_.begin());
|
||||
EXPECT_EQ(result.second, vector_.begin());
|
||||
}
|
||||
|
||||
sequence_.front() = 0;
|
||||
{
|
||||
auto result = absl::c_mismatch(vector_, sequence_, BinPredicate);
|
||||
EXPECT_EQ(result.first, vector_.begin());
|
||||
EXPECT_EQ(result.second, sequence_.begin());
|
||||
}
|
||||
{
|
||||
auto result = absl::c_mismatch(sequence_, vector_, BinPredicate);
|
||||
EXPECT_EQ(result.first, std::next(sequence_.begin()));
|
||||
EXPECT_EQ(result.second, std::next(vector_.begin()));
|
||||
}
|
||||
|
||||
sequence_.clear();
|
||||
{
|
||||
auto result = absl::c_mismatch(vector_, sequence_, BinPredicate);
|
||||
EXPECT_EQ(result.first, vector_.begin());
|
||||
EXPECT_EQ(result.second, sequence_.end());
|
||||
}
|
||||
{
|
||||
auto result = absl::c_mismatch(sequence_, vector_, BinPredicate);
|
||||
EXPECT_EQ(result.first, sequence_.end());
|
||||
EXPECT_EQ(result.second, vector_.begin());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(NonMutatingTest, Equal) {
|
||||
|
|
@ -519,11 +593,9 @@ TEST_F(SortingTest, IsSortedUntil) {
|
|||
TEST_F(SortingTest, NthElement) {
|
||||
std::vector<int> unsorted = {2, 4, 1, 3};
|
||||
absl::c_nth_element(unsorted, unsorted.begin() + 2);
|
||||
EXPECT_THAT(unsorted,
|
||||
ElementsAre(Lt(3), Lt(3), 3, Gt(3)));
|
||||
EXPECT_THAT(unsorted, ElementsAre(Lt(3), Lt(3), 3, Gt(3)));
|
||||
absl::c_nth_element(unsorted, unsorted.begin() + 2, std::greater<int>());
|
||||
EXPECT_THAT(unsorted,
|
||||
ElementsAre(Gt(2), Gt(2), 2, Lt(2)));
|
||||
EXPECT_THAT(unsorted, ElementsAre(Gt(2), Gt(2), 2, Lt(2)));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, IsPartitioned) {
|
||||
|
|
@ -676,6 +748,15 @@ TEST(MutatingTest, SwapRanges) {
|
|||
absl::c_swap_ranges(odds, evens);
|
||||
EXPECT_THAT(odds, ElementsAre(1, 3, 5));
|
||||
EXPECT_THAT(evens, ElementsAre(2, 4, 6));
|
||||
|
||||
odds.pop_back();
|
||||
absl::c_swap_ranges(odds, evens);
|
||||
EXPECT_THAT(odds, ElementsAre(2, 4));
|
||||
EXPECT_THAT(evens, ElementsAre(1, 3, 6));
|
||||
|
||||
absl::c_swap_ranges(evens, odds);
|
||||
EXPECT_THAT(odds, ElementsAre(1, 3));
|
||||
EXPECT_THAT(evens, ElementsAre(2, 4, 6));
|
||||
}
|
||||
|
||||
TEST_F(NonMutatingTest, Transform) {
|
||||
|
|
@ -690,6 +771,20 @@ TEST_F(NonMutatingTest, Transform) {
|
|||
EXPECT_EQ(std::vector<int>({1, 5, 4}), z);
|
||||
*end = 7;
|
||||
EXPECT_EQ(std::vector<int>({1, 5, 4, 7}), z);
|
||||
|
||||
z.clear();
|
||||
y.pop_back();
|
||||
end = absl::c_transform(x, y, std::back_inserter(z), std::plus<int>());
|
||||
EXPECT_EQ(std::vector<int>({1, 5}), z);
|
||||
*end = 7;
|
||||
EXPECT_EQ(std::vector<int>({1, 5, 7}), z);
|
||||
|
||||
z.clear();
|
||||
std::swap(x, y);
|
||||
end = absl::c_transform(x, y, std::back_inserter(z), std::plus<int>());
|
||||
EXPECT_EQ(std::vector<int>({1, 5}), z);
|
||||
*end = 7;
|
||||
EXPECT_EQ(std::vector<int>({1, 5, 7}), z);
|
||||
}
|
||||
|
||||
TEST(MutatingTest, Replace) {
|
||||
|
|
@ -755,10 +850,9 @@ MATCHER_P2(IsElement, key, value, "") {
|
|||
TEST(MutatingTest, StableSort) {
|
||||
std::vector<Element> test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}};
|
||||
absl::c_stable_sort(test_vector);
|
||||
EXPECT_THAT(
|
||||
test_vector,
|
||||
ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1),
|
||||
IsElement(2, 0), IsElement(2, 2)));
|
||||
EXPECT_THAT(test_vector,
|
||||
ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1),
|
||||
IsElement(2, 0), IsElement(2, 2)));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, StableSortWithPredicate) {
|
||||
|
|
@ -766,10 +860,9 @@ TEST(MutatingTest, StableSortWithPredicate) {
|
|||
absl::c_stable_sort(test_vector, [](const Element& e1, const Element& e2) {
|
||||
return e2 < e1;
|
||||
});
|
||||
EXPECT_THAT(
|
||||
test_vector,
|
||||
ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2),
|
||||
IsElement(1, 1), IsElement(1, 0)));
|
||||
EXPECT_THAT(test_vector,
|
||||
ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2),
|
||||
IsElement(1, 1), IsElement(1, 0)));
|
||||
}
|
||||
|
||||
TEST(MutatingTest, ReplaceCopyIf) {
|
||||
|
|
|
|||
|
|
@ -1,304 +0,0 @@
|
|||
# Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//third_party/abseil-cpp/absl.gni")
|
||||
|
||||
absl_source_set("atomic_hook") {
|
||||
public = [ "internal/atomic_hook.h" ]
|
||||
deps = [
|
||||
":config",
|
||||
":core_headers",
|
||||
]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("errno_saver") {
|
||||
public = [ "internal/errno_saver.h" ]
|
||||
deps = [ ":config" ]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("log_severity") {
|
||||
sources = [ "log_severity.cc" ]
|
||||
public = [ "log_severity.h" ]
|
||||
deps = [
|
||||
":config",
|
||||
":core_headers",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("raw_logging_internal") {
|
||||
sources = [ "internal/raw_logging.cc" ]
|
||||
public = [ "internal/raw_logging.h" ]
|
||||
deps = [
|
||||
":atomic_hook",
|
||||
":config",
|
||||
":core_headers",
|
||||
":log_severity",
|
||||
]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("spinlock_wait") {
|
||||
sources = [
|
||||
"internal/spinlock_akaros.inc",
|
||||
"internal/spinlock_linux.inc",
|
||||
"internal/spinlock_posix.inc",
|
||||
"internal/spinlock_wait.cc",
|
||||
"internal/spinlock_win32.inc",
|
||||
]
|
||||
public = [ "internal/spinlock_wait.h" ]
|
||||
deps = [
|
||||
":base_internal",
|
||||
":core_headers",
|
||||
":errno_saver",
|
||||
]
|
||||
visibility = []
|
||||
visibility += [ "../base:*" ]
|
||||
}
|
||||
|
||||
absl_source_set("config") {
|
||||
public = [
|
||||
"config.h",
|
||||
"options.h",
|
||||
"policy_checks.h",
|
||||
]
|
||||
}
|
||||
|
||||
config("clang_support_dynamic_annotations") {
|
||||
cflags_cc = [ "-D__CLANG_SUPPORT_DYN_ANNOTATION__" ]
|
||||
}
|
||||
|
||||
absl_source_set("dynamic_annotations") {
|
||||
public_configs = [ ":clang_support_dynamic_annotations" ]
|
||||
sources = [ "dynamic_annotations.cc" ]
|
||||
public = [ "dynamic_annotations.h" ]
|
||||
|
||||
# Abseil's dynamic annotations are only visible inside Abseil because
|
||||
# their usage is deprecated in Chromium (see README.chromium for more info).
|
||||
visibility = []
|
||||
visibility = [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("core_headers") {
|
||||
public = [
|
||||
"attributes.h",
|
||||
"const_init.h",
|
||||
"macros.h",
|
||||
"optimization.h",
|
||||
"port.h",
|
||||
"thread_annotations.h",
|
||||
]
|
||||
deps = [ ":config" ]
|
||||
}
|
||||
|
||||
absl_source_set("malloc_internal") {
|
||||
sources = [ "internal/low_level_alloc.cc" ]
|
||||
public = [
|
||||
"internal/direct_mmap.h",
|
||||
"internal/low_level_alloc.h",
|
||||
]
|
||||
deps = [
|
||||
":base",
|
||||
":base_internal",
|
||||
":config",
|
||||
":core_headers",
|
||||
":dynamic_annotations",
|
||||
":raw_logging_internal",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("base_internal") {
|
||||
public = [
|
||||
"internal/hide_ptr.h",
|
||||
"internal/identity.h",
|
||||
"internal/inline_variable.h",
|
||||
"internal/invoke.h",
|
||||
"internal/scheduling_mode.h",
|
||||
]
|
||||
deps = [
|
||||
":config",
|
||||
"../meta:type_traits",
|
||||
]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("base") {
|
||||
sources = [
|
||||
"internal/cycleclock.cc",
|
||||
"internal/spinlock.cc",
|
||||
"internal/sysinfo.cc",
|
||||
"internal/thread_identity.cc",
|
||||
"internal/unscaledcycleclock.cc",
|
||||
]
|
||||
public = [
|
||||
"call_once.h",
|
||||
"casts.h",
|
||||
"internal/cycleclock.h",
|
||||
"internal/low_level_scheduling.h",
|
||||
"internal/per_thread_tls.h",
|
||||
"internal/spinlock.h",
|
||||
"internal/sysinfo.h",
|
||||
"internal/thread_identity.h",
|
||||
"internal/tsan_mutex_interface.h",
|
||||
"internal/unscaledcycleclock.h",
|
||||
]
|
||||
|
||||
# TODO(mbonadei): The bazel file has:
|
||||
# "-DEFAULTLIB:advapi32.lib"
|
||||
# understand if this is needed here as well.
|
||||
deps = [
|
||||
":atomic_hook",
|
||||
":base_internal",
|
||||
":config",
|
||||
":core_headers",
|
||||
":dynamic_annotations",
|
||||
":log_severity",
|
||||
":raw_logging_internal",
|
||||
":spinlock_wait",
|
||||
"../meta:type_traits",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("throw_delegate") {
|
||||
sources = [ "internal/throw_delegate.cc" ]
|
||||
public = [ "internal/throw_delegate.h" ]
|
||||
deps = [
|
||||
":config",
|
||||
":raw_logging_internal",
|
||||
]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("exception_testing") {
|
||||
testonly = true
|
||||
public = [ "internal/exception_testing.h" ]
|
||||
deps = [ ":config" ]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("pretty_function") {
|
||||
public = [ "internal/pretty_function.h" ]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
# TODO(mbonadei): This target throws by design. We should probably
|
||||
# just remove it.
|
||||
# source_set("exception_safety_testing") {
|
||||
# testonly = true
|
||||
# configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
# configs += [
|
||||
# "//build/config/compiler:no_chromium_code",
|
||||
# "//third_party/abseil-cpp:absl_test_cflags_cc",
|
||||
# ]
|
||||
# public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
|
||||
# sources = [
|
||||
# "internal/exception_safety_testing.cc",
|
||||
# ]
|
||||
# public = [
|
||||
# "internal/exception_safety_testing.h",
|
||||
# ]
|
||||
# deps = [
|
||||
# ":config",
|
||||
# ":pretty_function",
|
||||
# "../memory",
|
||||
# "../meta:type_traits",
|
||||
# "../strings",
|
||||
# "../utility",
|
||||
# "//testing/gtest",
|
||||
# ]
|
||||
# }
|
||||
|
||||
absl_source_set("spinlock_test_common") {
|
||||
testonly = true
|
||||
sources = [ "spinlock_test_common.cc" ]
|
||||
deps = [
|
||||
":base",
|
||||
":base_internal",
|
||||
":core_headers",
|
||||
"../synchronization",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("endian") {
|
||||
public = [
|
||||
"internal/endian.h",
|
||||
"internal/unaligned_access.h",
|
||||
]
|
||||
deps = [
|
||||
":config",
|
||||
":core_headers",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("bits") {
|
||||
public = [ "internal/bits.h" ]
|
||||
deps = [
|
||||
":config",
|
||||
":core_headers",
|
||||
]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("exponential_biased") {
|
||||
sources = [ "internal/exponential_biased.cc" ]
|
||||
public = [ "internal/exponential_biased.h" ]
|
||||
deps = [
|
||||
":config",
|
||||
":core_headers",
|
||||
]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("periodic_sampler") {
|
||||
sources = [ "internal/periodic_sampler.cc" ]
|
||||
public = [ "internal/periodic_sampler.h" ]
|
||||
deps = [
|
||||
":core_headers",
|
||||
":exponential_biased",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("scoped_set_env") {
|
||||
testonly = true
|
||||
public = [ "internal/scoped_set_env.h" ]
|
||||
sources = [ "internal/scoped_set_env.cc" ]
|
||||
deps = [
|
||||
":config",
|
||||
":raw_logging_internal",
|
||||
]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("strerror") {
|
||||
sources = ["internal/strerror.cc"]
|
||||
public = ["internal/strerror.h"]
|
||||
deps = [
|
||||
":config",
|
||||
":core_headers",
|
||||
":errno_saver",
|
||||
]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("fast_type_id") {
|
||||
public = ["internal/fast_type_id.h"]
|
||||
deps = [
|
||||
":config",
|
||||
]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
|
@ -105,11 +105,11 @@ absl_cc_library(
|
|||
HDRS
|
||||
"dynamic_annotations.h"
|
||||
SRCS
|
||||
"dynamic_annotations.cc"
|
||||
"internal/dynamic_annotations.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEFINES
|
||||
"__CLANG_SUPPORT_DYN_ANNOTATION__"
|
||||
DEPS
|
||||
absl::config
|
||||
PUBLIC
|
||||
)
|
||||
|
||||
|
|
@ -191,7 +191,7 @@ absl_cc_library(
|
|||
${ABSL_DEFAULT_COPTS}
|
||||
LINKOPTS
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
$<$<BOOL:${LIBRT}>:${LIBRT}>
|
||||
$<$<BOOL:${LIBRT}>:-lrt>
|
||||
$<$<BOOL:${MINGW}>:"advapi32">
|
||||
DEPS
|
||||
absl::atomic_hook
|
||||
|
|
@ -230,7 +230,7 @@ absl_cc_library(
|
|||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
gtest
|
||||
GTest::gtest
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
|
@ -259,7 +259,7 @@ absl_cc_library(
|
|||
absl::meta
|
||||
absl::strings
|
||||
absl::utility
|
||||
gtest
|
||||
GTest::gtest
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
|
@ -273,7 +273,7 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::exception_safety_testing
|
||||
absl::memory
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -300,8 +300,8 @@ absl_cc_test(
|
|||
absl::atomic_hook_test_helper
|
||||
absl::atomic_hook
|
||||
absl::core_headers
|
||||
gmock
|
||||
gtest_main
|
||||
GTest::gmock
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -314,7 +314,7 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::base
|
||||
absl::core_headers
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -327,8 +327,8 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::errno_saver
|
||||
absl::strerror
|
||||
gmock
|
||||
gtest_main
|
||||
GTest::gmock
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -342,7 +342,7 @@ absl_cc_test(
|
|||
absl::base
|
||||
absl::config
|
||||
absl::throw_delegate
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -357,7 +357,7 @@ absl_cc_test(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::base_internal
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -371,8 +371,8 @@ absl_cc_test(
|
|||
absl::base_internal
|
||||
absl::memory
|
||||
absl::strings
|
||||
gmock
|
||||
gtest_main
|
||||
GTest::gmock
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -384,10 +384,11 @@ absl_cc_library(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::base
|
||||
absl::config
|
||||
absl::base_internal
|
||||
absl::core_headers
|
||||
absl::synchronization
|
||||
gtest
|
||||
GTest::gtest
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
|
@ -402,9 +403,10 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::base
|
||||
absl::base_internal
|
||||
absl::config
|
||||
absl::core_headers
|
||||
absl::synchronization
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -416,6 +418,7 @@ absl_cc_library(
|
|||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::base
|
||||
absl::config
|
||||
absl::core_headers
|
||||
PUBLIC
|
||||
|
|
@ -432,7 +435,7 @@ absl_cc_test(
|
|||
absl::base
|
||||
absl::config
|
||||
absl::endian
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -445,7 +448,7 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::config
|
||||
absl::synchronization
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -459,7 +462,7 @@ absl_cc_test(
|
|||
absl::base
|
||||
absl::core_headers
|
||||
absl::synchronization
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -472,7 +475,7 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::raw_logging_internal
|
||||
absl::strings
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -485,7 +488,7 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::base
|
||||
absl::synchronization
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -497,6 +500,7 @@ absl_cc_test(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::malloc_internal
|
||||
absl::node_hash_map
|
||||
Threads::Threads
|
||||
)
|
||||
|
||||
|
|
@ -512,31 +516,7 @@ absl_cc_test(
|
|||
absl::core_headers
|
||||
absl::synchronization
|
||||
Threads::Threads
|
||||
gtest_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
bits
|
||||
HDRS
|
||||
"internal/bits.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
absl::core_headers
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
bits_test
|
||||
SRCS
|
||||
"internal/bits_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::bits
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -563,7 +543,7 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::exponential_biased
|
||||
absl::strings
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -590,7 +570,7 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::core_headers
|
||||
absl::periodic_sampler
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -616,7 +596,7 @@ absl_cc_test(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::scoped_set_env
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -640,8 +620,8 @@ absl_cc_test(
|
|||
absl::flags_marshalling
|
||||
absl::log_severity
|
||||
absl::strings
|
||||
gmock
|
||||
gtest_main
|
||||
GTest::gmock
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -671,8 +651,8 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::strerror
|
||||
absl::strings
|
||||
gmock
|
||||
gtest_main
|
||||
GTest::gmock
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -697,5 +677,18 @@ absl_cc_test(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::fast_type_id
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
optimization_test
|
||||
SRCS
|
||||
"optimization_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::core_headers
|
||||
absl::optional
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@
|
|||
// These macros are used within Abseil and allow the compiler to optimize, where
|
||||
// applicable, certain function calls.
|
||||
//
|
||||
// This file is used for both C and C++!
|
||||
//
|
||||
// Most macros here are exposing GCC or Clang features, and are stubbed out for
|
||||
// other compilers.
|
||||
//
|
||||
|
|
@ -32,34 +30,12 @@
|
|||
// 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).
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// Sanitizer Attributes
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Sanitizer-related attributes are not "defined" in this file (and indeed
|
||||
// are not defined as such in any file). To utilize the following
|
||||
// sanitizer-related attributes within your builds, define the following macros
|
||||
// within your build using a `-D` flag, along with the given value for
|
||||
// `-fsanitize`:
|
||||
//
|
||||
// * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8)
|
||||
// * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only)
|
||||
// * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+)
|
||||
// * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+)
|
||||
// * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only)
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Enable branches in the Abseil code that are tagged for ASan:
|
||||
// $ bazel build --copt=-DADDRESS_SANITIZER --copt=-fsanitize=address
|
||||
// --linkopt=-fsanitize=address *target*
|
||||
//
|
||||
// Since these macro names are only supported by GCC and Clang, we only check
|
||||
// for `__GNUC__` (GCC or Clang) and the above macros.
|
||||
|
||||
#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
|
||||
|
|
@ -143,7 +119,7 @@
|
|||
#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__)
|
||||
#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")))
|
||||
|
|
@ -155,14 +131,14 @@
|
|||
// ABSL_ATTRIBUTE_WEAK
|
||||
//
|
||||
// Tags a function as weak for the purposes of compilation and linking.
|
||||
// Weak attributes currently do not work properly in LLVM's Windows backend,
|
||||
// so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
|
||||
// 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(__llvm__) && defined(_WIN32)) && !defined(__MINGW32__)
|
||||
(!defined(_WIN32) || __clang_major__ < 9) && !defined(__MINGW32__)
|
||||
#undef ABSL_ATTRIBUTE_WEAK
|
||||
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
|
||||
#define ABSL_HAVE_ATTRIBUTE_WEAK 1
|
||||
|
|
@ -234,7 +210,7 @@
|
|||
// 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 defined(__GNUC__)
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_address)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||
|
|
@ -242,13 +218,13 @@
|
|||
|
||||
// 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 ADDRESS_SANITIZER attribute above, but deals
|
||||
// with initialized-ness rather than addressability issues.
|
||||
// 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 defined(__clang__)
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
|
||||
|
|
@ -259,7 +235,7 @@
|
|||
// 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 defined(__GNUC__)
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
|
||||
|
|
@ -271,8 +247,10 @@
|
|||
// 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 defined(__GNUC__) && \
|
||||
(defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER))
|
||||
#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
|
||||
|
|
@ -283,7 +261,7 @@
|
|||
//
|
||||
// Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
|
||||
// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
|
||||
#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY)
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
|
||||
|
|
@ -293,7 +271,7 @@
|
|||
//
|
||||
// Tells the SafeStack to not instrument a given function.
|
||||
// See https://clang.llvm.org/docs/SafeStack.html for details.
|
||||
#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER)
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
|
||||
__attribute__((no_sanitize("safe-stack")))
|
||||
#else
|
||||
|
|
@ -303,10 +281,7 @@
|
|||
// ABSL_ATTRIBUTE_RETURNS_NONNULL
|
||||
//
|
||||
// Tells the compiler that a particular function never returns a null pointer.
|
||||
#if ABSL_HAVE_ATTRIBUTE(returns_nonnull) || \
|
||||
(defined(__GNUC__) && \
|
||||
(__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \
|
||||
!defined(__clang__))
|
||||
#if ABSL_HAVE_ATTRIBUTE(returns_nonnull)
|
||||
#define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_RETURNS_NONNULL
|
||||
|
|
@ -546,6 +521,13 @@
|
|||
// 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__))
|
||||
|
|
@ -566,13 +548,19 @@
|
|||
// ABSL_ATTRIBUTE_PACKED
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
|
|
@ -594,6 +582,79 @@
|
|||
#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).
|
||||
//
|
||||
// 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();
|
||||
//
|
||||
// Every usage of a deprecated entity will trigger a warning when compiled with
|
||||
// clang's `-Wdeprecated-declarations` option. This option is turned off by
|
||||
// default, but the warnings will be reported by clang-tidy.
|
||||
#if defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L
|
||||
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||
#endif
|
||||
|
||||
#ifndef ABSL_DEPRECATED
|
||||
#define ABSL_DEPRECATED(message)
|
||||
#endif
|
||||
|
||||
// ABSL_CONST_INIT
|
||||
//
|
||||
// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
|
||||
|
|
@ -620,4 +681,47 @@
|
|||
#define ABSL_CONST_INIT
|
||||
#endif // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
|
||||
|
||||
// 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_
|
||||
|
|
|
|||
|
|
@ -175,17 +175,10 @@ void CallOnceImpl(std::atomic<uint32_t>* control,
|
|||
std::memory_order_relaxed) ||
|
||||
base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
|
||||
scheduling_mode) == kOnceInit) {
|
||||
base_internal::Invoke(std::forward<Callable>(fn),
|
||||
base_internal::invoke(std::forward<Callable>(fn),
|
||||
std::forward<Args>(args)...);
|
||||
// The call to SpinLockWake below is an optimization, because the waiter
|
||||
// in SpinLockWait is waiting with a short timeout. The atomic load/store
|
||||
// sequence is slightly faster than an atomic exchange:
|
||||
// old_control = control->exchange(base_internal::kOnceDone,
|
||||
// std::memory_order_release);
|
||||
// We opt for a slightly faster case when there are no waiters, in spite
|
||||
// of longer tail latency when there are waiters.
|
||||
old_control = control->load(std::memory_order_relaxed);
|
||||
control->store(base_internal::kOnceDone, std::memory_order_release);
|
||||
old_control =
|
||||
control->exchange(base_internal::kOnceDone, std::memory_order_release);
|
||||
if (old_control == base_internal::kOnceWaiter) {
|
||||
base_internal::SpinLockWake(control, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,16 +159,19 @@ inline Dest bit_cast(const Source& source) {
|
|||
return dest;
|
||||
}
|
||||
|
||||
// NOTE: This overload is only picked if the requirements of bit_cast are not
|
||||
// met. It is therefore UB, but is provided temporarily as previous versions of
|
||||
// this function template were unchecked. Do not use this in new code.
|
||||
// NOTE: This overload is only picked if the requirements of bit_cast are
|
||||
// not met. It is therefore UB, but is provided temporarily as previous
|
||||
// versions of this function template were unchecked. Do not use this in
|
||||
// new code.
|
||||
template <
|
||||
typename Dest, typename Source,
|
||||
typename std::enable_if<
|
||||
!internal_casts::is_bitcastable<Dest, Source>::value, int>::type = 0>
|
||||
!internal_casts::is_bitcastable<Dest, Source>::value,
|
||||
int>::type = 0>
|
||||
ABSL_DEPRECATED(
|
||||
"absl::bit_cast type requirements were violated. Update the types being "
|
||||
"used such that they are the same size and are both TriviallyCopyable.")
|
||||
"absl::bit_cast type requirements were violated. Update the types "
|
||||
"being used such that they are the same size and are both "
|
||||
"TriviallyCopyable.")
|
||||
inline Dest bit_cast(const Source& source) {
|
||||
static_assert(sizeof(Dest) == sizeof(Source),
|
||||
"Source and destination types should have equal sizes.");
|
||||
|
|
|
|||
|
|
@ -66,6 +66,35 @@
|
|||
#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.
|
||||
#undef ABSL_LTS_RELEASE_VERSION
|
||||
#undef ABSL_LTS_RELEASE_PATCH_LEVEL
|
||||
|
||||
// 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)
|
||||
|
|
@ -121,10 +150,16 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
#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
|
||||
|
|
@ -154,6 +189,28 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
#define ABSL_INTERNAL_HAS_KEYWORD(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 when compiled with Clang or compiled
|
||||
// against libstdc++ with _GLIBCXX_HAVE_TLS defined.
|
||||
|
|
@ -171,10 +228,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
// 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(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && \
|
||||
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
|
||||
defined(_MSC_VER)
|
||||
#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
|
||||
|
||||
|
|
@ -193,10 +249,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
#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__) && defined(__GNUC__) && \
|
||||
(__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 4)) && \
|
||||
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \
|
||||
#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \
|
||||
(!defined(__clang__) && ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(7, 4) && \
|
||||
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \
|
||||
(defined(_MSC_VER) && !defined(__NVCC__))
|
||||
#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
|
||||
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
|
||||
|
|
@ -210,6 +265,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
#if ABSL_INTERNAL_HAS_KEYWORD(__builtin_LINE) && \
|
||||
ABSL_INTERNAL_HAS_KEYWORD(__builtin_FILE)
|
||||
#define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1
|
||||
#elif ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(5, 0)
|
||||
#define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
@ -226,11 +283,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
// * 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 __has_feature unreliable there.
|
||||
// making ABSL_HAVE_FEATURE unreliable there.
|
||||
//
|
||||
// Otherwise, `__has_feature` is only supported by Clang so it has be inside
|
||||
// `defined(__APPLE__)` check.
|
||||
#if __has_feature(cxx_thread_local) && \
|
||||
#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
|
||||
|
|
@ -307,25 +362,21 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
// For further details, consult the compiler's documentation.
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
#error ABSL_HAVE_EXCEPTIONS cannot be directly set.
|
||||
|
||||
#elif defined(__clang__)
|
||||
|
||||
#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
|
||||
#elif ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(3, 6)
|
||||
// Clang >= 3.6
|
||||
#if __has_feature(cxx_exceptions)
|
||||
#if ABSL_HAVE_FEATURE(cxx_exceptions)
|
||||
#define ABSL_HAVE_EXCEPTIONS 1
|
||||
#endif // __has_feature(cxx_exceptions)
|
||||
#else
|
||||
#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) && __has_feature(cxx_exceptions)
|
||||
#if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
|
||||
#define ABSL_HAVE_EXCEPTIONS 1
|
||||
#endif // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
|
||||
#endif // __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
|
||||
|
||||
#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)) && \
|
||||
!(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \
|
||||
#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
|
||||
|
|
@ -360,7 +411,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
|
||||
defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
|
||||
defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \
|
||||
defined(__ASYLO__)
|
||||
defined(__ASYLO__) || defined(__myriad2__)
|
||||
#define ABSL_HAVE_MMAP 1
|
||||
#endif
|
||||
|
||||
|
|
@ -375,6 +426,15 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
#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
|
||||
|
|
@ -470,9 +530,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
(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__ < 120000) || \
|
||||
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
|
||||
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
|
||||
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 50000))
|
||||
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))
|
||||
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
|
||||
#else
|
||||
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
|
||||
|
|
@ -486,7 +546,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<any>) && __cplusplus >= 201703L && \
|
||||
#if __has_include(<any>) && defined(__cplusplus) && __cplusplus >= 201703L && \
|
||||
!ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
|
||||
#define ABSL_HAVE_STD_ANY 1
|
||||
#endif
|
||||
|
|
@ -500,8 +560,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<optional>) && __cplusplus >= 201703L && \
|
||||
!ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
|
||||
#if __has_include(<optional>) && defined(__cplusplus) && \
|
||||
__cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
|
||||
#define ABSL_HAVE_STD_OPTIONAL 1
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -514,8 +574,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<variant>) && __cplusplus >= 201703L && \
|
||||
!ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
|
||||
#if __has_include(<variant>) && defined(__cplusplus) && \
|
||||
__cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
|
||||
#define ABSL_HAVE_STD_VARIANT 1
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -528,7 +588,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<string_view>) && __cplusplus >= 201703L
|
||||
#if __has_include(<string_view>) && defined(__cplusplus) && \
|
||||
__cplusplus >= 201703L
|
||||
#define ABSL_HAVE_STD_STRING_VIEW 1
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -540,8 +601,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
// 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) || __cplusplus > 201402)
|
||||
#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
|
||||
|
|
@ -661,4 +723,47 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
|||
#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(__SANITIZE_MEMORY__)
|
||||
#define ABSL_HAVE_MEMORY_SANITIZER 1
|
||||
#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_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
|
||||
|
||||
#endif // ABSL_BASE_CONFIG_H_
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "absl/base/dynamic_annotations.h"
|
||||
|
||||
#ifndef __has_feature
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
/* Compiler-based ThreadSanitizer defines
|
||||
ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
|
||||
and provides its own definitions of the functions. */
|
||||
|
||||
#ifndef ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL
|
||||
# define ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0
|
||||
#endif
|
||||
|
||||
/* Each function is empty and called (via a macro) only in debug mode.
|
||||
The arguments are captured by dynamic tools at runtime. */
|
||||
|
||||
#if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__)
|
||||
|
||||
#if __has_feature(memory_sanitizer)
|
||||
#include <sanitizer/msan_interface.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void AbslAnnotateRWLockCreate(const char *, int,
|
||||
const volatile void *){}
|
||||
void AbslAnnotateRWLockDestroy(const char *, int,
|
||||
const volatile void *){}
|
||||
void AbslAnnotateRWLockAcquired(const char *, int,
|
||||
const volatile void *, long){}
|
||||
void AbslAnnotateRWLockReleased(const char *, int,
|
||||
const volatile void *, long){}
|
||||
void AbslAnnotateBenignRace(const char *, int,
|
||||
const volatile void *,
|
||||
const char *){}
|
||||
void AbslAnnotateBenignRaceSized(const char *, int,
|
||||
const volatile void *,
|
||||
size_t,
|
||||
const char *) {}
|
||||
void AbslAnnotateThreadName(const char *, int,
|
||||
const char *){}
|
||||
void AbslAnnotateIgnoreReadsBegin(const char *, int){}
|
||||
void AbslAnnotateIgnoreReadsEnd(const char *, int){}
|
||||
void AbslAnnotateIgnoreWritesBegin(const char *, int){}
|
||||
void AbslAnnotateIgnoreWritesEnd(const char *, int){}
|
||||
void AbslAnnotateEnableRaceDetection(const char *, int, int){}
|
||||
void AbslAnnotateMemoryIsInitialized(const char *, int,
|
||||
const volatile void *mem, size_t size) {
|
||||
#if __has_feature(memory_sanitizer)
|
||||
__msan_unpoison(mem, size);
|
||||
#else
|
||||
(void)mem;
|
||||
(void)size;
|
||||
#endif
|
||||
}
|
||||
|
||||
void AbslAnnotateMemoryIsUninitialized(const char *, int,
|
||||
const volatile void *mem, size_t size) {
|
||||
#if __has_feature(memory_sanitizer)
|
||||
__msan_allocated_memory(mem, size);
|
||||
#else
|
||||
(void)mem;
|
||||
(void)size;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int AbslGetRunningOnValgrind(void) {
|
||||
#ifdef RUNNING_ON_VALGRIND
|
||||
if (RUNNING_ON_VALGRIND) return 1;
|
||||
#endif
|
||||
char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND");
|
||||
if (running_on_valgrind_str) {
|
||||
return strcmp(running_on_valgrind_str, "0") != 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* See the comments in dynamic_annotations.h */
|
||||
int AbslRunningOnValgrind(void) {
|
||||
static volatile int running_on_valgrind = -1;
|
||||
int local_running_on_valgrind = running_on_valgrind;
|
||||
/* C doesn't have thread-safe initialization of statics, and we
|
||||
don't want to depend on pthread_once here, so hack it. */
|
||||
ABSL_ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack");
|
||||
if (local_running_on_valgrind == -1)
|
||||
running_on_valgrind = local_running_on_valgrind = AbslGetRunningOnValgrind();
|
||||
return local_running_on_valgrind;
|
||||
}
|
||||
|
||||
/* See the comments in dynamic_annotations.h */
|
||||
double AbslValgrindSlowdown(void) {
|
||||
/* Same initialization hack as in AbslRunningOnValgrind(). */
|
||||
static volatile double slowdown = 0.0;
|
||||
double local_slowdown = slowdown;
|
||||
ABSL_ANNOTATE_BENIGN_RACE(&slowdown, "safe hack");
|
||||
if (AbslRunningOnValgrind() == 0) {
|
||||
return 1.0;
|
||||
}
|
||||
if (local_slowdown == 0.0) {
|
||||
char *env = getenv("VALGRIND_SLOWDOWN");
|
||||
slowdown = local_slowdown = env ? atof(env) : 50.0;
|
||||
}
|
||||
return local_slowdown;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#endif /* ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
|
||||
|
|
@ -1,389 +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.
|
||||
// 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.
|
||||
|
||||
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. */
|
||||
// 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_
|
||||
|
||||
#ifndef ABSL_DYNAMIC_ANNOTATIONS_ENABLED
|
||||
# define ABSL_DYNAMIC_ANNOTATIONS_ENABLED 0
|
||||
#endif
|
||||
|
||||
#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0
|
||||
|
||||
/* -------------------------------------------------------------
|
||||
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) \
|
||||
AbslAnnotateBenignRaceSized(__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) \
|
||||
AbslAnnotateBenignRaceSized(__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) \
|
||||
AbslAnnotateEnableRaceDetection(__FILE__, __LINE__, enable)
|
||||
|
||||
/* -------------------------------------------------------------
|
||||
Annotations useful for debugging. */
|
||||
|
||||
/* Report the current thread name to a race detector. */
|
||||
#define ABSL_ANNOTATE_THREAD_NAME(name) \
|
||||
AbslAnnotateThreadName(__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) \
|
||||
AbslAnnotateRWLockCreate(__FILE__, __LINE__, lock)
|
||||
|
||||
/* Report that a linker initialized lock has been created at address "lock".
|
||||
*/
|
||||
#ifdef THREAD_SANITIZER
|
||||
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
|
||||
AbslAnnotateRWLockCreateStatic(__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) \
|
||||
AbslAnnotateRWLockDestroy(__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) \
|
||||
AbslAnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w)
|
||||
|
||||
/* Report that the lock at address "lock" is about to be released. */
|
||||
#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
|
||||
AbslAnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w)
|
||||
|
||||
#else /* ABSL_DYNAMIC_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 */
|
||||
|
||||
#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */
|
||||
|
||||
/* These annotations are also made available to LLVM's Memory Sanitizer */
|
||||
#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 1 || defined(MEMORY_SANITIZER)
|
||||
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
|
||||
AbslAnnotateMemoryIsInitialized(__FILE__, __LINE__, address, size)
|
||||
|
||||
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
|
||||
AbslAnnotateMemoryIsUninitialized(__FILE__, __LINE__, address, size)
|
||||
#else
|
||||
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */
|
||||
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */
|
||||
#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */
|
||||
|
||||
/* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the
|
||||
appropriate feature ID. */
|
||||
#if defined(__clang__) && (!defined(SWIG)) \
|
||||
&& defined(__CLANG_SUPPORT_DYN_ANNOTATION__)
|
||||
|
||||
#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0
|
||||
#define ABSL_ANNOTALYSIS_ENABLED
|
||||
#endif
|
||||
|
||||
/* When running in opt-mode, GCC will issue a warning, if these attributes are
|
||||
compiled. Only include them when compiling using Clang. */
|
||||
#define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN \
|
||||
__attribute((exclusive_lock_function("*")))
|
||||
#define ABSL_ATTRIBUTE_IGNORE_READS_END \
|
||||
__attribute((unlock_function("*")))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN /* empty */
|
||||
#define ABSL_ATTRIBUTE_IGNORE_READS_END /* empty */
|
||||
#endif /* defined(__clang__) && ... */
|
||||
|
||||
#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0) || defined(ABSL_ANNOTALYSIS_ENABLED)
|
||||
#define ABSL_ANNOTATIONS_ENABLED
|
||||
#endif
|
||||
|
||||
#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0)
|
||||
|
||||
/* 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() \
|
||||
AbslAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
|
||||
|
||||
/* Stop ignoring reads. */
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_END() \
|
||||
AbslAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
|
||||
|
||||
/* Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. */
|
||||
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
|
||||
AbslAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
|
||||
|
||||
/* Stop ignoring writes. */
|
||||
#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
|
||||
AbslAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
|
||||
|
||||
/* 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. */
|
||||
#elif defined(ABSL_ANNOTALYSIS_ENABLED)
|
||||
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
|
||||
AbslStaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
|
||||
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_END() \
|
||||
AbslStaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
|
||||
|
||||
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
|
||||
AbslStaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
|
||||
|
||||
#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
|
||||
AbslStaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
|
||||
|
||||
#else
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() /* empty */
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_END() /* empty */
|
||||
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */
|
||||
#define ABSL_ANNOTATE_IGNORE_WRITES_END() /* empty */
|
||||
#endif
|
||||
|
||||
/* Implement the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
|
||||
primitive annotations defined above. */
|
||||
#if defined(ABSL_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)
|
||||
|
||||
#else
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */
|
||||
#endif
|
||||
|
||||
/* Use the macros above rather than using these functions directly. */
|
||||
#include <stddef.h>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void AbslAnnotateRWLockCreate(const char *file, int line,
|
||||
const volatile void *lock);
|
||||
void AbslAnnotateRWLockCreateStatic(const char *file, int line,
|
||||
const volatile void *lock);
|
||||
void AbslAnnotateRWLockDestroy(const char *file, int line,
|
||||
const volatile void *lock);
|
||||
void AbslAnnotateRWLockAcquired(const char *file, int line,
|
||||
const volatile void *lock, long is_w); /* NOLINT */
|
||||
void AbslAnnotateRWLockReleased(const char *file, int line,
|
||||
const volatile void *lock, long is_w); /* NOLINT */
|
||||
void AbslAnnotateBenignRace(const char *file, int line,
|
||||
const volatile void *address,
|
||||
const char *description);
|
||||
void AbslAnnotateBenignRaceSized(const char *file, int line,
|
||||
const volatile void *address,
|
||||
size_t size,
|
||||
const char *description);
|
||||
void AbslAnnotateThreadName(const char *file, int line,
|
||||
const char *name);
|
||||
void AbslAnnotateEnableRaceDetection(const char *file, int line, int enable);
|
||||
void AbslAnnotateMemoryIsInitialized(const char *file, int line,
|
||||
const volatile void *mem, size_t size);
|
||||
void AbslAnnotateMemoryIsUninitialized(const char *file, int line,
|
||||
const volatile void *mem, size_t size);
|
||||
|
||||
/* Annotations expand to these functions, when Dynamic Annotations are enabled.
|
||||
These functions are either implemented as no-op calls, if no Sanitizer is
|
||||
attached, or provided with externally-linked implementations by a library
|
||||
like ThreadSanitizer. */
|
||||
void AbslAnnotateIgnoreReadsBegin(const char *file, int line)
|
||||
ABSL_ATTRIBUTE_IGNORE_READS_BEGIN;
|
||||
void AbslAnnotateIgnoreReadsEnd(const char *file, int line)
|
||||
ABSL_ATTRIBUTE_IGNORE_READS_END;
|
||||
void AbslAnnotateIgnoreWritesBegin(const char *file, int line);
|
||||
void AbslAnnotateIgnoreWritesEnd(const char *file, int line);
|
||||
|
||||
#if defined(ABSL_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. */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
static inline void AbslStaticAnnotateIgnoreReadsBegin(const char *file, int line)
|
||||
ABSL_ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; }
|
||||
static inline void AbslStaticAnnotateIgnoreReadsEnd(const char *file, int line)
|
||||
ABSL_ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; }
|
||||
static inline void AbslStaticAnnotateIgnoreWritesBegin(
|
||||
const char *file, int line) { (void)file; (void)line; }
|
||||
static inline void AbslStaticAnnotateIgnoreWritesEnd(
|
||||
const char *file, int line) { (void)file; (void)line; }
|
||||
#pragma GCC diagnostic pop
|
||||
#include "absl/base/macros.h"
|
||||
#endif
|
||||
|
||||
/* Return non-zero value if running under valgrind.
|
||||
// TODO(rogeeff): Remove after the backward compatibility period.
|
||||
#include "absl/base/internal/dynamic_annotations.h" // IWYU pragma: export
|
||||
|
||||
If "valgrind.h" is included into dynamic_annotations.cc,
|
||||
the regular valgrind mechanism will be used.
|
||||
See http://valgrind.org/docs/manual/manual-core-adv.html about
|
||||
RUNNING_ON_VALGRIND and other valgrind "client requests".
|
||||
The file "valgrind.h" may be obtained by doing
|
||||
svn co svn://svn.valgrind.org/valgrind/trunk/include
|
||||
// -------------------------------------------------------------------------
|
||||
// Decide which features are enabled.
|
||||
|
||||
If for some reason you can't use "valgrind.h" or want to fake valgrind,
|
||||
there are two ways to make this function return non-zero:
|
||||
- Use environment variable: export RUNNING_ON_VALGRIND=1
|
||||
- Make your tool intercept the function AbslRunningOnValgrind() and
|
||||
change its return value.
|
||||
*/
|
||||
int AbslRunningOnValgrind(void);
|
||||
#ifdef ABSL_HAVE_THREAD_SANITIZER
|
||||
|
||||
/* AbslValgrindSlowdown returns:
|
||||
* 1.0, if (AbslRunningOnValgrind() == 0)
|
||||
* 50.0, if (AbslRunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL)
|
||||
* atof(getenv("VALGRIND_SLOWDOWN")) otherwise
|
||||
This function can be used to scale timeout values:
|
||||
EXAMPLE:
|
||||
for (;;) {
|
||||
DoExpensiveBackgroundTask();
|
||||
SleepForSeconds(5 * AbslValgrindSlowdown());
|
||||
}
|
||||
*/
|
||||
double AbslValgrindSlowdown(void);
|
||||
#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
|
||||
|
||||
/* ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
|
||||
// -------------------------------------------------------------------------
|
||||
// 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 {
|
||||
|
||||
Instead of doing
|
||||
ABSL_ANNOTATE_IGNORE_READS_BEGIN();
|
||||
... = x;
|
||||
ABSL_ANNOTATE_IGNORE_READS_END();
|
||||
one can use
|
||||
... = ABSL_ANNOTATE_UNPROTECTED_READ(x); */
|
||||
#if defined(__cplusplus) && defined(ABSL_ANNOTATIONS_ENABLED)
|
||||
template <typename T>
|
||||
inline T ABSL_ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */
|
||||
inline T AnnotateUnprotectedRead(const volatile T& x) { // NOLINT
|
||||
ABSL_ANNOTATE_IGNORE_READS_BEGIN();
|
||||
T res = x;
|
||||
ABSL_ANNOTATE_IGNORE_READS_END();
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
#endif
|
||||
|
||||
#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
|
||||
/* Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
|
||||
#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
|
||||
#else /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 */
|
||||
#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */
|
||||
#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */
|
||||
#else
|
||||
|
||||
#ifdef 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. */
|
||||
#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 { char x[8] __attribute__ ((aligned (8))); } name
|
||||
#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)
|
||||
|
||||
#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) // empty
|
||||
#define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
|
||||
#endif // ADDRESS_SANITIZER
|
||||
|
||||
/* Undefine the macros intended only in this file. */
|
||||
#undef ABSL_ANNOTALYSIS_ENABLED
|
||||
#undef ABSL_ANNOTATIONS_ENABLED
|
||||
#undef ABSL_ATTRIBUTE_IGNORE_READS_BEGIN
|
||||
#undef ABSL_ATTRIBUTE_IGNORE_READS_END
|
||||
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||
|
||||
#endif /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */
|
||||
// -------------------------------------------------------------------------
|
||||
// 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_
|
||||
|
|
|
|||
|
|
@ -1,218 +0,0 @@
|
|||
// 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_BITS_H_
|
||||
#define ABSL_BASE_INTERNAL_BITS_H_
|
||||
|
||||
// This file contains bitwise ops which are implementation details of various
|
||||
// absl libraries.
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// Clang on Windows has __builtin_clzll; otherwise we need to use the
|
||||
// windows intrinsic functions.
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#include <intrin.h>
|
||||
#if defined(_M_X64)
|
||||
#pragma intrinsic(_BitScanReverse64)
|
||||
#pragma intrinsic(_BitScanForward64)
|
||||
#endif
|
||||
#pragma intrinsic(_BitScanReverse)
|
||||
#pragma intrinsic(_BitScanForward)
|
||||
#endif
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
// We can achieve something similar to attribute((always_inline)) with MSVC by
|
||||
// using the __forceinline keyword, however this is not perfect. MSVC is
|
||||
// much less aggressive about inlining, and even with the __forceinline keyword.
|
||||
#define ABSL_BASE_INTERNAL_FORCEINLINE __forceinline
|
||||
#else
|
||||
// Use default attribute inline.
|
||||
#define ABSL_BASE_INTERNAL_FORCEINLINE inline ABSL_ATTRIBUTE_ALWAYS_INLINE
|
||||
#endif
|
||||
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) {
|
||||
int zeroes = 60;
|
||||
if (n >> 32) {
|
||||
zeroes -= 32;
|
||||
n >>= 32;
|
||||
}
|
||||
if (n >> 16) {
|
||||
zeroes -= 16;
|
||||
n >>= 16;
|
||||
}
|
||||
if (n >> 8) {
|
||||
zeroes -= 8;
|
||||
n >>= 8;
|
||||
}
|
||||
if (n >> 4) {
|
||||
zeroes -= 4;
|
||||
n >>= 4;
|
||||
}
|
||||
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
|
||||
}
|
||||
|
||||
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
|
||||
#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
|
||||
// MSVC does not have __buitin_clzll. Use _BitScanReverse64.
|
||||
unsigned long result = 0; // NOLINT(runtime/int)
|
||||
if (_BitScanReverse64(&result, n)) {
|
||||
return 63 - result;
|
||||
}
|
||||
return 64;
|
||||
#elif defined(_MSC_VER) && !defined(__clang__)
|
||||
// MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
|
||||
unsigned long result = 0; // NOLINT(runtime/int)
|
||||
if ((n >> 32) && _BitScanReverse(&result, n >> 32)) {
|
||||
return 31 - result;
|
||||
}
|
||||
if (_BitScanReverse(&result, n)) {
|
||||
return 63 - result;
|
||||
}
|
||||
return 64;
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
// Use __builtin_clzll, which uses the following instructions:
|
||||
// x86: bsr
|
||||
// ARM64: clz
|
||||
// PPC: cntlzd
|
||||
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
|
||||
"__builtin_clzll does not take 64-bit arg");
|
||||
|
||||
// Handle 0 as a special case because __builtin_clzll(0) is undefined.
|
||||
if (n == 0) {
|
||||
return 64;
|
||||
}
|
||||
return __builtin_clzll(n);
|
||||
#else
|
||||
return CountLeadingZeros64Slow(n);
|
||||
#endif
|
||||
}
|
||||
|
||||
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) {
|
||||
int zeroes = 28;
|
||||
if (n >> 16) {
|
||||
zeroes -= 16;
|
||||
n >>= 16;
|
||||
}
|
||||
if (n >> 8) {
|
||||
zeroes -= 8;
|
||||
n >>= 8;
|
||||
}
|
||||
if (n >> 4) {
|
||||
zeroes -= 4;
|
||||
n >>= 4;
|
||||
}
|
||||
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
|
||||
}
|
||||
|
||||
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) {
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
unsigned long result = 0; // NOLINT(runtime/int)
|
||||
if (_BitScanReverse(&result, n)) {
|
||||
return 31 - result;
|
||||
}
|
||||
return 32;
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
// Use __builtin_clz, which uses the following instructions:
|
||||
// x86: bsr
|
||||
// ARM64: clz
|
||||
// PPC: cntlzd
|
||||
static_assert(sizeof(int) == sizeof(n),
|
||||
"__builtin_clz does not take 32-bit arg");
|
||||
|
||||
// Handle 0 as a special case because __builtin_clz(0) is undefined.
|
||||
if (n == 0) {
|
||||
return 32;
|
||||
}
|
||||
return __builtin_clz(n);
|
||||
#else
|
||||
return CountLeadingZeros32Slow(n);
|
||||
#endif
|
||||
}
|
||||
|
||||
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) {
|
||||
int c = 63;
|
||||
n &= ~n + 1;
|
||||
if (n & 0x00000000FFFFFFFF) c -= 32;
|
||||
if (n & 0x0000FFFF0000FFFF) c -= 16;
|
||||
if (n & 0x00FF00FF00FF00FF) c -= 8;
|
||||
if (n & 0x0F0F0F0F0F0F0F0F) c -= 4;
|
||||
if (n & 0x3333333333333333) c -= 2;
|
||||
if (n & 0x5555555555555555) c -= 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
|
||||
#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
|
||||
unsigned long result = 0; // NOLINT(runtime/int)
|
||||
_BitScanForward64(&result, n);
|
||||
return result;
|
||||
#elif defined(_MSC_VER) && !defined(__clang__)
|
||||
unsigned long result = 0; // NOLINT(runtime/int)
|
||||
if (static_cast<uint32_t>(n) == 0) {
|
||||
_BitScanForward(&result, n >> 32);
|
||||
return result + 32;
|
||||
}
|
||||
_BitScanForward(&result, n);
|
||||
return result;
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
|
||||
"__builtin_ctzll does not take 64-bit arg");
|
||||
return __builtin_ctzll(n);
|
||||
#else
|
||||
return CountTrailingZerosNonZero64Slow(n);
|
||||
#endif
|
||||
}
|
||||
|
||||
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) {
|
||||
int c = 31;
|
||||
n &= ~n + 1;
|
||||
if (n & 0x0000FFFF) c -= 16;
|
||||
if (n & 0x00FF00FF) c -= 8;
|
||||
if (n & 0x0F0F0F0F) c -= 4;
|
||||
if (n & 0x33333333) c -= 2;
|
||||
if (n & 0x55555555) c -= 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
unsigned long result = 0; // NOLINT(runtime/int)
|
||||
_BitScanForward(&result, n);
|
||||
return result;
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
static_assert(sizeof(int) == sizeof(n),
|
||||
"__builtin_ctz does not take 32-bit arg");
|
||||
return __builtin_ctz(n);
|
||||
#else
|
||||
return CountTrailingZerosNonZero32Slow(n);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef ABSL_BASE_INTERNAL_FORCEINLINE
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_BITS_H_
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#include "absl/base/internal/bits.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
int CLZ64(uint64_t n) {
|
||||
int fast = absl::base_internal::CountLeadingZeros64(n);
|
||||
int slow = absl::base_internal::CountLeadingZeros64Slow(n);
|
||||
EXPECT_EQ(fast, slow) << n;
|
||||
return fast;
|
||||
}
|
||||
|
||||
TEST(BitsTest, CountLeadingZeros64) {
|
||||
EXPECT_EQ(64, CLZ64(uint64_t{}));
|
||||
EXPECT_EQ(0, CLZ64(~uint64_t{}));
|
||||
|
||||
for (int index = 0; index < 64; index++) {
|
||||
uint64_t x = static_cast<uint64_t>(1) << index;
|
||||
const auto cnt = 63 - index;
|
||||
ASSERT_EQ(cnt, CLZ64(x)) << index;
|
||||
ASSERT_EQ(cnt, CLZ64(x + x - 1)) << index;
|
||||
}
|
||||
}
|
||||
|
||||
int CLZ32(uint32_t n) {
|
||||
int fast = absl::base_internal::CountLeadingZeros32(n);
|
||||
int slow = absl::base_internal::CountLeadingZeros32Slow(n);
|
||||
EXPECT_EQ(fast, slow) << n;
|
||||
return fast;
|
||||
}
|
||||
|
||||
TEST(BitsTest, CountLeadingZeros32) {
|
||||
EXPECT_EQ(32, CLZ32(uint32_t{}));
|
||||
EXPECT_EQ(0, CLZ32(~uint32_t{}));
|
||||
|
||||
for (int index = 0; index < 32; index++) {
|
||||
uint32_t x = static_cast<uint32_t>(1) << index;
|
||||
const auto cnt = 31 - index;
|
||||
ASSERT_EQ(cnt, CLZ32(x)) << index;
|
||||
ASSERT_EQ(cnt, CLZ32(x + x - 1)) << index;
|
||||
ASSERT_EQ(CLZ64(x), CLZ32(x) + 32);
|
||||
}
|
||||
}
|
||||
|
||||
int CTZ64(uint64_t n) {
|
||||
int fast = absl::base_internal::CountTrailingZerosNonZero64(n);
|
||||
int slow = absl::base_internal::CountTrailingZerosNonZero64Slow(n);
|
||||
EXPECT_EQ(fast, slow) << n;
|
||||
return fast;
|
||||
}
|
||||
|
||||
TEST(BitsTest, CountTrailingZerosNonZero64) {
|
||||
EXPECT_EQ(0, CTZ64(~uint64_t{}));
|
||||
|
||||
for (int index = 0; index < 64; index++) {
|
||||
uint64_t x = static_cast<uint64_t>(1) << index;
|
||||
const auto cnt = index;
|
||||
ASSERT_EQ(cnt, CTZ64(x)) << index;
|
||||
ASSERT_EQ(cnt, CTZ64(~(x - 1))) << index;
|
||||
}
|
||||
}
|
||||
|
||||
int CTZ32(uint32_t n) {
|
||||
int fast = absl::base_internal::CountTrailingZerosNonZero32(n);
|
||||
int slow = absl::base_internal::CountTrailingZerosNonZero32Slow(n);
|
||||
EXPECT_EQ(fast, slow) << n;
|
||||
return fast;
|
||||
}
|
||||
|
||||
TEST(BitsTest, CountTrailingZerosNonZero32) {
|
||||
EXPECT_EQ(0, CTZ32(~uint32_t{}));
|
||||
|
||||
for (int index = 0; index < 32; index++) {
|
||||
uint32_t x = static_cast<uint32_t>(1) << index;
|
||||
const auto cnt = index;
|
||||
ASSERT_EQ(cnt, CTZ32(x)) << index;
|
||||
ASSERT_EQ(cnt, CTZ32(~(x - 1))) << index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
|
@ -61,6 +61,10 @@ extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
|
|||
#endif
|
||||
#endif // __BIONIC__
|
||||
|
||||
#if defined(__NR_mmap2) && !defined(SYS_mmap2)
|
||||
#define SYS_mmap2 __NR_mmap2
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
|
@ -70,9 +74,13 @@ namespace base_internal {
|
|||
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(__s390__) && !defined(__s390x__))
|
||||
(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) {
|
||||
|
|
|
|||
398
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/dynamic_annotations.h
vendored
Normal file
398
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/dynamic_annotations.h
vendored
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_
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include "absl/base/casts.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/unaligned_access.h"
|
||||
#include "absl/base/port.h"
|
||||
|
|
@ -173,6 +174,36 @@ 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));
|
||||
|
|
@ -233,6 +264,36 @@ 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));
|
||||
|
|
|
|||
|
|
@ -54,24 +54,22 @@ const uint32_t k32ValueBE{0x67452301};
|
|||
const uint16_t k16ValueBE{0x2301};
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> GenerateAllValuesForType() {
|
||||
std::vector<T> result;
|
||||
T next = std::numeric_limits<T>::min();
|
||||
while (true) {
|
||||
result.push_back(next);
|
||||
if (next == std::numeric_limits<T>::max()) {
|
||||
return result;
|
||||
}
|
||||
++next;
|
||||
std::vector<uint16_t> GenerateAllUint16Values() {
|
||||
std::vector<uint16_t> result;
|
||||
result.reserve(size_t{1} << (sizeof(uint16_t) * 8));
|
||||
for (uint32_t i = std::numeric_limits<uint16_t>::min();
|
||||
i <= std::numeric_limits<uint16_t>::max(); ++i) {
|
||||
result.push_back(static_cast<uint16_t>(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> GenerateRandomIntegers(size_t numValuesToTest) {
|
||||
std::vector<T> GenerateRandomIntegers(size_t num_values_to_test) {
|
||||
std::vector<T> result;
|
||||
result.reserve(num_values_to_test);
|
||||
std::mt19937_64 rng(kRandomSeed);
|
||||
for (size_t i = 0; i < numValuesToTest; ++i) {
|
||||
for (size_t i = 0; i < num_values_to_test; ++i) {
|
||||
result.push_back(rng());
|
||||
}
|
||||
return result;
|
||||
|
|
@ -148,7 +146,7 @@ void Swap64(char* bytes) {
|
|||
}
|
||||
|
||||
TEST(EndianessTest, Uint16) {
|
||||
GBSwapHelper(GenerateAllValuesForType<uint16_t>(), &Swap16);
|
||||
GBSwapHelper(GenerateAllUint16Values(), &Swap16);
|
||||
}
|
||||
|
||||
TEST(EndianessTest, Uint32) {
|
||||
|
|
|
|||
|
|
@ -536,7 +536,22 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
|
|||
}
|
||||
|
||||
// Memory management operators
|
||||
// Args.. allows us to overload regular and placement new in one shot
|
||||
static void* operator new(size_t s) noexcept(
|
||||
IsSpecified(TypeSpec::kNoThrowNew)) {
|
||||
if (!IsSpecified(TypeSpec::kNoThrowNew)) {
|
||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
|
||||
}
|
||||
return ::operator new(s);
|
||||
}
|
||||
|
||||
static void* operator new[](size_t s) noexcept(
|
||||
IsSpecified(TypeSpec::kNoThrowNew)) {
|
||||
if (!IsSpecified(TypeSpec::kNoThrowNew)) {
|
||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
|
||||
}
|
||||
return ::operator new[](s);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static void* operator new(size_t s, Args&&... args) noexcept(
|
||||
IsSpecified(TypeSpec::kNoThrowNew)) {
|
||||
|
|
@ -557,12 +572,6 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
|
|||
|
||||
// Abseil doesn't support throwing overloaded operator delete. These are
|
||||
// provided so a throwing operator-new can clean up after itself.
|
||||
//
|
||||
// We provide both regular and templated operator delete because if only the
|
||||
// templated version is provided as we did with operator new, the compiler has
|
||||
// no way of knowing which overload of operator delete to call. See
|
||||
// https://en.cppreference.com/w/cpp/memory/new/operator_delete and
|
||||
// https://en.cppreference.com/w/cpp/language/delete for the gory details.
|
||||
void operator delete(void* p) noexcept { ::operator delete(p); }
|
||||
|
||||
template <typename... Args>
|
||||
|
|
@ -726,9 +735,8 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
|
|||
|
||||
ThrowingAllocator select_on_container_copy_construction() noexcept(
|
||||
IsSpecified(AllocSpec::kNoThrowAllocate)) {
|
||||
auto& out = *this;
|
||||
ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||
return out;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ int64_t ExponentialBiased::GetSkipCount(int64_t mean) {
|
|||
// Assume huge values are bias neutral, retain bias for next call.
|
||||
return std::numeric_limits<int64_t>::max() / 2;
|
||||
}
|
||||
double value = std::round(interval);
|
||||
double value = std::rint(interval);
|
||||
bias_ = interval - value;
|
||||
return value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ namespace base_internal {
|
|||
// Adjusting with rounding bias is relatively trivial:
|
||||
//
|
||||
// double value = bias_ + exponential_distribution(mean)();
|
||||
// double rounded_value = std::round(value);
|
||||
// double rounded_value = std::rint(value);
|
||||
// bias_ = value - rounded_value;
|
||||
// return rounded_value;
|
||||
//
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ TEST(ExponentialBiasedTest, InitializationModes) {
|
|||
ABSL_CONST_INIT static ExponentialBiased eb_static;
|
||||
EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0));
|
||||
|
||||
#if ABSL_HAVE_THREAD_LOCAL
|
||||
#ifdef ABSL_HAVE_THREAD_LOCAL
|
||||
thread_local ExponentialBiased eb_thread;
|
||||
EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0));
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// absl::base_internal::Invoke(f, args...) is an implementation of
|
||||
// absl::base_internal::invoke(f, args...) is an implementation of
|
||||
// INVOKE(f, args...) from section [func.require] of the C++ standard.
|
||||
//
|
||||
// [func.require]
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
// 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()
|
||||
// The implementation is SFINAE-friendly: substitution failure within invoke()
|
||||
// isn't an error.
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_INVOKE_H_
|
||||
|
|
@ -170,13 +170,13 @@ struct Invoker {
|
|||
|
||||
// The result type of Invoke<F, Args...>.
|
||||
template <typename F, typename... Args>
|
||||
using InvokeT = decltype(Invoker<F, Args...>::type::Invoke(
|
||||
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>
|
||||
InvokeT<F, Args...> Invoke(F&& f, Args&&... 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)...);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,12 @@
|
|||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "absl/container/node_hash_map.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
|
@ -75,7 +81,7 @@ static bool using_low_level_alloc = false;
|
|||
// allocations and deallocations are reported via the MallocHook
|
||||
// interface.
|
||||
static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
|
||||
typedef std::unordered_map<int, BlockDesc> AllocMap;
|
||||
typedef absl::node_hash_map<int, BlockDesc> AllocMap;
|
||||
AllocMap allocated;
|
||||
AllocMap::iterator it;
|
||||
BlockDesc block_desc;
|
||||
|
|
@ -156,5 +162,20 @@ ABSL_NAMESPACE_END
|
|||
int main(int argc, char *argv[]) {
|
||||
// The actual test runs in the global constructor of `before_main`.
|
||||
printf("PASS\n");
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// clang-format off
|
||||
// This is JS here. Don't try to format it.
|
||||
MAIN_THREAD_EM_ASM({
|
||||
if (ENVIRONMENT_IS_WEB) {
|
||||
if (typeof TEST_FINISH === 'function') {
|
||||
TEST_FINISH($0);
|
||||
} else {
|
||||
console.error('Attempted to exit with status ' + $0);
|
||||
console.error('But TEST_FINSIHED is not a function.');
|
||||
}
|
||||
}
|
||||
}, 0);
|
||||
// clang-format on
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#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"
|
||||
|
||||
|
|
@ -29,6 +30,13 @@ 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.
|
||||
|
|
@ -53,6 +61,8 @@ 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
|
||||
|
|
@ -76,12 +86,23 @@ class SchedulingGuard {
|
|||
bool disabled;
|
||||
};
|
||||
|
||||
// Access to SchedulingGuard is explicitly white-listed.
|
||||
// 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;
|
||||
|
||||
SchedulingGuard(const SchedulingGuard&) = delete;
|
||||
SchedulingGuard& operator=(const SchedulingGuard&) = delete;
|
||||
friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -100,6 +121,12 @@ 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
|
||||
|
|
|
|||
|
|
@ -67,28 +67,32 @@
|
|||
#undef ABSL_HAVE_RAW_IO
|
||||
#endif
|
||||
|
||||
// TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
|
||||
// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a
|
||||
// whitelisted set of platforms for which we expect not to be able to raw log.
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace raw_logging_internal {
|
||||
namespace {
|
||||
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
|
||||
absl::raw_logging_internal::LogPrefixHook>
|
||||
log_prefix_hook;
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
|
||||
absl::raw_logging_internal::AbortHook>
|
||||
abort_hook;
|
||||
// TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
|
||||
// Explicitly `#error` out when not `ABSL_LOW_LEVEL_WRITE_SUPPORTED`, except for
|
||||
// a selected set of platforms for which we expect not to be able to raw log.
|
||||
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
|
||||
absl::base_internal::AtomicHook<LogPrefixHook>
|
||||
log_prefix_hook;
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
|
||||
absl::base_internal::AtomicHook<AbortHook>
|
||||
abort_hook;
|
||||
|
||||
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
|
||||
static const char kTruncated[] = " ... (message truncated)\n";
|
||||
constexpr char kTruncated[] = " ... (message truncated)\n";
|
||||
|
||||
// sprintf the format to the buffer, adjusting *buf and *size to reflect the
|
||||
// consumed bytes, and return whether the message fit without truncation. If
|
||||
// truncation occurred, if possible leave room in the buffer for the message
|
||||
// kTruncated[].
|
||||
inline static bool VADoRawLog(char** buf, int* size, const char* format,
|
||||
va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0);
|
||||
inline static bool VADoRawLog(char** buf, int* size,
|
||||
const char* format, va_list ap) {
|
||||
bool VADoRawLog(char** buf, int* size, const char* format, va_list ap)
|
||||
ABSL_PRINTF_ATTRIBUTE(3, 0);
|
||||
bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) {
|
||||
int n = vsnprintf(*buf, *size, format, ap);
|
||||
bool result = true;
|
||||
if (n < 0 || n > *size) {
|
||||
|
|
@ -96,7 +100,7 @@ inline static bool VADoRawLog(char** buf, int* size,
|
|||
if (static_cast<size_t>(*size) > sizeof(kTruncated)) {
|
||||
n = *size - sizeof(kTruncated); // room for truncation message
|
||||
} else {
|
||||
n = 0; // no room for truncation message
|
||||
n = 0; // no room for truncation message
|
||||
}
|
||||
}
|
||||
*size -= n;
|
||||
|
|
@ -105,9 +109,7 @@ inline static bool VADoRawLog(char** buf, int* size,
|
|||
}
|
||||
#endif // ABSL_LOW_LEVEL_WRITE_SUPPORTED
|
||||
|
||||
static constexpr int kLogBufSize = 3000;
|
||||
|
||||
namespace {
|
||||
constexpr int kLogBufSize = 3000;
|
||||
|
||||
// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
|
||||
// that invoke malloc() and getenv() that might acquire some locks.
|
||||
|
|
@ -166,7 +168,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line,
|
|||
} else {
|
||||
DoRawLog(&buf, &size, "%s", kTruncated);
|
||||
}
|
||||
absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer));
|
||||
SafeWriteToStderr(buffer, strlen(buffer));
|
||||
}
|
||||
#else
|
||||
static_cast<void>(format);
|
||||
|
|
@ -181,11 +183,18 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line,
|
|||
}
|
||||
}
|
||||
|
||||
// Non-formatting version of RawLog().
|
||||
//
|
||||
// TODO(gfalcon): When string_view no longer depends on base, change this
|
||||
// interface to take its message as a string_view instead.
|
||||
void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line,
|
||||
const std::string& message) {
|
||||
RawLog(severity, file, line, "%.*s", static_cast<int>(message.size()),
|
||||
message.data());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace raw_logging_internal {
|
||||
void SafeWriteToStderr(const char *s, size_t len) {
|
||||
#if defined(ABSL_HAVE_SYSCALL_WRITE)
|
||||
syscall(SYS_write, STDERR_FILENO, s, len);
|
||||
|
|
@ -200,8 +209,6 @@ void SafeWriteToStderr(const char *s, size_t len) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void RawLog(absl::LogSeverity severity, const char* file, int line,
|
||||
const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
|
||||
void RawLog(absl::LogSeverity severity, const char* file, int line,
|
||||
const char* format, ...) {
|
||||
va_list ap;
|
||||
|
|
@ -210,15 +217,6 @@ void RawLog(absl::LogSeverity severity, const char* file, int line,
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
// Non-formatting version of RawLog().
|
||||
//
|
||||
// TODO(gfalcon): When string_view no longer depends on base, change this
|
||||
// interface to take its message as a string_view instead.
|
||||
static void DefaultInternalLog(absl::LogSeverity severity, const char* file,
|
||||
int line, const std::string& message) {
|
||||
RawLog(severity, file, line, "%s", message.c_str());
|
||||
}
|
||||
|
||||
bool RawLoggingFullySupported() {
|
||||
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
|
||||
return true;
|
||||
|
|
@ -227,10 +225,14 @@ bool RawLoggingFullySupported() {
|
|||
#endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
|
||||
}
|
||||
|
||||
ABSL_DLL ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL
|
||||
absl::base_internal::AtomicHook<InternalLogFunction>
|
||||
internal_log_function(DefaultInternalLog);
|
||||
|
||||
void RegisterLogPrefixHook(LogPrefixHook func) { log_prefix_hook.Store(func); }
|
||||
|
||||
void RegisterAbortHook(AbortHook func) { abort_hook.Store(func); }
|
||||
|
||||
void RegisterInternalLogFunction(InternalLogFunction func) {
|
||||
internal_log_function.Store(func);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,10 +72,14 @@
|
|||
//
|
||||
// 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 { \
|
||||
::absl::raw_logging_internal::internal_log_function( \
|
||||
ABSL_RAW_LOGGING_INTERNAL_##severity, __FILE__, __LINE__, 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) \
|
||||
|
|
@ -170,10 +174,18 @@ using InternalLogFunction = void (*)(absl::LogSeverity severity,
|
|||
const char* file, int line,
|
||||
const std::string& message);
|
||||
|
||||
ABSL_DLL ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES extern base_internal::AtomicHook<
|
||||
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 RegisterLogPrefixHook(LogPrefixHook func);
|
||||
void RegisterAbortHook(AbortHook func);
|
||||
void RegisterInternalLogFunction(InternalLogFunction func);
|
||||
|
||||
} // namespace raw_logging_internal
|
||||
|
|
|
|||
|
|
@ -66,35 +66,19 @@ void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock,
|
|||
submit_profile_data.Store(fn);
|
||||
}
|
||||
|
||||
// Static member variable definitions.
|
||||
constexpr uint32_t SpinLock::kSpinLockHeld;
|
||||
constexpr uint32_t SpinLock::kSpinLockCooperative;
|
||||
constexpr uint32_t SpinLock::kSpinLockDisabledScheduling;
|
||||
constexpr uint32_t SpinLock::kSpinLockSleeper;
|
||||
constexpr uint32_t SpinLock::kWaitTimeMask;
|
||||
|
||||
// Uncommon constructors.
|
||||
SpinLock::SpinLock(base_internal::SchedulingMode mode)
|
||||
: lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
|
||||
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
|
||||
}
|
||||
|
||||
SpinLock::SpinLock(base_internal::LinkerInitialized,
|
||||
base_internal::SchedulingMode mode) {
|
||||
ABSL_TSAN_MUTEX_CREATE(this, 0);
|
||||
if (IsCooperative(mode)) {
|
||||
InitLinkerInitializedAndCooperative();
|
||||
}
|
||||
// Otherwise, lockword_ is already initialized.
|
||||
}
|
||||
|
||||
// Static (linker initialized) spinlocks always start life as functional
|
||||
// non-cooperative locks. When their static constructor does run, it will call
|
||||
// this initializer to augment the lockword with the cooperative bit. By
|
||||
// actually taking the lock when we do this we avoid the need for an atomic
|
||||
// operation in the regular unlock path.
|
||||
//
|
||||
// SlowLock() must be careful to re-test for this bit so that any outstanding
|
||||
// waiters may be upgraded to cooperative status.
|
||||
void SpinLock::InitLinkerInitializedAndCooperative() {
|
||||
Lock();
|
||||
lockword_.fetch_or(kSpinLockCooperative, std::memory_order_relaxed);
|
||||
Unlock();
|
||||
}
|
||||
|
||||
// Monitor the lock to see if its value changes within some time period
|
||||
// (adaptive_spin_count loop iterations). The last value read from the lock
|
||||
// is returned from the method.
|
||||
|
|
@ -121,6 +105,14 @@ void SpinLock::SlowLock() {
|
|||
if ((lock_value & kSpinLockHeld) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
base_internal::SchedulingMode scheduling_mode;
|
||||
if ((lock_value & kSpinLockCooperative) != 0) {
|
||||
scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
|
||||
} else {
|
||||
scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
|
||||
}
|
||||
|
||||
// The lock was not obtained initially, so this thread needs to wait for
|
||||
// it. Record the current timestamp in the local variable wait_start_time
|
||||
// so the total wait time can be stored in the lockword once this thread
|
||||
|
|
@ -133,8 +125,9 @@ void SpinLock::SlowLock() {
|
|||
// it as having a sleeper.
|
||||
if ((lock_value & kWaitTimeMask) == 0) {
|
||||
// Here, just "mark" that the thread is going to sleep. Don't store the
|
||||
// lock wait time in the lock as that will cause the current lock
|
||||
// owner to think it experienced contention.
|
||||
// lock wait time in the lock -- the lock word stores the amount of time
|
||||
// that the current holder waited before acquiring the lock, not the wait
|
||||
// time of any thread currently waiting to acquire it.
|
||||
if (lockword_.compare_exchange_strong(
|
||||
lock_value, lock_value | kSpinLockSleeper,
|
||||
std::memory_order_relaxed, std::memory_order_relaxed)) {
|
||||
|
|
@ -148,15 +141,17 @@ void SpinLock::SlowLock() {
|
|||
// this thread obtains the lock.
|
||||
lock_value = TryLockInternal(lock_value, wait_cycles);
|
||||
continue; // Skip the delay at the end of the loop.
|
||||
} else if ((lock_value & kWaitTimeMask) == 0) {
|
||||
// The lock is still held, without a waiter being marked, but something
|
||||
// else about the lock word changed, causing our CAS to fail. For
|
||||
// example, a new lock holder may have acquired the lock with
|
||||
// kSpinLockDisabledScheduling set, whereas the previous holder had not
|
||||
// set that flag. In this case, attempt again to mark ourselves as a
|
||||
// waiter.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
base_internal::SchedulingMode scheduling_mode;
|
||||
if ((lock_value & kSpinLockCooperative) != 0) {
|
||||
scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
|
||||
} else {
|
||||
scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
|
||||
}
|
||||
// SpinLockDelay() calls into fiber scheduler, we need to see
|
||||
// synchronization there to avoid false positives.
|
||||
ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
|
||||
|
|
|
|||
|
|
@ -15,11 +15,8 @@
|
|||
//
|
||||
|
||||
// Most users requiring mutual exclusion should use Mutex.
|
||||
// SpinLock is provided for use in three situations:
|
||||
// SpinLock is provided for use in two situations:
|
||||
// - for use in code that Mutex itself depends on
|
||||
// - to get a faster fast-path release under low contention (without an
|
||||
// atomic read-modify-write) In return, SpinLock has worse behaviour under
|
||||
// contention, which is why Mutex is preferred in most situations.
|
||||
// - for async signal safety (see below)
|
||||
|
||||
// SpinLock is async signal safe. If a spinlock is used within a signal
|
||||
|
|
@ -36,6 +33,7 @@
|
|||
#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"
|
||||
|
|
@ -55,29 +53,22 @@ class ABSL_LOCKABLE SpinLock {
|
|||
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
|
||||
}
|
||||
|
||||
// Special constructor for use with static SpinLock objects. E.g.,
|
||||
//
|
||||
// static SpinLock lock(base_internal::kLinkerInitialized);
|
||||
//
|
||||
// When initialized using this constructor, we depend on the fact
|
||||
// that the linker has already initialized the memory appropriately. The lock
|
||||
// is initialized in non-cooperative mode.
|
||||
//
|
||||
// A SpinLock constructed like this can be freely used from global
|
||||
// initializers without worrying about the order in which global
|
||||
// initializers run.
|
||||
explicit SpinLock(base_internal::LinkerInitialized) {
|
||||
// Does nothing; lockword_ is already initialized
|
||||
ABSL_TSAN_MUTEX_CREATE(this, 0);
|
||||
}
|
||||
|
||||
// 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);
|
||||
SpinLock(base_internal::LinkerInitialized,
|
||||
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() {
|
||||
|
|
@ -146,8 +137,20 @@ class ABSL_LOCKABLE SpinLock {
|
|||
//
|
||||
// bit[0] encodes whether a lock is being held.
|
||||
// bit[1] encodes whether a lock uses cooperative scheduling.
|
||||
// bit[2] encodes whether a lock disables 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;
|
||||
|
|
@ -163,7 +166,6 @@ class ABSL_LOCKABLE SpinLock {
|
|||
}
|
||||
|
||||
uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
|
||||
void InitLinkerInitializedAndCooperative();
|
||||
void SlowLock() ABSL_ATTRIBUTE_COLD;
|
||||
void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
|
||||
uint32_t SpinLoop();
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
extern "C" {
|
||||
|
||||
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
|
||||
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
|
||||
|
|
@ -29,7 +29,7 @@ ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
|
|||
// arbitrary code.
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
|
||||
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
|
||||
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
|
||||
|
||||
} // extern "C"
|
||||
|
|
|
|||
|
|
@ -46,9 +46,17 @@ static_assert(sizeof(std::atomic<uint32_t>) == sizeof(int),
|
|||
#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 AbslInternalSpinLockDelay(
|
||||
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
|
||||
std::atomic<uint32_t> *w, uint32_t value, int loop,
|
||||
absl::base_internal::SchedulingMode) {
|
||||
absl::base_internal::ErrnoSaver errno_saver;
|
||||
|
|
@ -58,8 +66,8 @@ ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
|
|||
syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w,
|
||||
bool all) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
extern "C" {
|
||||
|
||||
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
|
||||
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;
|
||||
|
|
@ -40,7 +40,7 @@ ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
|
|||
}
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
|
||||
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
|
||||
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
|
||||
|
||||
} // extern "C"
|
||||
|
|
|
|||
|
|
@ -43,18 +43,16 @@ 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. This call is a hint, and on some
|
||||
// systems it may be a no-op; threads calling SpinLockDelay() will always wake
|
||||
// eventually even if SpinLockWake() is never called.
|
||||
// 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 delay that can be truncated by a call to SpinLockWake(w).
|
||||
// In all cases, it must return in bounded time even if SpinLockWake() is not
|
||||
// called.
|
||||
// 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);
|
||||
|
||||
|
|
@ -73,21 +71,23 @@ ABSL_NAMESPACE_END
|
|||
// By changing our extension points to be extern "C", we dodge this
|
||||
// check.
|
||||
extern "C" {
|
||||
void AbslInternalSpinLockWake(std::atomic<uint32_t> *w, bool all);
|
||||
void AbslInternalSpinLockDelay(
|
||||
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) {
|
||||
AbslInternalSpinLockWake(w, 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) {
|
||||
AbslInternalSpinLockDelay(w, value, loop, scheduling_mode);
|
||||
ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)
|
||||
(w, value, loop, scheduling_mode);
|
||||
}
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@
|
|||
|
||||
extern "C" {
|
||||
|
||||
void AbslInternalSpinLockDelay(std::atomic<uint32_t>* /* lock_word */,
|
||||
uint32_t /* value */, int loop,
|
||||
absl::base_internal::SchedulingMode /* mode */) {
|
||||
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);
|
||||
|
|
@ -31,7 +31,7 @@ void AbslInternalSpinLockDelay(std::atomic<uint32_t>* /* lock_word */,
|
|||
}
|
||||
}
|
||||
|
||||
void AbslInternalSpinLockWake(std::atomic<uint32_t>* /* lock_word */,
|
||||
bool /* all */) {}
|
||||
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
|
||||
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
|
||||
|
||||
} // extern "C"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "absl/base/internal/strerror.h"
|
||||
|
||||
#include <array>
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
|
|
@ -21,13 +22,13 @@
|
|||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/internal/errno_saver.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
namespace {
|
||||
|
||||
const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
|
||||
#if defined(_WIN32)
|
||||
int rc = strerror_s(buf, buflen, errnum);
|
||||
|
|
@ -35,15 +36,6 @@ const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
|
|||
if (rc == 0 && strncmp(buf, "Unknown error", buflen) == 0) *buf = '\0';
|
||||
return buf;
|
||||
#else
|
||||
#if defined(__GLIBC__) || defined(__APPLE__)
|
||||
// Use the BSD sys_errlist API provided by GNU glibc and others to
|
||||
// avoid any need to copy the message into the local buffer first.
|
||||
if (0 <= errnum && errnum < sys_nerr) {
|
||||
if (const char* p = sys_errlist[errnum]) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// The type of `ret` is platform-specific; both of these branches must compile
|
||||
// either way but only one will execute on any given platform:
|
||||
auto ret = strerror_r(errnum, buf, buflen);
|
||||
|
|
@ -57,10 +49,8 @@ const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
|
|||
}
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string StrError(int errnum) {
|
||||
absl::base_internal::ErrnoSaver errno_saver;
|
||||
std::string StrErrorInternal(int errnum) {
|
||||
char buf[100];
|
||||
const char* str = StrErrorAdaptor(errnum, buf, sizeof buf);
|
||||
if (*str == '\0') {
|
||||
|
|
@ -70,6 +60,29 @@ std::string StrError(int errnum) {
|
|||
return str;
|
||||
}
|
||||
|
||||
// kSysNerr is the number of errors from a recent glibc. `StrError()` falls back
|
||||
// to `StrErrorAdaptor()` if the value is larger than this.
|
||||
constexpr int kSysNerr = 135;
|
||||
|
||||
std::array<std::string, kSysNerr>* NewStrErrorTable() {
|
||||
auto* table = new std::array<std::string, kSysNerr>;
|
||||
for (int i = 0; i < static_cast<int>(table->size()); ++i) {
|
||||
(*table)[i] = StrErrorInternal(i);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string StrError(int errnum) {
|
||||
absl::base_internal::ErrnoSaver errno_saver;
|
||||
static const auto* table = NewStrErrorTable();
|
||||
if (errnum >= 0 && errnum < static_cast<int>(table->size())) {
|
||||
return (*table)[errnum];
|
||||
}
|
||||
return StrErrorInternal(errnum);
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
|||
|
|
@ -20,15 +20,6 @@
|
|||
#include "benchmark/benchmark.h"
|
||||
|
||||
namespace {
|
||||
#if defined(__GLIBC__) || defined(__APPLE__)
|
||||
void BM_SysErrList(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
benchmark::DoNotOptimize(std::string(sys_errlist[ERANGE]));
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SysErrList);
|
||||
#endif
|
||||
|
||||
void BM_AbslStrError(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
benchmark::DoNotOptimize(absl::base_internal::StrError(ERANGE));
|
||||
|
|
|
|||
|
|
@ -62,12 +62,14 @@ TEST(StrErrorTest, MultipleThreads) {
|
|||
++counter;
|
||||
errno = ERANGE;
|
||||
const std::string value = absl::base_internal::StrError(i);
|
||||
// EXPECT_* could change errno. Stash it first.
|
||||
int check_err = errno;
|
||||
EXPECT_THAT(check_err, Eq(ERANGE));
|
||||
// Only the GNU implementation is guaranteed to provide the
|
||||
// string "Unknown error nnn". POSIX doesn't say anything.
|
||||
if (!absl::StartsWith(value, "Unknown error ")) {
|
||||
EXPECT_THAT(absl::base_internal::StrError(i), Eq(expected_strings[i]));
|
||||
EXPECT_THAT(value, Eq(expected_strings[i]));
|
||||
}
|
||||
EXPECT_THAT(errno, Eq(ERANGE));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
|
@ -50,17 +51,86 @@
|
|||
#include <vector>
|
||||
|
||||
#include "absl/base/call_once.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/internal/spinlock.h"
|
||||
#include "absl/base/internal/unscaledcycleclock.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
// Returns number of bits set in `bitMask`
|
||||
DWORD Win32CountSetBits(ULONG_PTR bitMask) {
|
||||
for (DWORD bitSetCount = 0; ; ++bitSetCount) {
|
||||
if (bitMask == 0) return bitSetCount;
|
||||
bitMask &= bitMask - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the number of logical CPUs using GetLogicalProcessorInformation(), or
|
||||
// 0 if the number of processors is not available or can not be computed.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformation
|
||||
int Win32NumCPUs() {
|
||||
#pragma comment(lib, "kernel32.lib")
|
||||
using Info = SYSTEM_LOGICAL_PROCESSOR_INFORMATION;
|
||||
|
||||
DWORD info_size = sizeof(Info);
|
||||
Info* info(static_cast<Info*>(malloc(info_size)));
|
||||
if (info == nullptr) return 0;
|
||||
|
||||
bool success = GetLogicalProcessorInformation(info, &info_size);
|
||||
if (!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
free(info);
|
||||
info = static_cast<Info*>(malloc(info_size));
|
||||
if (info == nullptr) return 0;
|
||||
success = GetLogicalProcessorInformation(info, &info_size);
|
||||
}
|
||||
|
||||
DWORD logicalProcessorCount = 0;
|
||||
if (success) {
|
||||
Info* ptr = info;
|
||||
DWORD byteOffset = 0;
|
||||
while (byteOffset + sizeof(Info) <= info_size) {
|
||||
switch (ptr->Relationship) {
|
||||
case RelationProcessorCore:
|
||||
logicalProcessorCount += Win32CountSetBits(ptr->ProcessorMask);
|
||||
break;
|
||||
|
||||
case RelationNumaNode:
|
||||
case RelationCache:
|
||||
case RelationProcessorPackage:
|
||||
// Ignore other entries
|
||||
break;
|
||||
|
||||
default:
|
||||
// Ignore unknown entries
|
||||
break;
|
||||
}
|
||||
byteOffset += sizeof(Info);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
free(info);
|
||||
return logicalProcessorCount;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
static int GetNumCPUs() {
|
||||
#if defined(__myriad2__)
|
||||
return 1;
|
||||
#elif defined(_WIN32)
|
||||
const unsigned hardware_concurrency = Win32NumCPUs();
|
||||
return hardware_concurrency ? hardware_concurrency : 1;
|
||||
#else
|
||||
// Other possibilities:
|
||||
// - Read /sys/devices/system/cpu/online and use cpumask_parse()
|
||||
|
|
@ -343,15 +413,16 @@ pid_t GetTID() {
|
|||
#else
|
||||
|
||||
// Fallback implementation of GetTID using pthread_getspecific.
|
||||
static once_flag tid_once;
|
||||
static pthread_key_t tid_key;
|
||||
static absl::base_internal::SpinLock tid_lock(
|
||||
absl::base_internal::kLinkerInitialized);
|
||||
ABSL_CONST_INIT static once_flag tid_once;
|
||||
ABSL_CONST_INIT static pthread_key_t tid_key;
|
||||
ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock(
|
||||
absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
|
||||
|
||||
// We set a bit per thread in this array to indicate that an ID is in
|
||||
// use. ID 0 is unused because it is the default value returned by
|
||||
// pthread_getspecific().
|
||||
static std::vector<uint32_t>* tid_array ABSL_GUARDED_BY(tid_lock) = nullptr;
|
||||
ABSL_CONST_INIT static std::vector<uint32_t> *tid_array
|
||||
ABSL_GUARDED_BY(tid_lock) = nullptr;
|
||||
static constexpr int kBitsPerWord = 32; // tid_array is uint32_t.
|
||||
|
||||
// Returns the TID to tid_array.
|
||||
|
|
@ -418,6 +489,18 @@ pid_t GetTID() {
|
|||
|
||||
#endif
|
||||
|
||||
// GetCachedTID() caches the thread ID in thread-local storage (which is a
|
||||
// userspace construct) to avoid unnecessary system calls. Without this caching,
|
||||
// it can take roughly 98ns, while it takes roughly 1ns with this caching.
|
||||
pid_t GetCachedTID() {
|
||||
#ifdef ABSL_HAVE_THREAD_LOCAL
|
||||
static thread_local pid_t thread_id = GetTID();
|
||||
return thread_id;
|
||||
#else
|
||||
return GetTID();
|
||||
#endif // ABSL_HAVE_THREAD_LOCAL
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/port.h"
|
||||
|
||||
namespace absl {
|
||||
|
|
@ -59,6 +60,13 @@ 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
|
||||
|
|
|
|||
|
|
@ -37,17 +37,28 @@ TEST(SysinfoTest, NumCPUs) {
|
|||
<< "NumCPUs() should not have the default value of 0";
|
||||
}
|
||||
|
||||
// Ensure that NominalCPUFrequency returns a reasonable value, or 1.00 on
|
||||
// platforms where the CPU frequency is not available through sysfs.
|
||||
//
|
||||
// POWER is particularly problematic here; some Linux kernels expose the CPU
|
||||
// frequency, while others do not. Since we can't predict a priori what a given
|
||||
// machine is going to do, just disable this test on POWER on Linux.
|
||||
#if !(defined(__linux) && (defined(__ppc64__) || defined(__PPC64__)))
|
||||
TEST(SysinfoTest, NominalCPUFrequency) {
|
||||
#if !(defined(__aarch64__) && defined(__linux__)) && !defined(__EMSCRIPTEN__)
|
||||
EXPECT_GE(NominalCPUFrequency(), 1000.0)
|
||||
<< "NominalCPUFrequency() did not return a reasonable value";
|
||||
#else
|
||||
// Aarch64 cannot read the CPU frequency from sysfs, so we get back 1.0.
|
||||
// Emscripten does not have a sysfs to read from at all.
|
||||
// Linux only exposes the CPU frequency on certain architectures, and
|
||||
// Emscripten doesn't expose it at all.
|
||||
#if defined(__linux__) && \
|
||||
(defined(__aarch64__) || defined(__hppa__) || defined(__mips__) || \
|
||||
defined(__riscv) || defined(__s390x__)) || \
|
||||
defined(__EMSCRIPTEN__)
|
||||
EXPECT_EQ(NominalCPUFrequency(), 1.0)
|
||||
<< "CPU frequency detection was fixed! Please update unittest.";
|
||||
#else
|
||||
EXPECT_GE(NominalCPUFrequency(), 1000.0)
|
||||
<< "NominalCPUFrequency() did not return a reasonable value";
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(SysinfoTest, GetTID) {
|
||||
EXPECT_EQ(GetTID(), GetTID()); // Basic compile and equality test.
|
||||
|
|
|
|||
271
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_annotations.h
vendored
Normal file
271
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_annotations.h
vendored
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_
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/call_once.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/internal/spinlock.h"
|
||||
|
|
@ -53,9 +54,11 @@ void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) {
|
|||
// exist within a process (via dlopen() or similar), references to
|
||||
// thread_identity_ptr from each instance of the code will refer to
|
||||
// *different* instances of this ptr.
|
||||
#ifdef __GNUC__
|
||||
// Apple platforms have the visibility attribute, but issue a compile warning
|
||||
// that protected visibility is unsupported.
|
||||
#if ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
|
||||
__attribute__((visibility("protected")))
|
||||
#endif // __GNUC__
|
||||
#endif // ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
|
||||
#if ABSL_PER_THREAD_TLS
|
||||
// Prefer __thread to thread_local as benchmarks indicate it is a bit faster.
|
||||
ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr;
|
||||
|
|
@ -117,10 +120,10 @@ void SetCurrentThreadIdentity(
|
|||
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)
|
||||
// thread_identity.h. When we cannot expose thread_local variables in
|
||||
// headers, we opt for the correct-but-slower option of not inlining this
|
||||
// function.
|
||||
#ifndef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
|
||||
ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; }
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/per_thread_tls.h"
|
||||
#include "absl/base/optimization.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
|
@ -69,30 +70,28 @@ struct PerThreadSynch {
|
|||
// is using this PerThreadSynch as a terminator. Its
|
||||
// skip field must not be filled in because the loop
|
||||
// might then skip over the terminator.
|
||||
|
||||
// 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;
|
||||
|
||||
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.
|
||||
|
||||
intptr_t readers; // Number of readers in mutex.
|
||||
int priority; // Priority of thread (updated every so often).
|
||||
|
||||
// When priority will next be read (cycles).
|
||||
int64_t next_priority_read_cycles;
|
||||
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.
|
||||
|
|
@ -111,30 +110,30 @@ struct PerThreadSynch {
|
|||
};
|
||||
std::atomic<State> state;
|
||||
|
||||
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
|
||||
// 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;
|
||||
|
||||
bool wake; // This thread is to be woken from a Mutex.
|
||||
intptr_t readers; // Number of readers in 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;
|
||||
// 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
|
||||
|
|
@ -144,7 +143,7 @@ struct ThreadIdentity {
|
|||
|
||||
// Private: Reserved for absl::synchronization_internal::Waiter.
|
||||
struct WaiterState {
|
||||
char data[128];
|
||||
alignas(void*) char data[128];
|
||||
} waiter_state;
|
||||
|
||||
// Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
|
||||
|
|
@ -189,30 +188,32 @@ 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 direcly set
|
||||
#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 direcly set
|
||||
#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 direcly set
|
||||
#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 direcly set
|
||||
#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 ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
|
||||
#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.
|
||||
|
|
@ -235,13 +236,18 @@ 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
|
||||
// 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 when compiling as a DLL.
|
||||
#if !defined(ABSL_BUILD_DLL) && !defined(ABSL_CONSUME_DLL)
|
||||
// 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/internal/spinlock.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/synchronization/internal/per_thread_sem.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
|
|
@ -29,10 +30,9 @@ ABSL_NAMESPACE_BEGIN
|
|||
namespace base_internal {
|
||||
namespace {
|
||||
|
||||
// protects num_identities_reused
|
||||
static absl::base_internal::SpinLock map_lock(
|
||||
absl::base_internal::kLinkerInitialized);
|
||||
static int num_identities_reused;
|
||||
ABSL_CONST_INIT static absl::base_internal::SpinLock map_lock(
|
||||
absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
|
||||
ABSL_CONST_INIT static int num_identities_reused ABSL_GUARDED_BY(map_lock);
|
||||
|
||||
static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
|
|||
// - If a thread implementation chooses to recycle threads, that
|
||||
// correct re-initialization occurs.
|
||||
static const int kNumLoops = 3;
|
||||
static const int kNumThreads = 400;
|
||||
static const int kNumThreads = 32;
|
||||
for (int iter = 0; iter < kNumLoops; iter++) {
|
||||
std::vector<std::thread> threads;
|
||||
for (int i = 0; i < kNumThreads; ++i) {
|
||||
|
|
@ -90,6 +90,7 @@ TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
|
|||
// We should have recycled ThreadIdentity objects above; while (external)
|
||||
// library threads allocating their own identities may preclude some
|
||||
// reuse, we should have sufficient repetitions to exclude this.
|
||||
absl::base_internal::SpinLockHolder l(&map_lock);
|
||||
EXPECT_LT(kNumThreads, num_identities_reused);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <functional>
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
|
||||
|
|
@ -25,83 +26,186 @@ namespace absl {
|
|||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// NOTE: The various STL exception throwing functions are placed within the
|
||||
// #ifdef blocks so the symbols aren't exposed on platforms that don't support
|
||||
// them, such as the Android NDK. For example, ANGLE fails to link when building
|
||||
// within AOSP without them, since the STL functions don't exist.
|
||||
namespace {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
template <typename T>
|
||||
[[noreturn]] void Throw(const T& error) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
throw error;
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", error.what());
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
void ThrowStdLogicError(const std::string& what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::logic_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
void ThrowStdLogicError(const char* what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::logic_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg);
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
void ThrowStdInvalidArgument(const std::string& what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::invalid_argument(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
void ThrowStdInvalidArgument(const char* what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::invalid_argument(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg);
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThrowStdDomainError(const std::string& what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::domain_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
void ThrowStdDomainError(const char* what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::domain_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg);
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThrowStdLengthError(const std::string& what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::length_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
void ThrowStdLengthError(const char* what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::length_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg);
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThrowStdOutOfRange(const std::string& what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::out_of_range(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
void ThrowStdOutOfRange(const char* what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::out_of_range(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg);
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThrowStdRuntimeError(const std::string& what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::runtime_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
void ThrowStdRuntimeError(const char* what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::runtime_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg);
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThrowStdRangeError(const std::string& what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::range_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
void ThrowStdRangeError(const char* what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::range_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg);
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThrowStdOverflowError(const std::string& what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::overflow_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
void ThrowStdOverflowError(const char* what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::overflow_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg);
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThrowStdUnderflowError(const std::string& what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::underflow_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
void ThrowStdUnderflowError(const char* what_arg) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::underflow_error(what_arg));
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "%s", what_arg);
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); }
|
||||
void ThrowStdBadFunctionCall() {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::bad_function_call());
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThrowStdBadAlloc() { Throw(std::bad_alloc()); }
|
||||
void ThrowStdBadAlloc() {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
Throw(std::bad_alloc());
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
#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.
|
||||
//
|
||||
|
|
@ -28,7 +30,7 @@
|
|||
#error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set."
|
||||
#endif
|
||||
|
||||
#if defined(THREAD_SANITIZER) && defined(__has_include)
|
||||
#if defined(ABSL_HAVE_THREAD_SANITIZER) && defined(__has_include)
|
||||
#if __has_include(<sanitizer/tsan_interface.h>)
|
||||
#define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,80 +31,6 @@
|
|||
// The unaligned API is C++ only. The declarations use C++ features
|
||||
// (namespaces, inline) which are absent or incompatible in C.
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
|
||||
defined(MEMORY_SANITIZER)
|
||||
// Consider we have an unaligned load/store of 4 bytes from address 0x...05.
|
||||
// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
|
||||
// will miss a bug if 08 is the first unaddressable byte.
|
||||
// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
|
||||
// miss a race between this access and some other accesses to 08.
|
||||
// MemorySanitizer will correctly propagate the shadow on unaligned stores
|
||||
// and correctly report bugs on unaligned loads, but it may not properly
|
||||
// update and report the origin of the uninitialized memory.
|
||||
// For all three tools, replacing an unaligned access with a tool-specific
|
||||
// callback solves the problem.
|
||||
|
||||
// Make sure uint16_t/uint32_t/uint64_t are defined.
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
uint16_t __sanitizer_unaligned_load16(const void *p);
|
||||
uint32_t __sanitizer_unaligned_load32(const void *p);
|
||||
uint64_t __sanitizer_unaligned_load64(const void *p);
|
||||
void __sanitizer_unaligned_store16(void *p, uint16_t v);
|
||||
void __sanitizer_unaligned_store32(void *p, uint32_t v);
|
||||
void __sanitizer_unaligned_store64(void *p, uint64_t v);
|
||||
} // extern "C"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
inline uint16_t UnalignedLoad16(const void *p) {
|
||||
return __sanitizer_unaligned_load16(p);
|
||||
}
|
||||
|
||||
inline uint32_t UnalignedLoad32(const void *p) {
|
||||
return __sanitizer_unaligned_load32(p);
|
||||
}
|
||||
|
||||
inline uint64_t UnalignedLoad64(const void *p) {
|
||||
return __sanitizer_unaligned_load64(p);
|
||||
}
|
||||
|
||||
inline void UnalignedStore16(void *p, uint16_t v) {
|
||||
__sanitizer_unaligned_store16(p, v);
|
||||
}
|
||||
|
||||
inline void UnalignedStore32(void *p, uint32_t v) {
|
||||
__sanitizer_unaligned_store32(p, v);
|
||||
}
|
||||
|
||||
inline void UnalignedStore64(void *p, uint64_t v) {
|
||||
__sanitizer_unaligned_store64(p, 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))
|
||||
|
||||
#else
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
|
@ -151,8 +77,6 @@ ABSL_NAMESPACE_END
|
|||
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
|
||||
(absl::base_internal::UnalignedStore64(_p, _val))
|
||||
|
||||
#endif
|
||||
|
||||
#endif // defined(__cplusplus), end of unaligned API
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
// 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 "gtest/gtest.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
// This test by itself does not do anything fancy, but it serves as binary I can
|
||||
// query in shell test.
|
||||
|
||||
namespace {
|
||||
|
||||
template <class T>
|
||||
void DoNotOptimize(const T& var) {
|
||||
#ifdef __GNUC__
|
||||
asm volatile("" : "+m"(const_cast<T&>(var)));
|
||||
#else
|
||||
std::cout << (void*)&var;
|
||||
#endif
|
||||
}
|
||||
|
||||
int very_long_int_variable_name ABSL_INTERNAL_UNIQUE_SMALL_NAME() = 0;
|
||||
char very_long_str_variable_name[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = "abc";
|
||||
|
||||
TEST(UniqueSmallName, NonAutomaticVar) {
|
||||
EXPECT_EQ(very_long_int_variable_name, 0);
|
||||
EXPECT_EQ(absl::string_view(very_long_str_variable_name), "abc");
|
||||
}
|
||||
|
||||
int VeryLongFreeFunctionName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
|
||||
|
||||
TEST(UniqueSmallName, FreeFunction) {
|
||||
DoNotOptimize(&VeryLongFreeFunctionName);
|
||||
|
||||
EXPECT_EQ(VeryLongFreeFunctionName(), 456);
|
||||
}
|
||||
|
||||
int VeryLongFreeFunctionName() { return 456; }
|
||||
|
||||
struct VeryLongStructName {
|
||||
explicit VeryLongStructName(int i);
|
||||
|
||||
int VeryLongMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
|
||||
|
||||
static int VeryLongStaticMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
|
||||
|
||||
private:
|
||||
int fld;
|
||||
};
|
||||
|
||||
TEST(UniqueSmallName, Struct) {
|
||||
VeryLongStructName var(10);
|
||||
|
||||
DoNotOptimize(var);
|
||||
DoNotOptimize(&VeryLongStructName::VeryLongMethodName);
|
||||
DoNotOptimize(&VeryLongStructName::VeryLongStaticMethodName);
|
||||
|
||||
EXPECT_EQ(var.VeryLongMethodName(), 10);
|
||||
EXPECT_EQ(VeryLongStructName::VeryLongStaticMethodName(), 123);
|
||||
}
|
||||
|
||||
VeryLongStructName::VeryLongStructName(int i) : fld(i) {}
|
||||
int VeryLongStructName::VeryLongMethodName() { return fld; }
|
||||
int VeryLongStructName::VeryLongStaticMethodName() { return 123; }
|
||||
|
||||
} // namespace
|
||||
|
|
@ -119,13 +119,23 @@ double UnscaledCycleClock::Frequency() {
|
|||
return aarch64_timer_frequency;
|
||||
}
|
||||
|
||||
#elif defined(__riscv)
|
||||
|
||||
int64_t UnscaledCycleClock::Now() {
|
||||
int64_t virtual_timer_value;
|
||||
asm volatile("rdcycle %0" : "=r"(virtual_timer_value));
|
||||
return virtual_timer_value;
|
||||
}
|
||||
|
||||
double UnscaledCycleClock::Frequency() {
|
||||
return base_internal::NominalCPUFrequency();
|
||||
}
|
||||
|
||||
#elif defined(_M_IX86) || defined(_M_X64)
|
||||
|
||||
#pragma intrinsic(__rdtsc)
|
||||
|
||||
int64_t UnscaledCycleClock::Now() {
|
||||
return __rdtsc();
|
||||
}
|
||||
int64_t UnscaledCycleClock::Now() { return __rdtsc(); }
|
||||
|
||||
double UnscaledCycleClock::Frequency() {
|
||||
return base_internal::NominalCPUFrequency();
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@
|
|||
// 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 / whitelisted use only, you should consider
|
||||
// using CycleClock instead.
|
||||
// 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.
|
||||
|
|
@ -46,8 +46,8 @@
|
|||
|
||||
// The following platforms have an implementation of a hardware counter.
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
|
||||
defined(__powerpc__) || defined(__ppc__) || \
|
||||
defined(_M_IX86) || defined(_M_X64)
|
||||
defined(__powerpc__) || defined(__ppc__) || defined(__riscv) || \
|
||||
defined(_M_IX86) || defined(_M_X64)
|
||||
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 1
|
||||
#else
|
||||
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 0
|
||||
|
|
@ -80,8 +80,8 @@
|
|||
|
||||
// This macro can be used to test if UnscaledCycleClock::Frequency()
|
||||
// is NominalCPUFrequency() on a particular platform.
|
||||
#if (defined(__i386__) || defined(__x86_64__) || \
|
||||
defined(_M_IX86) || defined(_M_X64))
|
||||
#if (defined(__i386__) || defined(__x86_64__) || defined(__riscv) || \
|
||||
defined(_M_IX86) || defined(_M_X64))
|
||||
#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
|
||||
#endif
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ class UnscaledCycleClock {
|
|||
// value.
|
||||
static double Frequency();
|
||||
|
||||
// Whitelisted friends.
|
||||
// Allowed users
|
||||
friend class base_internal::CycleClock;
|
||||
friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime;
|
||||
friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
|
||||
|
|
|
|||
|
|
@ -86,71 +86,73 @@ struct FlipFlop {
|
|||
int member;
|
||||
};
|
||||
|
||||
// CallMaybeWithArg(f) resolves either to Invoke(f) or Invoke(f, 42), depending
|
||||
// CallMaybeWithArg(f) resolves either to invoke(f) or invoke(f, 42), depending
|
||||
// on which one is valid.
|
||||
template <typename F>
|
||||
decltype(Invoke(std::declval<const F&>())) CallMaybeWithArg(const F& f) {
|
||||
return Invoke(f);
|
||||
decltype(base_internal::invoke(std::declval<const F&>())) CallMaybeWithArg(
|
||||
const F& f) {
|
||||
return base_internal::invoke(f);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
decltype(Invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(const F& f) {
|
||||
return Invoke(f, 42);
|
||||
decltype(base_internal::invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(
|
||||
const F& f) {
|
||||
return base_internal::invoke(f, 42);
|
||||
}
|
||||
|
||||
TEST(InvokeTest, Function) {
|
||||
EXPECT_EQ(1, Invoke(Function, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Function, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(Function, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Function, 3, 2));
|
||||
}
|
||||
|
||||
TEST(InvokeTest, NonCopyableArgument) {
|
||||
EXPECT_EQ(42, Invoke(Sink, make_unique<int>(42)));
|
||||
EXPECT_EQ(42, base_internal::invoke(Sink, make_unique<int>(42)));
|
||||
}
|
||||
|
||||
TEST(InvokeTest, NonCopyableResult) {
|
||||
EXPECT_THAT(Invoke(Factory, 42), ::testing::Pointee(42));
|
||||
EXPECT_THAT(base_internal::invoke(Factory, 42), ::testing::Pointee(42));
|
||||
}
|
||||
|
||||
TEST(InvokeTest, VoidResult) {
|
||||
Invoke(NoOp);
|
||||
}
|
||||
TEST(InvokeTest, VoidResult) { base_internal::invoke(NoOp); }
|
||||
|
||||
TEST(InvokeTest, ConstFunctor) {
|
||||
EXPECT_EQ(1, Invoke(ConstFunctor(), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(ConstFunctor(), 3, 2));
|
||||
}
|
||||
|
||||
TEST(InvokeTest, MutableFunctor) {
|
||||
MutableFunctor f;
|
||||
EXPECT_EQ(1, Invoke(f, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(MutableFunctor(), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(f, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(MutableFunctor(), 3, 2));
|
||||
}
|
||||
|
||||
TEST(InvokeTest, EphemeralFunctor) {
|
||||
EphemeralFunctor f;
|
||||
EXPECT_EQ(1, Invoke(std::move(f), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(EphemeralFunctor(), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(std::move(f), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(EphemeralFunctor(), 3, 2));
|
||||
}
|
||||
|
||||
TEST(InvokeTest, OverloadedFunctor) {
|
||||
OverloadedFunctor f;
|
||||
const OverloadedFunctor& cf = f;
|
||||
|
||||
EXPECT_EQ("&", Invoke(f));
|
||||
EXPECT_EQ("& 42", Invoke(f, " 42"));
|
||||
EXPECT_EQ("&", base_internal::invoke(f));
|
||||
EXPECT_EQ("& 42", base_internal::invoke(f, " 42"));
|
||||
|
||||
EXPECT_EQ("const&", Invoke(cf));
|
||||
EXPECT_EQ("const& 42", Invoke(cf, " 42"));
|
||||
EXPECT_EQ("const&", base_internal::invoke(cf));
|
||||
EXPECT_EQ("const& 42", base_internal::invoke(cf, " 42"));
|
||||
|
||||
EXPECT_EQ("&&", Invoke(std::move(f)));
|
||||
EXPECT_EQ("&& 42", Invoke(std::move(f), " 42"));
|
||||
EXPECT_EQ("&&", base_internal::invoke(std::move(f)));
|
||||
|
||||
OverloadedFunctor f2;
|
||||
EXPECT_EQ("&& 42", base_internal::invoke(std::move(f2), " 42"));
|
||||
}
|
||||
|
||||
TEST(InvokeTest, ReferenceWrapper) {
|
||||
ConstFunctor cf;
|
||||
MutableFunctor mf;
|
||||
EXPECT_EQ(1, Invoke(std::cref(cf), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(std::ref(cf), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(std::ref(mf), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(std::cref(cf), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(std::ref(cf), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(std::ref(mf), 3, 2));
|
||||
}
|
||||
|
||||
TEST(InvokeTest, MemberFunction) {
|
||||
|
|
@ -158,58 +160,62 @@ TEST(InvokeTest, MemberFunction) {
|
|||
std::unique_ptr<const Class> cp(new Class);
|
||||
std::unique_ptr<volatile Class> vp(new Class);
|
||||
|
||||
EXPECT_EQ(1, Invoke(&Class::Method, p, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::Method, *p, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::RefMethod, p, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::RefMethod, p.get(), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::RefMethod, *p, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::RefRefMethod, std::move(*p), 3, 2)); // NOLINT
|
||||
EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p.get(), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, *p, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::Method, p, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::Method, p.get(), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::Method, *p, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p.get(), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, *p, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::RefRefMethod, std::move(*p), 3,
|
||||
2)); // NOLINT
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p.get(), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, *p, 3, 2));
|
||||
|
||||
EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::ConstMethod, *p, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, p, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, p.get(), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, *p, 3, 2));
|
||||
|
||||
EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, cp, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, cp.get(), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, *cp, 3, 2));
|
||||
|
||||
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p.get(), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *p, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp, 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp.get(), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *vp, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p.get(), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *p, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp, 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp.get(), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *vp, 3, 2));
|
||||
|
||||
EXPECT_EQ(1, Invoke(&Class::Method, make_unique<Class>(), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<Class>(), 3, 2));
|
||||
EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<const Class>(), 3, 2));
|
||||
EXPECT_EQ(1,
|
||||
base_internal::invoke(&Class::Method, make_unique<Class>(), 3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, make_unique<Class>(),
|
||||
3, 2));
|
||||
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod,
|
||||
make_unique<const Class>(), 3, 2));
|
||||
}
|
||||
|
||||
TEST(InvokeTest, DataMember) {
|
||||
std::unique_ptr<Class> p(new Class{42});
|
||||
std::unique_ptr<const Class> cp(new Class{42});
|
||||
EXPECT_EQ(42, Invoke(&Class::member, p));
|
||||
EXPECT_EQ(42, Invoke(&Class::member, *p));
|
||||
EXPECT_EQ(42, Invoke(&Class::member, p.get()));
|
||||
EXPECT_EQ(42, base_internal::invoke(&Class::member, p));
|
||||
EXPECT_EQ(42, base_internal::invoke(&Class::member, *p));
|
||||
EXPECT_EQ(42, base_internal::invoke(&Class::member, p.get()));
|
||||
|
||||
Invoke(&Class::member, p) = 42;
|
||||
Invoke(&Class::member, p.get()) = 42;
|
||||
base_internal::invoke(&Class::member, p) = 42;
|
||||
base_internal::invoke(&Class::member, p.get()) = 42;
|
||||
|
||||
EXPECT_EQ(42, Invoke(&Class::member, cp));
|
||||
EXPECT_EQ(42, Invoke(&Class::member, *cp));
|
||||
EXPECT_EQ(42, Invoke(&Class::member, cp.get()));
|
||||
EXPECT_EQ(42, base_internal::invoke(&Class::member, cp));
|
||||
EXPECT_EQ(42, base_internal::invoke(&Class::member, *cp));
|
||||
EXPECT_EQ(42, base_internal::invoke(&Class::member, cp.get()));
|
||||
}
|
||||
|
||||
TEST(InvokeTest, FlipFlop) {
|
||||
FlipFlop obj = {42};
|
||||
// This call could resolve to (obj.*&FlipFlop::ConstMethod)() or
|
||||
// ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former.
|
||||
EXPECT_EQ(42, Invoke(&FlipFlop::ConstMethod, obj));
|
||||
EXPECT_EQ(42, Invoke(&FlipFlop::member, obj));
|
||||
EXPECT_EQ(42, base_internal::invoke(&FlipFlop::ConstMethod, obj));
|
||||
EXPECT_EQ(42, base_internal::invoke(&FlipFlop::member, obj));
|
||||
}
|
||||
|
||||
TEST(InvokeTest, SfinaeFriendly) {
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
|
||||
#define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
|
||||
#ifndef ABSL_BASE_LOG_SEVERITY_H_
|
||||
#define ABSL_BASE_LOG_SEVERITY_H_
|
||||
|
||||
#include <array>
|
||||
#include <ostream>
|
||||
|
|
@ -36,7 +36,7 @@ ABSL_NAMESPACE_BEGIN
|
|||
// such values to a defined severity level, however in some cases values other
|
||||
// than the defined levels are useful for comparison.
|
||||
//
|
||||
// Exmaple:
|
||||
// Example:
|
||||
//
|
||||
// // Effectively disables all logging:
|
||||
// SetMinLogLevel(static_cast<absl::LogSeverity>(100));
|
||||
|
|
@ -118,4 +118,4 @@ std::ostream& operator<<(std::ostream& os, absl::LogSeverity s);
|
|||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
|
||||
#endif // ABSL_BASE_LOG_SEVERITY_H_
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ TEST(StreamTest, Works) {
|
|||
Eq("absl::LogSeverity(4)"));
|
||||
}
|
||||
|
||||
static_assert(
|
||||
absl::flags_internal::FlagUseOneWordStorage<absl::LogSeverity>::value,
|
||||
"Flags of type absl::LogSeverity ought to be lock-free.");
|
||||
static_assert(absl::flags_internal::FlagUseValueAndInitBitStorage<
|
||||
absl::LogSeverity>::value,
|
||||
"Flags of type absl::LogSeverity ought to be lock-free.");
|
||||
|
||||
using ParseFlagFromOutOfRangeIntegerTest = TestWithParam<int64_t>;
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
|
|
|
|||
|
|
@ -55,115 +55,6 @@ auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
|
|||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
// kLinkerInitialized
|
||||
//
|
||||
// An enum used only as a constructor argument to indicate that a variable has
|
||||
// static storage duration, and that the constructor should do nothing to its
|
||||
// state. Use of this macro indicates to the reader that it is legal to
|
||||
// declare a static instance of the class, provided the constructor is given
|
||||
// the absl::base_internal::kLinkerInitialized argument.
|
||||
//
|
||||
// Normally, it is unsafe to declare a static variable that has a constructor or
|
||||
// a destructor because invocation order is undefined. However, if the type can
|
||||
// be zero-initialized (which the loader does for static variables) into a valid
|
||||
// state and the type's destructor does not affect storage, then a constructor
|
||||
// for static initialization can be declared.
|
||||
//
|
||||
// Example:
|
||||
// // Declaration
|
||||
// explicit MyClass(absl::base_internal:LinkerInitialized x) {}
|
||||
//
|
||||
// // Invocation
|
||||
// static MyClass my_global(absl::base_internal::kLinkerInitialized);
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
enum LinkerInitialized {
|
||||
kLinkerInitialized = 0,
|
||||
};
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
// 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 compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
|
||||
// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
|
||||
// when performing switch labels fall-through diagnostic
|
||||
// (`-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."
|
||||
#endif
|
||||
|
||||
// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
|
||||
#if defined(__clang__) && defined(__has_warning)
|
||||
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
|
||||
#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
|
||||
#endif
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 7
|
||||
#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
|
||||
#endif
|
||||
|
||||
#ifndef ABSL_FALLTHROUGH_INTENDED
|
||||
#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).
|
||||
//
|
||||
// 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();
|
||||
//
|
||||
// Every usage of a deprecated entity will trigger a warning when compiled with
|
||||
// clang's `-Wdeprecated-declarations` option. This option is turned off by
|
||||
// default, but the warnings will be reported by clang-tidy.
|
||||
#if defined(__clang__) && __cplusplus >= 201103L
|
||||
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||
#endif
|
||||
|
||||
#ifndef ABSL_DEPRECATED
|
||||
#define ABSL_DEPRECATED(message)
|
||||
#endif
|
||||
|
||||
// ABSL_BAD_CALL_IF()
|
||||
//
|
||||
// Used on a function overload to trap bad calls: any call that matches the
|
||||
|
|
@ -253,4 +144,15 @@ ABSL_NAMESPACE_END
|
|||
#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_
|
||||
|
|
|
|||
|
|
@ -22,13 +22,15 @@
|
|||
#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. Use of this
|
||||
// macro is useful when you wish to preserve the existing function order within
|
||||
// a stack trace for logging, debugging, or profiling purposes.
|
||||
// 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:
|
||||
//
|
||||
|
|
@ -104,9 +106,10 @@
|
|||
// Cacheline aligning objects properly allows constructive memory sharing and
|
||||
// prevents destructive (or "false") memory sharing.
|
||||
//
|
||||
// NOTE: this macro should be replaced with usage of `alignas()` using
|
||||
// NOTE: callers should replace uses of this macro with `alignas()` using
|
||||
// `std::hardware_constructive_interference_size` and/or
|
||||
// `std::hardware_destructive_interference_size` when available within C++17.
|
||||
// `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.
|
||||
|
|
@ -171,11 +174,71 @@
|
|||
// to yield performance improvements.
|
||||
#if ABSL_HAVE_BUILTIN(__builtin_expect) || \
|
||||
(defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
||||
#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_INTERNAL_ASSUME(cond)
|
||||
// Informs the compiler that a condition is always true and that it can assume
|
||||
// it to be true for optimization purposes. The call has undefined behavior if
|
||||
// the condition is false.
|
||||
// In !NDEBUG mode, the condition is checked with an assert().
|
||||
// NOTE: The expression must not have side effects, as it will only be evaluated
|
||||
// in some compilation modes and not others.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// int x = ...;
|
||||
// ABSL_INTERNAL_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_INTERNAL_ASSUME(cond) assert(cond)
|
||||
#elif ABSL_HAVE_BUILTIN(__builtin_assume)
|
||||
#define ABSL_INTERNAL_ASSUME(cond) __builtin_assume(cond)
|
||||
#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
|
||||
#define ABSL_INTERNAL_ASSUME(cond) \
|
||||
do { \
|
||||
if (!(cond)) __builtin_unreachable(); \
|
||||
} while (0)
|
||||
#elif defined(_MSC_VER)
|
||||
#define ABSL_INTERNAL_ASSUME(cond) __assume(cond)
|
||||
#else
|
||||
#define ABSL_INTERNAL_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_
|
||||
|
|
|
|||
129
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/optimization_test.cc
vendored
Normal file
129
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/optimization_test.cc
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
// 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/base/optimization.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Tests for the ABSL_PREDICT_TRUE and ABSL_PREDICT_FALSE macros.
|
||||
// The tests only verify that the macros are functionally correct - i.e. code
|
||||
// behaves as if they weren't used. They don't try to check their impact on
|
||||
// optimization.
|
||||
|
||||
TEST(PredictTest, PredictTrue) {
|
||||
EXPECT_TRUE(ABSL_PREDICT_TRUE(true));
|
||||
EXPECT_FALSE(ABSL_PREDICT_TRUE(false));
|
||||
EXPECT_TRUE(ABSL_PREDICT_TRUE(1 == 1));
|
||||
EXPECT_FALSE(ABSL_PREDICT_TRUE(1 == 2));
|
||||
|
||||
if (ABSL_PREDICT_TRUE(false)) ADD_FAILURE();
|
||||
if (!ABSL_PREDICT_TRUE(true)) ADD_FAILURE();
|
||||
|
||||
EXPECT_TRUE(ABSL_PREDICT_TRUE(true) && true);
|
||||
EXPECT_TRUE(ABSL_PREDICT_TRUE(true) || false);
|
||||
}
|
||||
|
||||
TEST(PredictTest, PredictFalse) {
|
||||
EXPECT_TRUE(ABSL_PREDICT_FALSE(true));
|
||||
EXPECT_FALSE(ABSL_PREDICT_FALSE(false));
|
||||
EXPECT_TRUE(ABSL_PREDICT_FALSE(1 == 1));
|
||||
EXPECT_FALSE(ABSL_PREDICT_FALSE(1 == 2));
|
||||
|
||||
if (ABSL_PREDICT_FALSE(false)) ADD_FAILURE();
|
||||
if (!ABSL_PREDICT_FALSE(true)) ADD_FAILURE();
|
||||
|
||||
EXPECT_TRUE(ABSL_PREDICT_FALSE(true) && true);
|
||||
EXPECT_TRUE(ABSL_PREDICT_FALSE(true) || false);
|
||||
}
|
||||
|
||||
TEST(PredictTest, OneEvaluation) {
|
||||
// Verify that the expression is only evaluated once.
|
||||
int x = 0;
|
||||
if (ABSL_PREDICT_TRUE((++x) == 0)) ADD_FAILURE();
|
||||
EXPECT_EQ(x, 1);
|
||||
if (ABSL_PREDICT_FALSE((++x) == 0)) ADD_FAILURE();
|
||||
EXPECT_EQ(x, 2);
|
||||
}
|
||||
|
||||
TEST(PredictTest, OperatorOrder) {
|
||||
// Verify that operator order inside and outside the macro behaves well.
|
||||
// These would fail for a naive '#define ABSL_PREDICT_TRUE(x) x'
|
||||
EXPECT_TRUE(ABSL_PREDICT_TRUE(1 && 2) == true);
|
||||
EXPECT_TRUE(ABSL_PREDICT_FALSE(1 && 2) == true);
|
||||
EXPECT_TRUE(!ABSL_PREDICT_TRUE(1 == 2));
|
||||
EXPECT_TRUE(!ABSL_PREDICT_FALSE(1 == 2));
|
||||
}
|
||||
|
||||
TEST(PredictTest, Pointer) {
|
||||
const int x = 3;
|
||||
const int *good_intptr = &x;
|
||||
const int *null_intptr = nullptr;
|
||||
EXPECT_TRUE(ABSL_PREDICT_TRUE(good_intptr));
|
||||
EXPECT_FALSE(ABSL_PREDICT_TRUE(null_intptr));
|
||||
EXPECT_TRUE(ABSL_PREDICT_FALSE(good_intptr));
|
||||
EXPECT_FALSE(ABSL_PREDICT_FALSE(null_intptr));
|
||||
}
|
||||
|
||||
TEST(PredictTest, Optional) {
|
||||
// Note: An optional's truth value is the value's existence, not its truth.
|
||||
absl::optional<bool> has_value(false);
|
||||
absl::optional<bool> no_value;
|
||||
EXPECT_TRUE(ABSL_PREDICT_TRUE(has_value));
|
||||
EXPECT_FALSE(ABSL_PREDICT_TRUE(no_value));
|
||||
EXPECT_TRUE(ABSL_PREDICT_FALSE(has_value));
|
||||
EXPECT_FALSE(ABSL_PREDICT_FALSE(no_value));
|
||||
}
|
||||
|
||||
class ImplictlyConvertibleToBool {
|
||||
public:
|
||||
explicit ImplictlyConvertibleToBool(bool value) : value_(value) {}
|
||||
operator bool() const { // NOLINT(google-explicit-constructor)
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool value_;
|
||||
};
|
||||
|
||||
TEST(PredictTest, ImplicitBoolConversion) {
|
||||
const ImplictlyConvertibleToBool is_true(true);
|
||||
const ImplictlyConvertibleToBool is_false(false);
|
||||
if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE();
|
||||
if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE();
|
||||
if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE();
|
||||
if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE();
|
||||
}
|
||||
|
||||
class ExplictlyConvertibleToBool {
|
||||
public:
|
||||
explicit ExplictlyConvertibleToBool(bool value) : value_(value) {}
|
||||
explicit operator bool() const { return value_; }
|
||||
|
||||
private:
|
||||
bool value_;
|
||||
};
|
||||
|
||||
TEST(PredictTest, ExplicitBoolConversion) {
|
||||
const ExplictlyConvertibleToBool is_true(true);
|
||||
const ExplictlyConvertibleToBool is_false(false);
|
||||
if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE();
|
||||
if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE();
|
||||
if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE();
|
||||
if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Compiler Check
|
||||
// Toolchain Check
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// We support MSVC++ 14.0 update 2 and later.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
//
|
||||
// This files is a forwarding header for other headers containing various
|
||||
// portability macros and functions.
|
||||
// This file is used for both C and C++!
|
||||
|
||||
#ifndef ABSL_BASE_PORT_H_
|
||||
#define ABSL_BASE_PORT_H_
|
||||
|
|
|
|||
|
|
@ -20,10 +20,12 @@
|
|||
#include <limits>
|
||||
#include <random>
|
||||
#include <thread> // NOLINT(build/c++11)
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/low_level_scheduling.h"
|
||||
#include "absl/base/internal/scheduling_mode.h"
|
||||
#include "absl/base/internal/spinlock.h"
|
||||
|
|
@ -56,12 +58,10 @@ namespace {
|
|||
static constexpr int kArrayLength = 10;
|
||||
static uint32_t values[kArrayLength];
|
||||
|
||||
static SpinLock static_spinlock(base_internal::kLinkerInitialized);
|
||||
static SpinLock static_cooperative_spinlock(
|
||||
base_internal::kLinkerInitialized,
|
||||
base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
|
||||
static SpinLock static_noncooperative_spinlock(
|
||||
base_internal::kLinkerInitialized, base_internal::SCHEDULE_KERNEL_ONLY);
|
||||
ABSL_CONST_INIT static SpinLock static_cooperative_spinlock(
|
||||
absl::kConstInit, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
|
||||
ABSL_CONST_INIT static SpinLock static_noncooperative_spinlock(
|
||||
absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
|
||||
|
||||
// Simple integer hash function based on the public domain lookup2 hash.
|
||||
// http://burtleburtle.net/bob/c/lookup2.c
|
||||
|
|
@ -92,6 +92,7 @@ static void TestFunction(int thread_salt, SpinLock* spinlock) {
|
|||
|
||||
static void ThreadedTest(SpinLock* spinlock) {
|
||||
std::vector<std::thread> threads;
|
||||
threads.reserve(kNumThreads);
|
||||
for (int i = 0; i < kNumThreads; ++i) {
|
||||
threads.push_back(std::thread(TestFunction, i, spinlock));
|
||||
}
|
||||
|
|
@ -105,6 +106,10 @@ static void ThreadedTest(SpinLock* spinlock) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef ABSL_HAVE_THREAD_SANITIZER
|
||||
static_assert(std::is_trivially_destructible<SpinLock>(), "");
|
||||
#endif
|
||||
|
||||
TEST(SpinLock, StackNonCooperativeDisablesScheduling) {
|
||||
SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
|
||||
spinlock.Lock();
|
||||
|
|
@ -191,10 +196,6 @@ TEST(SpinLock, WaitCyclesEncoding) {
|
|||
EXPECT_GT(expected_max_value_decoded, before_max_value_decoded);
|
||||
}
|
||||
|
||||
TEST(SpinLockWithThreads, StaticSpinLock) {
|
||||
ThreadedTest(&static_spinlock);
|
||||
}
|
||||
|
||||
TEST(SpinLockWithThreads, StackSpinLock) {
|
||||
SpinLock spinlock;
|
||||
ThreadedTest(&spinlock);
|
||||
|
|
|
|||
|
|
@ -34,13 +34,10 @@
|
|||
#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
|
||||
#define ABSL_BASE_THREAD_ANNOTATIONS_H_
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x))
|
||||
#else
|
||||
#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) // no-op
|
||||
#endif
|
||||
// TODO(mbonadei): Remove after the backward compatibility period.
|
||||
#include "absl/base/internal/thread_annotations.h" // IWYU pragma: export
|
||||
|
||||
// ABSL_GUARDED_BY()
|
||||
//
|
||||
|
|
@ -59,8 +56,11 @@
|
|||
// int p1_ ABSL_GUARDED_BY(mu_);
|
||||
// ...
|
||||
// };
|
||||
#define ABSL_GUARDED_BY(x) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x))
|
||||
#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()
|
||||
//
|
||||
|
|
@ -82,8 +82,11 @@
|
|||
// // `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_);
|
||||
#define ABSL_PT_GUARDED_BY(x) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x))
|
||||
#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()
|
||||
//
|
||||
|
|
@ -100,11 +103,17 @@
|
|||
//
|
||||
// Mutex m1_;
|
||||
// Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
|
||||
#define ABSL_ACQUIRED_AFTER(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__))
|
||||
#if ABSL_HAVE_ATTRIBUTE(acquired_after)
|
||||
#define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_ACQUIRED_AFTER(...)
|
||||
#endif
|
||||
|
||||
#define ABSL_ACQUIRED_BEFORE(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__))
|
||||
#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()
|
||||
//
|
||||
|
|
@ -129,65 +138,95 @@
|
|||
//
|
||||
// void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
|
||||
// void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
|
||||
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
|
||||
exclusive_locks_required(__VA_ARGS__))
|
||||
#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(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_locks_required(__VA_ARGS__))
|
||||
__attribute__((shared_locks_required(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_SHARED_LOCKS_REQUIRED(...)
|
||||
#endif
|
||||
|
||||
// ABSL_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 ABSL_LOCKS_EXCLUDED(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(locks_excluded(__VA_ARGS__))
|
||||
#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.
|
||||
#define ABSL_LOCK_RETURNED(x) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x))
|
||||
#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).
|
||||
#define ABSL_LOCKABLE ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lockable)
|
||||
#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 `ABSL_UNLOCK_FUNCTION()` with no
|
||||
// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
|
||||
// arguments; the analysis will assume that the destructor unlocks whatever the
|
||||
// constructor locked.
|
||||
#define ABSL_SCOPED_LOCKABLE \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(scoped_lockable)
|
||||
#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.
|
||||
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
|
||||
exclusive_lock_function(__VA_ARGS__))
|
||||
#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(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_lock_function(__VA_ARGS__))
|
||||
__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.
|
||||
#define ABSL_UNLOCK_FUNCTION(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(unlock_function(__VA_ARGS__))
|
||||
#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()
|
||||
//
|
||||
|
|
@ -197,31 +236,49 @@
|
|||
// 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(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
|
||||
exclusive_trylock_function(__VA_ARGS__))
|
||||
__attribute__((exclusive_trylock_function(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...)
|
||||
#endif
|
||||
|
||||
#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
|
||||
shared_trylock_function(__VA_ARGS__))
|
||||
#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(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_exclusive_lock(__VA_ARGS__))
|
||||
__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(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_shared_lock(__VA_ARGS__))
|
||||
__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 \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis)
|
||||
__attribute__((no_thread_safety_analysis))
|
||||
#else
|
||||
#define ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tool-Supplied Annotations
|
||||
|
|
@ -252,7 +309,7 @@
|
|||
// 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::absl_ts_unchecked_read(x)
|
||||
#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::ts_unchecked_read(x)
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
|
@ -260,14 +317,14 @@ namespace base_internal {
|
|||
|
||||
// Takes a reference to a guarded data member, and returns an unguarded
|
||||
// reference.
|
||||
// Do not used this function directly, use ABSL_TS_UNCHECKED_READ instead.
|
||||
// Do not use this function directly, use ABSL_TS_UNCHECKED_READ instead.
|
||||
template <typename T>
|
||||
inline const T& absl_ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T& absl_ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
inline T& ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
return v;
|
||||
}
|
||||
|
||||
|
|
|
|||
55
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/CMakeLists.txt
vendored
Normal file
55
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# 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.
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
cleanup_internal
|
||||
HDRS
|
||||
"internal/cleanup.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::base_internal
|
||||
absl::core_headers
|
||||
absl::utility
|
||||
PUBLIC
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
cleanup
|
||||
HDRS
|
||||
"cleanup.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::cleanup_internal
|
||||
absl::config
|
||||
absl::core_headers
|
||||
PUBLIC
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
cleanup_test
|
||||
SRCS
|
||||
"cleanup_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::cleanup
|
||||
absl::config
|
||||
absl::utility
|
||||
GTest::gmock_main
|
||||
)
|
||||
140
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup.h
vendored
Normal file
140
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup.h
vendored
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_
|
||||
311
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup_test.cc
vendored
Normal file
311
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup_test.cc
vendored
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
// 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.
|
||||
|
||||
#include "absl/cleanup/cleanup.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/utility/utility.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using Tag = absl::cleanup_internal::Tag;
|
||||
|
||||
template <typename Type1, typename Type2>
|
||||
constexpr bool IsSame() {
|
||||
return (std::is_same<Type1, Type2>::value);
|
||||
}
|
||||
|
||||
struct IdentityFactory {
|
||||
template <typename Callback>
|
||||
static Callback AsCallback(Callback callback) {
|
||||
return Callback(std::move(callback));
|
||||
}
|
||||
};
|
||||
|
||||
// `FunctorClass` is a type used for testing `absl::Cleanup`. It is intended to
|
||||
// represent users that make their own move-only callback types outside of
|
||||
// `std::function` and lambda literals.
|
||||
class FunctorClass {
|
||||
using Callback = std::function<void()>;
|
||||
|
||||
public:
|
||||
explicit FunctorClass(Callback callback) : callback_(std::move(callback)) {}
|
||||
|
||||
FunctorClass(FunctorClass&& other)
|
||||
: callback_(absl::exchange(other.callback_, Callback())) {}
|
||||
|
||||
FunctorClass(const FunctorClass&) = delete;
|
||||
|
||||
FunctorClass& operator=(const FunctorClass&) = delete;
|
||||
|
||||
FunctorClass& operator=(FunctorClass&&) = delete;
|
||||
|
||||
void operator()() const& = delete;
|
||||
|
||||
void operator()() && {
|
||||
ASSERT_TRUE(callback_);
|
||||
callback_();
|
||||
callback_ = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
Callback callback_;
|
||||
};
|
||||
|
||||
struct FunctorClassFactory {
|
||||
template <typename Callback>
|
||||
static FunctorClass AsCallback(Callback callback) {
|
||||
return FunctorClass(std::move(callback));
|
||||
}
|
||||
};
|
||||
|
||||
struct StdFunctionFactory {
|
||||
template <typename Callback>
|
||||
static std::function<void()> AsCallback(Callback callback) {
|
||||
return std::function<void()>(std::move(callback));
|
||||
}
|
||||
};
|
||||
|
||||
using CleanupTestParams =
|
||||
::testing::Types<IdentityFactory, FunctorClassFactory, StdFunctionFactory>;
|
||||
template <typename>
|
||||
struct CleanupTest : public ::testing::Test {};
|
||||
TYPED_TEST_SUITE(CleanupTest, CleanupTestParams);
|
||||
|
||||
bool fn_ptr_called = false;
|
||||
void FnPtrFunction() { fn_ptr_called = true; }
|
||||
|
||||
TYPED_TEST(CleanupTest, FactoryProducesCorrectType) {
|
||||
{
|
||||
auto callback = TypeParam::AsCallback([] {});
|
||||
auto cleanup = absl::MakeCleanup(std::move(callback));
|
||||
|
||||
static_assert(
|
||||
IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
|
||||
"");
|
||||
}
|
||||
|
||||
{
|
||||
auto cleanup = absl::MakeCleanup(&FnPtrFunction);
|
||||
|
||||
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
|
||||
"");
|
||||
}
|
||||
|
||||
{
|
||||
auto cleanup = absl::MakeCleanup(FnPtrFunction);
|
||||
|
||||
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
|
||||
"");
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
|
||||
TYPED_TEST(CleanupTest, CTADProducesCorrectType) {
|
||||
{
|
||||
auto callback = TypeParam::AsCallback([] {});
|
||||
absl::Cleanup cleanup = std::move(callback);
|
||||
|
||||
static_assert(
|
||||
IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
|
||||
"");
|
||||
}
|
||||
|
||||
{
|
||||
absl::Cleanup cleanup = &FnPtrFunction;
|
||||
|
||||
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
|
||||
"");
|
||||
}
|
||||
|
||||
{
|
||||
absl::Cleanup cleanup = FnPtrFunction;
|
||||
|
||||
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
|
||||
"");
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) {
|
||||
{
|
||||
auto callback = IdentityFactory::AsCallback([] {});
|
||||
auto factory_cleanup = absl::MakeCleanup(callback);
|
||||
absl::Cleanup deduction_cleanup = callback;
|
||||
|
||||
static_assert(
|
||||
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
|
||||
}
|
||||
|
||||
{
|
||||
auto factory_cleanup =
|
||||
absl::MakeCleanup(FunctorClassFactory::AsCallback([] {}));
|
||||
absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {});
|
||||
|
||||
static_assert(
|
||||
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
|
||||
}
|
||||
|
||||
{
|
||||
auto factory_cleanup =
|
||||
absl::MakeCleanup(StdFunctionFactory::AsCallback([] {}));
|
||||
absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {});
|
||||
|
||||
static_assert(
|
||||
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
|
||||
}
|
||||
|
||||
{
|
||||
auto factory_cleanup = absl::MakeCleanup(&FnPtrFunction);
|
||||
absl::Cleanup deduction_cleanup = &FnPtrFunction;
|
||||
|
||||
static_assert(
|
||||
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
|
||||
}
|
||||
|
||||
{
|
||||
auto factory_cleanup = absl::MakeCleanup(FnPtrFunction);
|
||||
absl::Cleanup deduction_cleanup = FnPtrFunction;
|
||||
|
||||
static_assert(
|
||||
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
|
||||
}
|
||||
}
|
||||
#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
|
||||
|
||||
TYPED_TEST(CleanupTest, BasicUsage) {
|
||||
bool called = false;
|
||||
|
||||
{
|
||||
auto cleanup =
|
||||
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
|
||||
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
|
||||
}
|
||||
|
||||
EXPECT_TRUE(called); // Destructor should invoke the callback
|
||||
}
|
||||
|
||||
TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) {
|
||||
fn_ptr_called = false;
|
||||
|
||||
{
|
||||
auto cleanup = absl::MakeCleanup(TypeParam::AsCallback(&FnPtrFunction));
|
||||
EXPECT_FALSE(fn_ptr_called); // Constructor shouldn't invoke the callback
|
||||
}
|
||||
|
||||
EXPECT_TRUE(fn_ptr_called); // Destructor should invoke the callback
|
||||
}
|
||||
|
||||
TYPED_TEST(CleanupTest, Cancel) {
|
||||
bool called = false;
|
||||
|
||||
{
|
||||
auto cleanup =
|
||||
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
|
||||
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
|
||||
|
||||
std::move(cleanup).Cancel();
|
||||
EXPECT_FALSE(called); // Cancel shouldn't invoke the callback
|
||||
}
|
||||
|
||||
EXPECT_FALSE(called); // Destructor shouldn't invoke the callback
|
||||
}
|
||||
|
||||
TYPED_TEST(CleanupTest, Invoke) {
|
||||
bool called = false;
|
||||
|
||||
{
|
||||
auto cleanup =
|
||||
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
|
||||
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
|
||||
|
||||
std::move(cleanup).Invoke();
|
||||
EXPECT_TRUE(called); // Invoke should invoke the callback
|
||||
|
||||
called = false; // Reset tracker before destructor runs
|
||||
}
|
||||
|
||||
EXPECT_FALSE(called); // Destructor shouldn't invoke the callback
|
||||
}
|
||||
|
||||
TYPED_TEST(CleanupTest, Move) {
|
||||
bool called = false;
|
||||
|
||||
{
|
||||
auto moved_from_cleanup =
|
||||
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
|
||||
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
|
||||
|
||||
{
|
||||
auto moved_to_cleanup = std::move(moved_from_cleanup);
|
||||
EXPECT_FALSE(called); // Move shouldn't invoke the callback
|
||||
}
|
||||
|
||||
EXPECT_TRUE(called); // Destructor should invoke the callback
|
||||
|
||||
called = false; // Reset tracker before destructor runs
|
||||
}
|
||||
|
||||
EXPECT_FALSE(called); // Destructor shouldn't invoke the callback
|
||||
}
|
||||
|
||||
int DestructionCount = 0;
|
||||
|
||||
struct DestructionCounter {
|
||||
void operator()() {}
|
||||
|
||||
~DestructionCounter() { ++DestructionCount; }
|
||||
};
|
||||
|
||||
TYPED_TEST(CleanupTest, DestructorDestroys) {
|
||||
{
|
||||
auto cleanup =
|
||||
absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
|
||||
DestructionCount = 0;
|
||||
}
|
||||
|
||||
EXPECT_EQ(DestructionCount, 1); // Engaged cleanup destroys
|
||||
}
|
||||
|
||||
TYPED_TEST(CleanupTest, CancelDestroys) {
|
||||
{
|
||||
auto cleanup =
|
||||
absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
|
||||
DestructionCount = 0;
|
||||
|
||||
std::move(cleanup).Cancel();
|
||||
EXPECT_EQ(DestructionCount, 1); // Cancel destroys
|
||||
}
|
||||
|
||||
EXPECT_EQ(DestructionCount, 1); // Canceled cleanup does not double destroy
|
||||
}
|
||||
|
||||
TYPED_TEST(CleanupTest, InvokeDestroys) {
|
||||
{
|
||||
auto cleanup =
|
||||
absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
|
||||
DestructionCount = 0;
|
||||
|
||||
std::move(cleanup).Invoke();
|
||||
EXPECT_EQ(DestructionCount, 1); // Invoke destroys
|
||||
}
|
||||
|
||||
EXPECT_EQ(DestructionCount, 1); // Invoked cleanup does not double destroy
|
||||
}
|
||||
|
||||
} // namespace
|
||||
100
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/internal/cleanup.h
vendored
Normal file
100
third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/internal/cleanup.h
vendored
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_
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#
|
||||
# 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.
|
||||
|
||||
"""Creates config_setting that allows selecting based on 'compiler' value."""
|
||||
|
||||
def create_llvm_config(name, visibility):
|
||||
# The "do_not_use_tools_cpp_compiler_present" attribute exists to
|
||||
# distinguish between older versions of Bazel that do not support
|
||||
# "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
|
||||
# In the future, the only way to select on the compiler will be through
|
||||
# flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
|
||||
# be removed.
|
||||
if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
|
||||
native.config_setting(
|
||||
name = name,
|
||||
flag_values = {
|
||||
"@bazel_tools//tools/cpp:compiler": "llvm",
|
||||
},
|
||||
visibility = visibility,
|
||||
)
|
||||
else:
|
||||
native.config_setting(
|
||||
name = name,
|
||||
values = {"compiler": "llvm"},
|
||||
visibility = visibility,
|
||||
)
|
||||
|
|
@ -1,352 +0,0 @@
|
|||
# Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//third_party/abseil-cpp/absl.gni")
|
||||
|
||||
absl_source_set("compressed_tuple") {
|
||||
public = [ "internal/compressed_tuple.h" ]
|
||||
deps = [ "../utility" ]
|
||||
}
|
||||
|
||||
absl_source_set("fixed_array") {
|
||||
public = [ "fixed_array.h" ]
|
||||
deps = [
|
||||
":compressed_tuple",
|
||||
"../algorithm",
|
||||
"../base:core_headers",
|
||||
"../base:dynamic_annotations",
|
||||
"../base:throw_delegate",
|
||||
"../memory",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("inlined_vector_internal") {
|
||||
public = [ "internal/inlined_vector.h" ]
|
||||
deps = [
|
||||
":compressed_tuple",
|
||||
"../base:core_headers",
|
||||
"../memory",
|
||||
"../meta:type_traits",
|
||||
"../types:span",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("inlined_vector") {
|
||||
public = [ "inlined_vector.h" ]
|
||||
deps = [
|
||||
":inlined_vector_internal",
|
||||
"../algorithm",
|
||||
"../base:core_headers",
|
||||
"../base:throw_delegate",
|
||||
"../memory",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("counting_allocator") {
|
||||
testonly = true
|
||||
public = [ "internal/counting_allocator.h" ]
|
||||
deps = [ "../base:config" ]
|
||||
visibility = []
|
||||
visibility += [ ":*" ]
|
||||
}
|
||||
|
||||
absl_source_set("test_instance_tracker") {
|
||||
testonly = true
|
||||
sources = [ "internal/test_instance_tracker.cc" ]
|
||||
public = [ "internal/test_instance_tracker.h" ]
|
||||
deps = [ "../types:compare" ]
|
||||
visibility = []
|
||||
visibility += [ "../*" ]
|
||||
}
|
||||
|
||||
absl_source_set("flat_hash_map") {
|
||||
public = [ "flat_hash_map.h" ]
|
||||
deps = [
|
||||
":container_memory",
|
||||
":hash_function_defaults",
|
||||
":raw_hash_map",
|
||||
"../algorithm:container",
|
||||
"../memory",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("flat_hash_set") {
|
||||
public = [ "flat_hash_set.h" ]
|
||||
deps = [
|
||||
":container_memory",
|
||||
":hash_function_defaults",
|
||||
":raw_hash_set",
|
||||
"../algorithm:container",
|
||||
"../base:core_headers",
|
||||
"../memory",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("node_hash_map") {
|
||||
public = [ "node_hash_map.h" ]
|
||||
deps = [
|
||||
":container_memory",
|
||||
":hash_function_defaults",
|
||||
":node_hash_policy",
|
||||
":raw_hash_map",
|
||||
"../algorithm:container",
|
||||
"../memory",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("node_hash_set") {
|
||||
public = [ "node_hash_set.h" ]
|
||||
deps = [
|
||||
":container_memory",
|
||||
":hash_function_defaults",
|
||||
":node_hash_policy",
|
||||
":raw_hash_set",
|
||||
"../algorithm:container",
|
||||
"../memory",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("container_memory") {
|
||||
public = [ "internal/container_memory.h" ]
|
||||
deps = [
|
||||
"../memory",
|
||||
"../meta:type_traits",
|
||||
"../utility",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("hash_function_defaults") {
|
||||
public = [ "internal/hash_function_defaults.h" ]
|
||||
deps = [
|
||||
"../base:config",
|
||||
"../hash",
|
||||
"../strings",
|
||||
"../strings:cord",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("hash_generator_testing") {
|
||||
testonly = true
|
||||
sources = [ "internal/hash_generator_testing.cc" ]
|
||||
public = [ "internal/hash_generator_testing.h" ]
|
||||
deps = [
|
||||
":hash_policy_testing",
|
||||
"../memory",
|
||||
"../meta:type_traits",
|
||||
"../strings",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("hash_policy_testing") {
|
||||
testonly = true
|
||||
public = [ "internal/hash_policy_testing.h" ]
|
||||
deps = [
|
||||
"../hash",
|
||||
"../strings",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("hash_policy_traits") {
|
||||
public = [ "internal/hash_policy_traits.h" ]
|
||||
deps = [ "../meta:type_traits" ]
|
||||
}
|
||||
|
||||
absl_source_set("hashtable_debug") {
|
||||
public = [ "internal/hashtable_debug.h" ]
|
||||
deps = [ ":hashtable_debug_hooks" ]
|
||||
}
|
||||
|
||||
absl_source_set("hashtable_debug_hooks") {
|
||||
public = [ "internal/hashtable_debug_hooks.h" ]
|
||||
deps = [ "../base:config" ]
|
||||
}
|
||||
|
||||
absl_source_set("hashtablez_sampler") {
|
||||
public = [ "internal/hashtablez_sampler.h" ]
|
||||
sources = [
|
||||
"internal/hashtablez_sampler.cc",
|
||||
"internal/hashtablez_sampler_force_weak_definition.cc",
|
||||
]
|
||||
deps = [
|
||||
":have_sse",
|
||||
"../base",
|
||||
"../base:core_headers",
|
||||
"../base:exponential_biased",
|
||||
"../debugging:stacktrace",
|
||||
"../memory",
|
||||
"../synchronization",
|
||||
"../utility",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("node_hash_policy") {
|
||||
public = [ "internal/node_hash_policy.h" ]
|
||||
deps = [ "../base:config" ]
|
||||
}
|
||||
|
||||
absl_source_set("raw_hash_map") {
|
||||
public = [ "internal/raw_hash_map.h" ]
|
||||
deps = [
|
||||
":container_memory",
|
||||
":raw_hash_set",
|
||||
"../base:throw_delegate",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("have_sse") {
|
||||
public = [ "internal/have_sse.h" ]
|
||||
visibility = []
|
||||
visibility += [ ":*" ]
|
||||
}
|
||||
|
||||
absl_source_set("common") {
|
||||
public = [ "internal/common.h" ]
|
||||
deps = [
|
||||
"../meta:type_traits",
|
||||
"../types:optional",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("raw_hash_set") {
|
||||
sources = [ "internal/raw_hash_set.cc" ]
|
||||
public = [ "internal/raw_hash_set.h" ]
|
||||
deps = [
|
||||
":common",
|
||||
":compressed_tuple",
|
||||
":container_memory",
|
||||
":hash_policy_traits",
|
||||
":hashtable_debug_hooks",
|
||||
":hashtablez_sampler",
|
||||
":have_sse",
|
||||
":layout",
|
||||
"../base:bits",
|
||||
"../base:config",
|
||||
"../base:core_headers",
|
||||
"../base:endian",
|
||||
"../memory",
|
||||
"../meta:type_traits",
|
||||
"../utility",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("layout") {
|
||||
public = [ "internal/layout.h" ]
|
||||
deps = [
|
||||
"../base:core_headers",
|
||||
"../meta:type_traits",
|
||||
"../strings",
|
||||
"../types:span",
|
||||
"../utility",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("tracked") {
|
||||
testonly = true
|
||||
public = [ "internal/tracked.h" ]
|
||||
deps = [ "../base:config" ]
|
||||
}
|
||||
|
||||
absl_source_set("unordered_map_constructor_test") {
|
||||
testonly = true
|
||||
public = [ "internal/unordered_map_constructor_test.h" ]
|
||||
deps = [
|
||||
":hash_generator_testing",
|
||||
":hash_policy_testing",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("unordered_map_lookup_test") {
|
||||
testonly = true
|
||||
public = [ "internal/unordered_map_lookup_test.h" ]
|
||||
deps = [
|
||||
":hash_generator_testing",
|
||||
":hash_policy_testing",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("unordered_map_modifiers_test") {
|
||||
testonly = true
|
||||
public = [ "internal/unordered_map_modifiers_test.h" ]
|
||||
deps = [
|
||||
":hash_generator_testing",
|
||||
":hash_policy_testing",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("unordered_set_constructor_test") {
|
||||
testonly = true
|
||||
public = [ "internal/unordered_set_constructor_test.h" ]
|
||||
deps = [
|
||||
":hash_generator_testing",
|
||||
":hash_policy_testing",
|
||||
"../meta:type_traits",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("unordered_set_members_test") {
|
||||
testonly = true
|
||||
public = [ "internal/unordered_set_members_test.h" ]
|
||||
deps = [
|
||||
"../meta:type_traits",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("unordered_map_members_test") {
|
||||
testonly = true
|
||||
public = [ "internal/unordered_map_members_test.h" ]
|
||||
deps = [
|
||||
"../meta:type_traits",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("unordered_set_lookup_test") {
|
||||
testonly = true
|
||||
public = [ "internal/unordered_set_lookup_test.h" ]
|
||||
deps = [
|
||||
":hash_generator_testing",
|
||||
":hash_policy_testing",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("unordered_set_modifiers_test") {
|
||||
testonly = true
|
||||
public = [ "internal/unordered_set_modifiers_test.h" ]
|
||||
deps = [
|
||||
":hash_generator_testing",
|
||||
":hash_policy_testing",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
absl_source_set("btree") {
|
||||
sources = [
|
||||
"internal/btree.h",
|
||||
"internal/btree_container.h",
|
||||
]
|
||||
public = [
|
||||
"btree_map.h",
|
||||
"btree_set.h",
|
||||
]
|
||||
deps = [
|
||||
":common",
|
||||
":compressed_tuple",
|
||||
":container_memory",
|
||||
":layout",
|
||||
"../base:core_headers",
|
||||
"../base:throw_delegate",
|
||||
"../memory",
|
||||
"../meta:type_traits",
|
||||
"../strings",
|
||||
"../strings:cord",
|
||||
"../types:compare",
|
||||
"../utility",
|
||||
]
|
||||
}
|
||||
|
|
@ -14,15 +14,6 @@
|
|||
# limitations under the License.
|
||||
#
|
||||
|
||||
# This is deprecated and will be removed in the future. It also doesn't do
|
||||
# anything anyways. Prefer to use the library associated with the API you are
|
||||
# using.
|
||||
absl_cc_library(
|
||||
NAME
|
||||
container
|
||||
PUBLIC
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
btree
|
||||
|
|
@ -89,7 +80,7 @@ absl_cc_test(
|
|||
absl::strings
|
||||
absl::test_instance_tracker
|
||||
absl::type_traits
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -118,7 +109,7 @@ absl_cc_test(
|
|||
absl::optional
|
||||
absl::test_instance_tracker
|
||||
absl::utility
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -131,6 +122,7 @@ absl_cc_library(
|
|||
DEPS
|
||||
absl::compressed_tuple
|
||||
absl::algorithm
|
||||
absl::config
|
||||
absl::core_headers
|
||||
absl::dynamic_annotations
|
||||
absl::throw_delegate
|
||||
|
|
@ -147,11 +139,12 @@ absl_cc_test(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::fixed_array
|
||||
absl::counting_allocator
|
||||
absl::config
|
||||
absl::exception_testing
|
||||
absl::hash_testing
|
||||
absl::memory
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -165,7 +158,7 @@ absl_cc_test(
|
|||
absl::fixed_array
|
||||
absl::config
|
||||
absl::exception_safety_testing
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -229,7 +222,7 @@ absl_cc_test(
|
|||
absl::memory
|
||||
absl::raw_logging_internal
|
||||
absl::strings
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -243,7 +236,7 @@ absl_cc_test(
|
|||
absl::inlined_vector
|
||||
absl::config
|
||||
absl::exception_safety_testing
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -269,7 +262,7 @@ absl_cc_test(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::test_instance_tracker
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -303,7 +296,8 @@ absl_cc_test(
|
|||
absl::unordered_map_members_test
|
||||
absl::unordered_map_modifiers_test
|
||||
absl::any
|
||||
gmock_main
|
||||
absl::raw_logging_internal
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -339,8 +333,9 @@ absl_cc_test(
|
|||
absl::unordered_set_members_test
|
||||
absl::unordered_set_modifiers_test
|
||||
absl::memory
|
||||
absl::raw_logging_internal
|
||||
absl::strings
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -375,7 +370,7 @@ absl_cc_test(
|
|||
absl::unordered_map_lookup_test
|
||||
absl::unordered_map_members_test
|
||||
absl::unordered_map_modifiers_test
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -409,7 +404,7 @@ absl_cc_test(
|
|||
absl::unordered_set_lookup_test
|
||||
absl::unordered_set_members_test
|
||||
absl::unordered_set_modifiers_test
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -420,6 +415,7 @@ absl_cc_library(
|
|||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
absl::memory
|
||||
absl::type_traits
|
||||
absl::utility
|
||||
|
|
@ -437,7 +433,7 @@ absl_cc_test(
|
|||
absl::container_memory
|
||||
absl::strings
|
||||
absl::test_instance_tracker
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -469,7 +465,7 @@ absl_cc_test(
|
|||
absl::hash
|
||||
absl::random_random
|
||||
absl::strings
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -511,7 +507,7 @@ absl_cc_test(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::hash_policy_testing
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -535,7 +531,7 @@ absl_cc_test(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::hash_policy_traits
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -552,6 +548,7 @@ absl_cc_library(
|
|||
absl::base
|
||||
absl::exponential_biased
|
||||
absl::have_sse
|
||||
absl::sample_recorder
|
||||
absl::synchronization
|
||||
)
|
||||
|
||||
|
|
@ -565,7 +562,7 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::hashtablez_sampler
|
||||
absl::have_sse
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -622,7 +619,7 @@ absl_cc_test(
|
|||
DEPS
|
||||
absl::hash_policy_traits
|
||||
absl::node_hash_policy
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -670,7 +667,6 @@ absl_cc_library(
|
|||
absl::hash_policy_traits
|
||||
absl::hashtable_debug_hooks
|
||||
absl::have_sse
|
||||
absl::layout
|
||||
absl::memory
|
||||
absl::meta
|
||||
absl::optional
|
||||
|
|
@ -693,10 +689,11 @@ absl_cc_test(
|
|||
absl::hashtable_debug
|
||||
absl::raw_hash_set
|
||||
absl::base
|
||||
absl::config
|
||||
absl::core_headers
|
||||
absl::raw_logging_internal
|
||||
absl::strings
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -710,7 +707,7 @@ absl_cc_test(
|
|||
absl::raw_hash_set
|
||||
absl::tracked
|
||||
absl::core_headers
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -721,6 +718,7 @@ absl_cc_library(
|
|||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
absl::core_headers
|
||||
absl::meta
|
||||
absl::strings
|
||||
|
|
@ -738,10 +736,11 @@ absl_cc_test(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::layout
|
||||
absl::config
|
||||
absl::core_headers
|
||||
absl::raw_logging_internal
|
||||
absl::span
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
|
|
@ -766,7 +765,7 @@ absl_cc_library(
|
|||
DEPS
|
||||
absl::hash_generator_testing
|
||||
absl::hash_policy_testing
|
||||
gmock
|
||||
GTest::gmock
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
|
@ -780,7 +779,7 @@ absl_cc_library(
|
|||
DEPS
|
||||
absl::hash_generator_testing
|
||||
absl::hash_policy_testing
|
||||
gmock
|
||||
GTest::gmock
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
|
@ -793,7 +792,7 @@ absl_cc_library(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::type_traits
|
||||
gmock
|
||||
GTest::gmock
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
|
@ -807,7 +806,7 @@ absl_cc_library(
|
|||
DEPS
|
||||
absl::hash_generator_testing
|
||||
absl::hash_policy_testing
|
||||
gmock
|
||||
GTest::gmock
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
|
@ -821,7 +820,7 @@ absl_cc_library(
|
|||
DEPS
|
||||
absl::hash_generator_testing
|
||||
absl::hash_policy_testing
|
||||
gmock
|
||||
GTest::gmock
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
|
@ -835,7 +834,7 @@ absl_cc_library(
|
|||
DEPS
|
||||
absl::hash_generator_testing
|
||||
absl::hash_policy_testing
|
||||
gmock
|
||||
GTest::gmock
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
|
@ -848,7 +847,7 @@ absl_cc_library(
|
|||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::type_traits
|
||||
gmock
|
||||
GTest::gmock
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
|
@ -862,7 +861,7 @@ absl_cc_library(
|
|||
DEPS
|
||||
absl::hash_generator_testing
|
||||
absl::hash_policy_testing
|
||||
gmock
|
||||
GTest::gmock
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
|
@ -878,7 +877,7 @@ absl_cc_test(
|
|||
absl::unordered_set_lookup_test
|
||||
absl::unordered_set_members_test
|
||||
absl::unordered_set_modifiers_test
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
|
|
@ -893,5 +892,5 @@ absl_cc_test(
|
|||
absl::unordered_map_lookup_test
|
||||
absl::unordered_map_members_test
|
||||
absl::unordered_map_modifiers_test
|
||||
gmock_main
|
||||
GTest::gmock_main
|
||||
)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/container/btree_map.h"
|
||||
#include "absl/container/btree_set.h"
|
||||
|
|
@ -39,7 +40,6 @@
|
|||
#include "absl/strings/cord.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
|
@ -101,39 +101,6 @@ void BM_InsertSorted(benchmark::State& state) {
|
|||
BM_InsertImpl<T>(state, true);
|
||||
}
|
||||
|
||||
// container::insert sometimes returns a pair<iterator, bool> and sometimes
|
||||
// returns an iterator (for multi- containers).
|
||||
template <typename Iter>
|
||||
Iter GetIterFromInsert(const std::pair<Iter, bool>& pair) {
|
||||
return pair.first;
|
||||
}
|
||||
template <typename Iter>
|
||||
Iter GetIterFromInsert(const Iter iter) {
|
||||
return iter;
|
||||
}
|
||||
|
||||
// Benchmark insertion of values into a container at the end.
|
||||
template <typename T>
|
||||
void BM_InsertEnd(benchmark::State& state) {
|
||||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||
|
||||
T container;
|
||||
const int kSize = 10000;
|
||||
for (int i = 0; i < kSize; ++i) {
|
||||
container.insert(Generator<V>(kSize)(i));
|
||||
}
|
||||
V v = Generator<V>(kSize)(kSize - 1);
|
||||
typename T::key_type k = key_of_value(v);
|
||||
|
||||
auto it = container.find(k);
|
||||
while (state.KeepRunning()) {
|
||||
// Repeatedly removing then adding v.
|
||||
container.erase(it);
|
||||
it = GetIterFromInsert(container.insert(v));
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark inserting the first few elements in a container. In b-tree, this is
|
||||
// when the root node grows.
|
||||
template <typename T>
|
||||
|
|
@ -513,7 +480,6 @@ BTREE_TYPES(Time);
|
|||
#define MY_BENCHMARK3(type) \
|
||||
MY_BENCHMARK4(type, Insert); \
|
||||
MY_BENCHMARK4(type, InsertSorted); \
|
||||
MY_BENCHMARK4(type, InsertEnd); \
|
||||
MY_BENCHMARK4(type, InsertSmall); \
|
||||
MY_BENCHMARK4(type, Lookup); \
|
||||
MY_BENCHMARK4(type, FullLookup); \
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ class btree_map
|
|||
// 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.
|
||||
// number of elements erased (0 or 1).
|
||||
using Base::erase;
|
||||
|
||||
// btree_map::insert()
|
||||
|
|
@ -325,6 +325,11 @@ class 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).
|
||||
|
|
@ -361,8 +366,8 @@ class btree_map
|
|||
// 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 is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||
// heterogeneous comparator.
|
||||
using Base::contains;
|
||||
|
||||
// btree_map::count()
|
||||
|
|
@ -373,15 +378,14 @@ class btree_map
|
|||
// 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 is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||
// heterogeneous comparator.
|
||||
using Base::count;
|
||||
|
||||
// btree_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
|
||||
// `btree_map`.
|
||||
// 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()
|
||||
|
|
@ -391,10 +395,34 @@ class btree_map
|
|||
//
|
||||
// Finds an element with the passed `key` within the `btree_map`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the map is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// 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
|
||||
|
|
@ -652,6 +680,11 @@ class 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).
|
||||
|
|
@ -682,8 +715,8 @@ class btree_multimap
|
|||
// 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 is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||
// heterogeneous comparator.
|
||||
using Base::contains;
|
||||
|
||||
// btree_multimap::count()
|
||||
|
|
@ -693,13 +726,13 @@ class btree_multimap
|
|||
// Returns the number of elements comparing equal to the given `key` within
|
||||
// the `btree_multimap`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the map is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// Supports heterogeneous lookup, provided that the map has a compatible
|
||||
// heterogeneous comparator.
|
||||
using Base::count;
|
||||
|
||||
// btree_multimap::equal_range()
|
||||
//
|
||||
// Returns a closed range [first, last], defined by a `std::pair` of two
|
||||
// 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;
|
||||
|
|
@ -711,10 +744,34 @@ class btree_multimap
|
|||
//
|
||||
// Finds an element with the passed `key` within the `btree_multimap`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the map is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// 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`.
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ class btree_set
|
|||
// 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.
|
||||
// number of elements erased (0 or 1).
|
||||
using Base::erase;
|
||||
|
||||
// btree_set::insert()
|
||||
|
|
@ -300,8 +300,8 @@ class btree_set
|
|||
// 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 is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||
// heterogeneous comparator.
|
||||
using Base::contains;
|
||||
|
||||
// btree_set::count()
|
||||
|
|
@ -312,8 +312,8 @@ class btree_set
|
|||
// 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 is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||
// heterogeneous comparator.
|
||||
using Base::count;
|
||||
|
||||
// btree_set::equal_range()
|
||||
|
|
@ -330,10 +330,32 @@ class btree_set
|
|||
//
|
||||
// Finds an element with the passed `key` within the `btree_set`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the set is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// 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`.
|
||||
|
|
@ -604,8 +626,8 @@ class btree_multiset
|
|||
// 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 is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||
// heterogeneous comparator.
|
||||
using Base::contains;
|
||||
|
||||
// btree_multiset::count()
|
||||
|
|
@ -615,8 +637,8 @@ class btree_multiset
|
|||
// Returns the number of elements comparing equal to the given `key` within
|
||||
// the `btree_multiset`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the set is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// Supports heterogeneous lookup, provided that the set has a compatible
|
||||
// heterogeneous comparator.
|
||||
using Base::count;
|
||||
|
||||
// btree_multiset::equal_range()
|
||||
|
|
@ -633,10 +655,34 @@ class btree_multiset
|
|||
//
|
||||
// Finds an element with the passed `key` within the `btree_multiset`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the set is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
// 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`.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "absl/container/btree_test.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
|
@ -52,7 +53,9 @@ using ::absl::test_internal::MovableOnlyInstance;
|
|||
using ::testing::ElementsAre;
|
||||
using ::testing::ElementsAreArray;
|
||||
using ::testing::IsEmpty;
|
||||
using ::testing::IsNull;
|
||||
using ::testing::Pair;
|
||||
using ::testing::SizeIs;
|
||||
|
||||
template <typename T, typename U>
|
||||
void CheckPairEquals(const T &x, const U &y) {
|
||||
|
|
@ -592,7 +595,7 @@ void BtreeTest() {
|
|||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
const std::vector<V> random_values = GenerateValuesWithSeed<V>(
|
||||
absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values),
|
||||
testing::GTEST_FLAG(random_seed));
|
||||
GTEST_FLAG_GET(random_seed));
|
||||
|
||||
unique_checker<T, C> container;
|
||||
|
||||
|
|
@ -616,7 +619,7 @@ void BtreeMultiTest() {
|
|||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
const std::vector<V> random_values = GenerateValuesWithSeed<V>(
|
||||
absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values),
|
||||
testing::GTEST_FLAG(random_seed));
|
||||
GTEST_FLAG_GET(random_seed));
|
||||
|
||||
multi_checker<T, C> container;
|
||||
|
||||
|
|
@ -1180,6 +1183,103 @@ TEST(Btree, RangeCtorSanity) {
|
|||
EXPECT_EQ(1, tmap.size());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class BtreeNodePeer {
|
||||
public:
|
||||
// Yields the size of a leaf node with a specific number of values.
|
||||
template <typename ValueType>
|
||||
constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) {
|
||||
return btree_node<
|
||||
set_params<ValueType, std::less<ValueType>, std::allocator<ValueType>,
|
||||
/*TargetNodeSize=*/256, // This parameter isn't used here.
|
||||
/*Multi=*/false>>::SizeWithNSlots(target_values_per_node);
|
||||
}
|
||||
|
||||
// Yields the number of slots in a (non-root) leaf node for this btree.
|
||||
template <typename Btree>
|
||||
constexpr static size_t GetNumSlotsPerNode() {
|
||||
return btree_node<typename Btree::params_type>::kNodeSlots;
|
||||
}
|
||||
|
||||
template <typename Btree>
|
||||
constexpr static size_t GetMaxFieldType() {
|
||||
return std::numeric_limits<
|
||||
typename btree_node<typename Btree::params_type>::field_type>::max();
|
||||
}
|
||||
|
||||
template <typename Btree>
|
||||
constexpr static bool UsesLinearNodeSearch() {
|
||||
return btree_node<typename Btree::params_type>::use_linear_search::value;
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
class BtreeMapTest : public ::testing::Test {
|
||||
public:
|
||||
struct Key {};
|
||||
struct Cmp {
|
||||
template <typename T>
|
||||
bool operator()(T, T) const {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct KeyLin {
|
||||
using absl_btree_prefer_linear_node_search = std::true_type;
|
||||
};
|
||||
struct CmpLin : Cmp {
|
||||
using absl_btree_prefer_linear_node_search = std::true_type;
|
||||
};
|
||||
|
||||
struct KeyBin {
|
||||
using absl_btree_prefer_linear_node_search = std::false_type;
|
||||
};
|
||||
struct CmpBin : Cmp {
|
||||
using absl_btree_prefer_linear_node_search = std::false_type;
|
||||
};
|
||||
|
||||
template <typename K, typename C>
|
||||
static bool IsLinear() {
|
||||
return BtreeNodePeer::UsesLinearNodeSearch<absl::btree_map<K, int, C>>();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(BtreeMapTest, TestLinearSearchPreferredForKeyLinearViaAlias) {
|
||||
// Test requesting linear search by directly exporting an alias.
|
||||
EXPECT_FALSE((IsLinear<Key, Cmp>()));
|
||||
EXPECT_TRUE((IsLinear<KeyLin, Cmp>()));
|
||||
EXPECT_TRUE((IsLinear<Key, CmpLin>()));
|
||||
EXPECT_TRUE((IsLinear<KeyLin, CmpLin>()));
|
||||
}
|
||||
|
||||
TEST_F(BtreeMapTest, LinearChoiceTree) {
|
||||
// Cmp has precedence, and is forcing binary
|
||||
EXPECT_FALSE((IsLinear<Key, CmpBin>()));
|
||||
EXPECT_FALSE((IsLinear<KeyLin, CmpBin>()));
|
||||
EXPECT_FALSE((IsLinear<KeyBin, CmpBin>()));
|
||||
EXPECT_FALSE((IsLinear<int, CmpBin>()));
|
||||
EXPECT_FALSE((IsLinear<std::string, CmpBin>()));
|
||||
// Cmp has precedence, and is forcing linear
|
||||
EXPECT_TRUE((IsLinear<Key, CmpLin>()));
|
||||
EXPECT_TRUE((IsLinear<KeyLin, CmpLin>()));
|
||||
EXPECT_TRUE((IsLinear<KeyBin, CmpLin>()));
|
||||
EXPECT_TRUE((IsLinear<int, CmpLin>()));
|
||||
EXPECT_TRUE((IsLinear<std::string, CmpLin>()));
|
||||
// Cmp has no preference, Key determines linear vs binary.
|
||||
EXPECT_FALSE((IsLinear<Key, Cmp>()));
|
||||
EXPECT_TRUE((IsLinear<KeyLin, Cmp>()));
|
||||
EXPECT_FALSE((IsLinear<KeyBin, Cmp>()));
|
||||
// arithmetic key w/ std::less or std::greater: linear
|
||||
EXPECT_TRUE((IsLinear<int, std::less<int>>()));
|
||||
EXPECT_TRUE((IsLinear<double, std::greater<double>>()));
|
||||
// arithmetic key w/ custom compare: binary
|
||||
EXPECT_FALSE((IsLinear<int, Cmp>()));
|
||||
// non-arithmetic key: binary
|
||||
EXPECT_FALSE((IsLinear<std::string, std::less<std::string>>()));
|
||||
}
|
||||
|
||||
TEST(Btree, BtreeMapCanHoldMoveOnlyTypes) {
|
||||
absl::btree_map<std::string, std::unique_ptr<std::string>> m;
|
||||
|
||||
|
|
@ -1325,28 +1425,6 @@ TEST(Btree, RValueInsert) {
|
|||
EXPECT_EQ(tracker.swaps(), 0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class BtreeNodePeer {
|
||||
public:
|
||||
// Yields the size of a leaf node with a specific number of values.
|
||||
template <typename ValueType>
|
||||
constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) {
|
||||
return btree_node<
|
||||
set_params<ValueType, std::less<ValueType>, std::allocator<ValueType>,
|
||||
/*TargetNodeSize=*/256, // This parameter isn't used here.
|
||||
/*Multi=*/false>>::SizeWithNValues(target_values_per_node);
|
||||
}
|
||||
|
||||
// Yields the number of values in a (non-root) leaf node for this set.
|
||||
template <typename Set>
|
||||
constexpr static size_t GetNumValuesPerNode() {
|
||||
return btree_node<typename Set::params_type>::kNodeValues;
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
// A btree set with a specific number of values per node.
|
||||
template <typename Key, int TargetValuesPerNode, typename Cmp = std::less<Key>>
|
||||
class SizedBtreeSet
|
||||
|
|
@ -1380,7 +1458,7 @@ void ExpectOperationCounts(const int expected_moves,
|
|||
TEST(Btree, MovesComparisonsCopiesSwapsTracking) {
|
||||
InstanceTracker tracker;
|
||||
// Note: this is minimum number of values per node.
|
||||
SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/3> set3;
|
||||
SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/4> set4;
|
||||
// Note: this is the default number of values per node for a set of int32s
|
||||
// (with 64-bit pointers).
|
||||
SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/61> set61;
|
||||
|
|
@ -1391,28 +1469,28 @@ TEST(Btree, MovesComparisonsCopiesSwapsTracking) {
|
|||
std::vector<int> values =
|
||||
GenerateValuesWithSeed<int>(10000, 1 << 22, /*seed=*/23);
|
||||
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set3)>(), 3);
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>(), 61);
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set100)>(), 100);
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set4)>(), 4);
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61);
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100);
|
||||
if (sizeof(void *) == 8) {
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<absl::btree_set<int32_t>>(),
|
||||
BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>());
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
|
||||
BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>());
|
||||
}
|
||||
|
||||
// Test key insertion/deletion in random order.
|
||||
ExpectOperationCounts(45281, 132551, values, &tracker, &set3);
|
||||
ExpectOperationCounts(56540, 134212, values, &tracker, &set4);
|
||||
ExpectOperationCounts(386718, 129807, values, &tracker, &set61);
|
||||
ExpectOperationCounts(586761, 130310, values, &tracker, &set100);
|
||||
|
||||
// Test key insertion/deletion in sorted order.
|
||||
std::sort(values.begin(), values.end());
|
||||
ExpectOperationCounts(26638, 92134, values, &tracker, &set3);
|
||||
ExpectOperationCounts(24972, 85563, values, &tracker, &set4);
|
||||
ExpectOperationCounts(20208, 87757, values, &tracker, &set61);
|
||||
ExpectOperationCounts(20124, 96583, values, &tracker, &set100);
|
||||
|
||||
// Test key insertion/deletion in reverse sorted order.
|
||||
std::reverse(values.begin(), values.end());
|
||||
ExpectOperationCounts(49951, 119325, values, &tracker, &set3);
|
||||
ExpectOperationCounts(54949, 127531, values, &tracker, &set4);
|
||||
ExpectOperationCounts(338813, 118266, values, &tracker, &set61);
|
||||
ExpectOperationCounts(534529, 125279, values, &tracker, &set100);
|
||||
}
|
||||
|
|
@ -1429,9 +1507,9 @@ struct MovableOnlyInstanceThreeWayCompare {
|
|||
TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) {
|
||||
InstanceTracker tracker;
|
||||
// Note: this is minimum number of values per node.
|
||||
SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/3,
|
||||
SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/4,
|
||||
MovableOnlyInstanceThreeWayCompare>
|
||||
set3;
|
||||
set4;
|
||||
// Note: this is the default number of values per node for a set of int32s
|
||||
// (with 64-bit pointers).
|
||||
SizedBtreeSet<MovableOnlyInstance, /*TargetValuesPerNode=*/61,
|
||||
|
|
@ -1446,28 +1524,28 @@ TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) {
|
|||
std::vector<int> values =
|
||||
GenerateValuesWithSeed<int>(10000, 1 << 22, /*seed=*/23);
|
||||
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set3)>(), 3);
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>(), 61);
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<decltype(set100)>(), 100);
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set4)>(), 4);
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>(), 61);
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<decltype(set100)>(), 100);
|
||||
if (sizeof(void *) == 8) {
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode<absl::btree_set<int32_t>>(),
|
||||
BtreeNodePeer::GetNumValuesPerNode<decltype(set61)>());
|
||||
EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode<absl::btree_set<int32_t>>(),
|
||||
BtreeNodePeer::GetNumSlotsPerNode<decltype(set61)>());
|
||||
}
|
||||
|
||||
// Test key insertion/deletion in random order.
|
||||
ExpectOperationCounts(45281, 122560, values, &tracker, &set3);
|
||||
ExpectOperationCounts(56540, 124221, values, &tracker, &set4);
|
||||
ExpectOperationCounts(386718, 119816, values, &tracker, &set61);
|
||||
ExpectOperationCounts(586761, 120319, values, &tracker, &set100);
|
||||
|
||||
// Test key insertion/deletion in sorted order.
|
||||
std::sort(values.begin(), values.end());
|
||||
ExpectOperationCounts(26638, 92134, values, &tracker, &set3);
|
||||
ExpectOperationCounts(24972, 85563, values, &tracker, &set4);
|
||||
ExpectOperationCounts(20208, 87757, values, &tracker, &set61);
|
||||
ExpectOperationCounts(20124, 96583, values, &tracker, &set100);
|
||||
|
||||
// Test key insertion/deletion in reverse sorted order.
|
||||
std::reverse(values.begin(), values.end());
|
||||
ExpectOperationCounts(49951, 109326, values, &tracker, &set3);
|
||||
ExpectOperationCounts(54949, 117532, values, &tracker, &set4);
|
||||
ExpectOperationCounts(338813, 108267, values, &tracker, &set61);
|
||||
ExpectOperationCounts(534529, 115280, values, &tracker, &set100);
|
||||
}
|
||||
|
|
@ -1543,7 +1621,7 @@ TEST(Btree, MapAt) {
|
|||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
EXPECT_THROW(map.at(3), std::out_of_range);
|
||||
#else
|
||||
EXPECT_DEATH(map.at(3), "absl::btree_map::at");
|
||||
EXPECT_DEATH_IF_SUPPORTED(map.at(3), "absl::btree_map::at");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1630,10 +1708,25 @@ TEST(Btree, StrSplitCompatible) {
|
|||
EXPECT_EQ(split_set, expected_set);
|
||||
}
|
||||
|
||||
// We can't use EXPECT_EQ/etc. to compare absl::weak_ordering because they
|
||||
// convert literal 0 to int and absl::weak_ordering can only be compared with
|
||||
// literal 0. Defining this function allows for avoiding ClangTidy warnings.
|
||||
bool Identity(const bool b) { return b; }
|
||||
TEST(Btree, KeyComp) {
|
||||
absl::btree_set<int> s;
|
||||
EXPECT_TRUE(s.key_comp()(1, 2));
|
||||
EXPECT_FALSE(s.key_comp()(2, 2));
|
||||
EXPECT_FALSE(s.key_comp()(2, 1));
|
||||
|
||||
absl::btree_map<int, int> m1;
|
||||
EXPECT_TRUE(m1.key_comp()(1, 2));
|
||||
EXPECT_FALSE(m1.key_comp()(2, 2));
|
||||
EXPECT_FALSE(m1.key_comp()(2, 1));
|
||||
|
||||
// Even though we internally adapt the comparator of `m2` to be three-way and
|
||||
// heterogeneous, the comparator we expose through key_comp() is the original
|
||||
// unadapted comparator.
|
||||
absl::btree_map<std::string, int> m2;
|
||||
EXPECT_TRUE(m2.key_comp()("a", "b"));
|
||||
EXPECT_FALSE(m2.key_comp()("b", "b"));
|
||||
EXPECT_FALSE(m2.key_comp()("b", "a"));
|
||||
}
|
||||
|
||||
TEST(Btree, ValueComp) {
|
||||
absl::btree_set<int> s;
|
||||
|
|
@ -1646,13 +1739,13 @@ TEST(Btree, ValueComp) {
|
|||
EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(2, 0)));
|
||||
EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(1, 0)));
|
||||
|
||||
// Even though we internally adapt the comparator of `m2` to be three-way and
|
||||
// heterogeneous, the comparator we expose through value_comp() is based on
|
||||
// the original unadapted comparator.
|
||||
absl::btree_map<std::string, int> m2;
|
||||
EXPECT_TRUE(Identity(
|
||||
m2.value_comp()(std::make_pair("a", 0), std::make_pair("b", 0)) < 0));
|
||||
EXPECT_TRUE(Identity(
|
||||
m2.value_comp()(std::make_pair("b", 0), std::make_pair("b", 0)) == 0));
|
||||
EXPECT_TRUE(Identity(
|
||||
m2.value_comp()(std::make_pair("b", 0), std::make_pair("a", 0)) > 0));
|
||||
EXPECT_TRUE(m2.value_comp()(std::make_pair("a", 0), std::make_pair("b", 0)));
|
||||
EXPECT_FALSE(m2.value_comp()(std::make_pair("b", 0), std::make_pair("b", 0)));
|
||||
EXPECT_FALSE(m2.value_comp()(std::make_pair("b", 0), std::make_pair("a", 0)));
|
||||
}
|
||||
|
||||
TEST(Btree, DefaultConstruction) {
|
||||
|
|
@ -1960,6 +2053,30 @@ TEST(Btree, ExtractAndInsertNodeHandleMultiMap) {
|
|||
EXPECT_EQ(res, ++other.begin());
|
||||
}
|
||||
|
||||
TEST(Btree, ExtractMultiMapEquivalentKeys) {
|
||||
// Note: using string keys means a three-way comparator.
|
||||
absl::btree_multimap<std::string, int> map;
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
for (int j = 0; j < 100; ++j) {
|
||||
map.insert({absl::StrCat(i), j});
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
const std::string key = absl::StrCat(i);
|
||||
auto node_handle = map.extract(key);
|
||||
EXPECT_EQ(node_handle.key(), key);
|
||||
EXPECT_EQ(node_handle.mapped(), 0) << i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
const std::string key = absl::StrCat(i);
|
||||
auto node_handle = map.extract(key);
|
||||
EXPECT_EQ(node_handle.key(), key);
|
||||
EXPECT_EQ(node_handle.mapped(), 1) << i;
|
||||
}
|
||||
}
|
||||
|
||||
// For multisets, insert with hint also affects correctness because we need to
|
||||
// insert immediately before the hint if possible.
|
||||
struct InsertMultiHintData {
|
||||
|
|
@ -2101,6 +2218,31 @@ TEST(Btree, MergeIntoMultiMapsWithDifferentComparators) {
|
|||
Pair(4, 1), Pair(4, 4), Pair(5, 5)));
|
||||
}
|
||||
|
||||
TEST(Btree, MergeIntoSetMovableOnly) {
|
||||
absl::btree_set<MovableOnlyInstance> src;
|
||||
src.insert(MovableOnlyInstance(1));
|
||||
absl::btree_multiset<MovableOnlyInstance> dst1;
|
||||
dst1.insert(MovableOnlyInstance(2));
|
||||
absl::btree_set<MovableOnlyInstance> dst2;
|
||||
|
||||
// Test merge into multiset.
|
||||
dst1.merge(src);
|
||||
|
||||
EXPECT_TRUE(src.empty());
|
||||
// ElementsAre/ElementsAreArray don't work with move-only types.
|
||||
ASSERT_THAT(dst1, SizeIs(2));
|
||||
EXPECT_EQ(*dst1.begin(), MovableOnlyInstance(1));
|
||||
EXPECT_EQ(*std::next(dst1.begin()), MovableOnlyInstance(2));
|
||||
|
||||
// Test merge into set.
|
||||
dst2.merge(dst1);
|
||||
|
||||
EXPECT_TRUE(dst1.empty());
|
||||
ASSERT_THAT(dst2, SizeIs(2));
|
||||
EXPECT_EQ(*dst2.begin(), MovableOnlyInstance(1));
|
||||
EXPECT_EQ(*std::next(dst2.begin()), MovableOnlyInstance(2));
|
||||
}
|
||||
|
||||
struct KeyCompareToWeakOrdering {
|
||||
template <typename T>
|
||||
absl::weak_ordering operator()(const T &a, const T &b) const {
|
||||
|
|
@ -2404,6 +2546,408 @@ TEST(Btree, BitfieldArgument) {
|
|||
m[n];
|
||||
}
|
||||
|
||||
TEST(Btree, SetRangeConstructorAndInsertSupportExplicitConversionComparable) {
|
||||
const absl::string_view names[] = {"n1", "n2"};
|
||||
|
||||
absl::btree_set<std::string> name_set1{std::begin(names), std::end(names)};
|
||||
EXPECT_THAT(name_set1, ElementsAreArray(names));
|
||||
|
||||
absl::btree_set<std::string> name_set2;
|
||||
name_set2.insert(std::begin(names), std::end(names));
|
||||
EXPECT_THAT(name_set2, ElementsAreArray(names));
|
||||
}
|
||||
|
||||
// A type that is explicitly convertible from int and counts constructor calls.
|
||||
struct ConstructorCounted {
|
||||
explicit ConstructorCounted(int i) : i(i) { ++constructor_calls; }
|
||||
bool operator==(int other) const { return i == other; }
|
||||
|
||||
int i;
|
||||
static int constructor_calls;
|
||||
};
|
||||
int ConstructorCounted::constructor_calls = 0;
|
||||
|
||||
struct ConstructorCountedCompare {
|
||||
bool operator()(int a, const ConstructorCounted &b) const { return a < b.i; }
|
||||
bool operator()(const ConstructorCounted &a, int b) const { return a.i < b; }
|
||||
bool operator()(const ConstructorCounted &a,
|
||||
const ConstructorCounted &b) const {
|
||||
return a.i < b.i;
|
||||
}
|
||||
using is_transparent = void;
|
||||
};
|
||||
|
||||
TEST(Btree,
|
||||
SetRangeConstructorAndInsertExplicitConvComparableLimitConstruction) {
|
||||
const int i[] = {0, 1, 1};
|
||||
ConstructorCounted::constructor_calls = 0;
|
||||
|
||||
absl::btree_set<ConstructorCounted, ConstructorCountedCompare> set{
|
||||
std::begin(i), std::end(i)};
|
||||
EXPECT_THAT(set, ElementsAre(0, 1));
|
||||
EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
|
||||
|
||||
set.insert(std::begin(i), std::end(i));
|
||||
EXPECT_THAT(set, ElementsAre(0, 1));
|
||||
EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
|
||||
}
|
||||
|
||||
TEST(Btree,
|
||||
SetRangeConstructorAndInsertSupportExplicitConversionNonComparable) {
|
||||
const int i[] = {0, 1};
|
||||
|
||||
absl::btree_set<std::vector<void *>> s1{std::begin(i), std::end(i)};
|
||||
EXPECT_THAT(s1, ElementsAre(IsEmpty(), ElementsAre(IsNull())));
|
||||
|
||||
absl::btree_set<std::vector<void *>> s2;
|
||||
s2.insert(std::begin(i), std::end(i));
|
||||
EXPECT_THAT(s2, ElementsAre(IsEmpty(), ElementsAre(IsNull())));
|
||||
}
|
||||
|
||||
// libstdc++ included with GCC 4.9 has a bug in the std::pair constructors that
|
||||
// prevents explicit conversions between pair types.
|
||||
// We only run this test for the libstdc++ from GCC 7 or newer because we can't
|
||||
// reliably check the libstdc++ version prior to that release.
|
||||
#if !defined(__GLIBCXX__) || \
|
||||
(defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 7)
|
||||
TEST(Btree, MapRangeConstructorAndInsertSupportExplicitConversionComparable) {
|
||||
const std::pair<absl::string_view, int> names[] = {{"n1", 1}, {"n2", 2}};
|
||||
|
||||
absl::btree_map<std::string, int> name_map1{std::begin(names),
|
||||
std::end(names)};
|
||||
EXPECT_THAT(name_map1, ElementsAre(Pair("n1", 1), Pair("n2", 2)));
|
||||
|
||||
absl::btree_map<std::string, int> name_map2;
|
||||
name_map2.insert(std::begin(names), std::end(names));
|
||||
EXPECT_THAT(name_map2, ElementsAre(Pair("n1", 1), Pair("n2", 2)));
|
||||
}
|
||||
|
||||
TEST(Btree,
|
||||
MapRangeConstructorAndInsertExplicitConvComparableLimitConstruction) {
|
||||
const std::pair<int, int> i[] = {{0, 1}, {1, 2}, {1, 3}};
|
||||
ConstructorCounted::constructor_calls = 0;
|
||||
|
||||
absl::btree_map<ConstructorCounted, int, ConstructorCountedCompare> map{
|
||||
std::begin(i), std::end(i)};
|
||||
EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2)));
|
||||
EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
|
||||
|
||||
map.insert(std::begin(i), std::end(i));
|
||||
EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2)));
|
||||
EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
|
||||
}
|
||||
|
||||
TEST(Btree,
|
||||
MapRangeConstructorAndInsertSupportExplicitConversionNonComparable) {
|
||||
const std::pair<int, int> i[] = {{0, 1}, {1, 2}};
|
||||
|
||||
absl::btree_map<std::vector<void *>, int> m1{std::begin(i), std::end(i)};
|
||||
EXPECT_THAT(m1,
|
||||
ElementsAre(Pair(IsEmpty(), 1), Pair(ElementsAre(IsNull()), 2)));
|
||||
|
||||
absl::btree_map<std::vector<void *>, int> m2;
|
||||
m2.insert(std::begin(i), std::end(i));
|
||||
EXPECT_THAT(m2,
|
||||
ElementsAre(Pair(IsEmpty(), 1), Pair(ElementsAre(IsNull()), 2)));
|
||||
}
|
||||
|
||||
TEST(Btree, HeterogeneousTryEmplace) {
|
||||
absl::btree_map<std::string, int> m;
|
||||
std::string s = "key";
|
||||
absl::string_view sv = s;
|
||||
m.try_emplace(sv, 1);
|
||||
EXPECT_EQ(m[s], 1);
|
||||
|
||||
m.try_emplace(m.end(), sv, 2);
|
||||
EXPECT_EQ(m[s], 1);
|
||||
}
|
||||
|
||||
TEST(Btree, HeterogeneousOperatorMapped) {
|
||||
absl::btree_map<std::string, int> m;
|
||||
std::string s = "key";
|
||||
absl::string_view sv = s;
|
||||
m[sv] = 1;
|
||||
EXPECT_EQ(m[s], 1);
|
||||
|
||||
m[sv] = 2;
|
||||
EXPECT_EQ(m[s], 2);
|
||||
}
|
||||
|
||||
TEST(Btree, HeterogeneousInsertOrAssign) {
|
||||
absl::btree_map<std::string, int> m;
|
||||
std::string s = "key";
|
||||
absl::string_view sv = s;
|
||||
m.insert_or_assign(sv, 1);
|
||||
EXPECT_EQ(m[s], 1);
|
||||
|
||||
m.insert_or_assign(m.end(), sv, 2);
|
||||
EXPECT_EQ(m[s], 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
// This test requires std::launder for mutable key access in node handles.
|
||||
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
|
||||
TEST(Btree, NodeHandleMutableKeyAccess) {
|
||||
{
|
||||
absl::btree_map<std::string, std::string> map;
|
||||
|
||||
map["key1"] = "mapped";
|
||||
|
||||
auto nh = map.extract(map.begin());
|
||||
nh.key().resize(3);
|
||||
map.insert(std::move(nh));
|
||||
|
||||
EXPECT_THAT(map, ElementsAre(Pair("key", "mapped")));
|
||||
}
|
||||
// Also for multimap.
|
||||
{
|
||||
absl::btree_multimap<std::string, std::string> map;
|
||||
|
||||
map.emplace("key1", "mapped");
|
||||
|
||||
auto nh = map.extract(map.begin());
|
||||
nh.key().resize(3);
|
||||
map.insert(std::move(nh));
|
||||
|
||||
EXPECT_THAT(map, ElementsAre(Pair("key", "mapped")));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct MultiKey {
|
||||
int i1;
|
||||
int i2;
|
||||
};
|
||||
|
||||
bool operator==(const MultiKey a, const MultiKey b) {
|
||||
return a.i1 == b.i1 && a.i2 == b.i2;
|
||||
}
|
||||
|
||||
// A heterogeneous comparator that has different equivalence classes for
|
||||
// different lookup types.
|
||||
struct MultiKeyComp {
|
||||
using is_transparent = void;
|
||||
bool operator()(const MultiKey a, const MultiKey b) const {
|
||||
if (a.i1 != b.i1) return a.i1 < b.i1;
|
||||
return a.i2 < b.i2;
|
||||
}
|
||||
bool operator()(const int a, const MultiKey b) const { return a < b.i1; }
|
||||
bool operator()(const MultiKey a, const int b) const { return a.i1 < b; }
|
||||
};
|
||||
|
||||
// A heterogeneous, three-way comparator that has different equivalence classes
|
||||
// for different lookup types.
|
||||
struct MultiKeyThreeWayComp {
|
||||
using is_transparent = void;
|
||||
absl::weak_ordering operator()(const MultiKey a, const MultiKey b) const {
|
||||
if (a.i1 < b.i1) return absl::weak_ordering::less;
|
||||
if (a.i1 > b.i1) return absl::weak_ordering::greater;
|
||||
if (a.i2 < b.i2) return absl::weak_ordering::less;
|
||||
if (a.i2 > b.i2) return absl::weak_ordering::greater;
|
||||
return absl::weak_ordering::equivalent;
|
||||
}
|
||||
absl::weak_ordering operator()(const int a, const MultiKey b) const {
|
||||
if (a < b.i1) return absl::weak_ordering::less;
|
||||
if (a > b.i1) return absl::weak_ordering::greater;
|
||||
return absl::weak_ordering::equivalent;
|
||||
}
|
||||
absl::weak_ordering operator()(const MultiKey a, const int b) const {
|
||||
if (a.i1 < b) return absl::weak_ordering::less;
|
||||
if (a.i1 > b) return absl::weak_ordering::greater;
|
||||
return absl::weak_ordering::equivalent;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Compare>
|
||||
class BtreeMultiKeyTest : public ::testing::Test {};
|
||||
using MultiKeyComps = ::testing::Types<MultiKeyComp, MultiKeyThreeWayComp>;
|
||||
TYPED_TEST_SUITE(BtreeMultiKeyTest, MultiKeyComps);
|
||||
|
||||
TYPED_TEST(BtreeMultiKeyTest, EqualRange) {
|
||||
absl::btree_set<MultiKey, TypeParam> set;
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
for (int j = 0; j < 100; ++j) {
|
||||
set.insert({i, j});
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
auto equal_range = set.equal_range(i);
|
||||
EXPECT_EQ(equal_range.first->i1, i);
|
||||
EXPECT_EQ(equal_range.first->i2, 0) << i;
|
||||
EXPECT_EQ(std::distance(equal_range.first, equal_range.second), 100) << i;
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(BtreeMultiKeyTest, Extract) {
|
||||
absl::btree_set<MultiKey, TypeParam> set;
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
for (int j = 0; j < 100; ++j) {
|
||||
set.insert({i, j});
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
auto node_handle = set.extract(i);
|
||||
EXPECT_EQ(node_handle.value().i1, i);
|
||||
EXPECT_EQ(node_handle.value().i2, 0) << i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
auto node_handle = set.extract(i);
|
||||
EXPECT_EQ(node_handle.value().i1, i);
|
||||
EXPECT_EQ(node_handle.value().i2, 1) << i;
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(BtreeMultiKeyTest, Erase) {
|
||||
absl::btree_set<MultiKey, TypeParam> set = {
|
||||
{1, 1}, {2, 1}, {2, 2}, {3, 1}};
|
||||
EXPECT_EQ(set.erase(2), 2);
|
||||
EXPECT_THAT(set, ElementsAre(MultiKey{1, 1}, MultiKey{3, 1}));
|
||||
}
|
||||
|
||||
TYPED_TEST(BtreeMultiKeyTest, Count) {
|
||||
const absl::btree_set<MultiKey, TypeParam> set = {
|
||||
{1, 1}, {2, 1}, {2, 2}, {3, 1}};
|
||||
EXPECT_EQ(set.count(2), 2);
|
||||
}
|
||||
|
||||
TEST(Btree, AllocConstructor) {
|
||||
using Alloc = CountingAllocator<int>;
|
||||
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||
int64_t bytes_used = 0;
|
||||
Alloc alloc(&bytes_used);
|
||||
Set set(alloc);
|
||||
|
||||
set.insert({1, 2, 3});
|
||||
|
||||
EXPECT_THAT(set, ElementsAre(1, 2, 3));
|
||||
EXPECT_GT(bytes_used, set.size() * sizeof(int));
|
||||
}
|
||||
|
||||
TEST(Btree, AllocInitializerListConstructor) {
|
||||
using Alloc = CountingAllocator<int>;
|
||||
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||
int64_t bytes_used = 0;
|
||||
Alloc alloc(&bytes_used);
|
||||
Set set({1, 2, 3}, alloc);
|
||||
|
||||
EXPECT_THAT(set, ElementsAre(1, 2, 3));
|
||||
EXPECT_GT(bytes_used, set.size() * sizeof(int));
|
||||
}
|
||||
|
||||
TEST(Btree, AllocRangeConstructor) {
|
||||
using Alloc = CountingAllocator<int>;
|
||||
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||
int64_t bytes_used = 0;
|
||||
Alloc alloc(&bytes_used);
|
||||
std::vector<int> v = {1, 2, 3};
|
||||
Set set(v.begin(), v.end(), alloc);
|
||||
|
||||
EXPECT_THAT(set, ElementsAre(1, 2, 3));
|
||||
EXPECT_GT(bytes_used, set.size() * sizeof(int));
|
||||
}
|
||||
|
||||
TEST(Btree, AllocCopyConstructor) {
|
||||
using Alloc = CountingAllocator<int>;
|
||||
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||
int64_t bytes_used1 = 0;
|
||||
Alloc alloc1(&bytes_used1);
|
||||
Set set1(alloc1);
|
||||
|
||||
set1.insert({1, 2, 3});
|
||||
|
||||
int64_t bytes_used2 = 0;
|
||||
Alloc alloc2(&bytes_used2);
|
||||
Set set2(set1, alloc2);
|
||||
|
||||
EXPECT_THAT(set1, ElementsAre(1, 2, 3));
|
||||
EXPECT_THAT(set2, ElementsAre(1, 2, 3));
|
||||
EXPECT_GT(bytes_used1, set1.size() * sizeof(int));
|
||||
EXPECT_EQ(bytes_used1, bytes_used2);
|
||||
}
|
||||
|
||||
TEST(Btree, AllocMoveConstructor_SameAlloc) {
|
||||
using Alloc = CountingAllocator<int>;
|
||||
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||
int64_t bytes_used = 0;
|
||||
Alloc alloc(&bytes_used);
|
||||
Set set1(alloc);
|
||||
|
||||
set1.insert({1, 2, 3});
|
||||
|
||||
const int64_t original_bytes_used = bytes_used;
|
||||
EXPECT_GT(original_bytes_used, set1.size() * sizeof(int));
|
||||
|
||||
Set set2(std::move(set1), alloc);
|
||||
|
||||
EXPECT_THAT(set2, ElementsAre(1, 2, 3));
|
||||
EXPECT_EQ(bytes_used, original_bytes_used);
|
||||
}
|
||||
|
||||
TEST(Btree, AllocMoveConstructor_DifferentAlloc) {
|
||||
using Alloc = CountingAllocator<int>;
|
||||
using Set = absl::btree_set<int, std::less<int>, Alloc>;
|
||||
int64_t bytes_used1 = 0;
|
||||
Alloc alloc1(&bytes_used1);
|
||||
Set set1(alloc1);
|
||||
|
||||
set1.insert({1, 2, 3});
|
||||
|
||||
const int64_t original_bytes_used = bytes_used1;
|
||||
EXPECT_GT(original_bytes_used, set1.size() * sizeof(int));
|
||||
|
||||
int64_t bytes_used2 = 0;
|
||||
Alloc alloc2(&bytes_used2);
|
||||
Set set2(std::move(set1), alloc2);
|
||||
|
||||
EXPECT_THAT(set2, ElementsAre(1, 2, 3));
|
||||
// We didn't free these bytes allocated by `set1` yet.
|
||||
EXPECT_EQ(bytes_used1, original_bytes_used);
|
||||
EXPECT_EQ(bytes_used2, original_bytes_used);
|
||||
}
|
||||
|
||||
bool IntCmp(const int a, const int b) { return a < b; }
|
||||
|
||||
TEST(Btree, SupportsFunctionPtrComparator) {
|
||||
absl::btree_set<int, decltype(IntCmp) *> set(IntCmp);
|
||||
set.insert({1, 2, 3});
|
||||
EXPECT_THAT(set, ElementsAre(1, 2, 3));
|
||||
EXPECT_TRUE(set.key_comp()(1, 2));
|
||||
EXPECT_TRUE(set.value_comp()(1, 2));
|
||||
|
||||
absl::btree_map<int, int, decltype(IntCmp) *> map(&IntCmp);
|
||||
map[1] = 1;
|
||||
EXPECT_THAT(map, ElementsAre(Pair(1, 1)));
|
||||
EXPECT_TRUE(map.key_comp()(1, 2));
|
||||
EXPECT_TRUE(map.value_comp()(std::make_pair(1, 1), std::make_pair(2, 2)));
|
||||
}
|
||||
|
||||
template <typename Compare>
|
||||
struct TransparentPassThroughComp {
|
||||
using is_transparent = void;
|
||||
|
||||
// This will fail compilation if we attempt a comparison that Compare does not
|
||||
// support, and the failure will happen inside the function implementation so
|
||||
// it can't be avoided by using SFINAE on this comparator.
|
||||
template <typename T, typename U>
|
||||
bool operator()(const T &lhs, const U &rhs) const {
|
||||
return Compare()(lhs, rhs);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Btree,
|
||||
SupportsTransparentComparatorThatDoesNotImplementAllVisibleOperators) {
|
||||
absl::btree_set<MultiKey, TransparentPassThroughComp<MultiKeyComp>> set;
|
||||
set.insert(MultiKey{1, 2});
|
||||
EXPECT_TRUE(set.contains(1));
|
||||
}
|
||||
|
||||
TEST(Btree, ConstructImplicitlyWithUnadaptedComparator) {
|
||||
absl::btree_set<MultiKey, MultiKeyComp> set = {{}, MultiKeyComp{}};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#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"
|
||||
|
|
@ -72,11 +73,6 @@ constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
|
|||
// 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`.
|
||||
//
|
||||
// Note that `FixedArray` does not provide a public allocator; if it requires a
|
||||
// heap allocation, it will do so with global `::operator new[]()` and
|
||||
// `::operator delete[]()`, even if T provides class-scope overrides for these
|
||||
// operators.
|
||||
template <typename T, size_t N = kFixedArrayUseDefault,
|
||||
typename A = std::allocator<T>>
|
||||
class FixedArray {
|
||||
|
|
@ -106,13 +102,13 @@ class FixedArray {
|
|||
|
||||
public:
|
||||
using allocator_type = typename AllocatorTraits::allocator_type;
|
||||
using value_type = typename allocator_type::value_type;
|
||||
using pointer = typename allocator_type::pointer;
|
||||
using const_pointer = typename allocator_type::const_pointer;
|
||||
using reference = typename allocator_type::reference;
|
||||
using const_reference = typename allocator_type::const_reference;
|
||||
using size_type = typename allocator_type::size_type;
|
||||
using difference_type = typename allocator_type::difference_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>;
|
||||
|
|
@ -231,8 +227,8 @@ class FixedArray {
|
|||
|
||||
// FixedArray::at
|
||||
//
|
||||
// Bounds-checked access. Returns a reference to the ith element of the
|
||||
// fiexed array, or throws std::out_of_range
|
||||
// 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");
|
||||
|
|
@ -422,10 +418,10 @@ class FixedArray {
|
|||
void AnnotateConstruct(size_type n);
|
||||
void AnnotateDestruct(size_type n);
|
||||
|
||||
#ifdef ADDRESS_SANITIZER
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
void* RedzoneBegin() { return &redzone_begin_; }
|
||||
void* RedzoneEnd() { return &redzone_end_ + 1; }
|
||||
#endif // ADDRESS_SANITIZER
|
||||
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||
|
||||
private:
|
||||
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
|
||||
|
|
@ -503,22 +499,26 @@ constexpr typename FixedArray<T, N, A>::size_type
|
|||
template <typename T, size_t N, typename A>
|
||||
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
|
||||
typename FixedArray<T, N, A>::size_type n) {
|
||||
#ifdef ADDRESS_SANITIZER
|
||||
#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 // ADDRESS_SANITIZER
|
||||
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 ADDRESS_SANITIZER
|
||||
#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 // ADDRESS_SANITIZER
|
||||
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
|
||||
|
|
|
|||
|
|
@ -150,8 +150,7 @@ TEST(FixedArrayExceptionSafety, InitListConstructorWithAlloc) {
|
|||
|
||||
template <typename FixedArrT>
|
||||
testing::AssertionResult ReadMemory(FixedArrT* fixed_arr) {
|
||||
// Marked volatile to prevent optimization. Used for running asan tests.
|
||||
volatile int sum = 0;
|
||||
int sum = 0;
|
||||
for (const auto& thrower : *fixed_arr) {
|
||||
sum += thrower.Get();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@
|
|||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/exception_testing.h"
|
||||
#include "absl/base/options.h"
|
||||
#include "absl/container/internal/counting_allocator.h"
|
||||
#include "absl/hash/hash_testing.h"
|
||||
#include "absl/memory/memory.h"
|
||||
|
||||
|
|
@ -638,70 +640,9 @@ TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) {
|
|||
}
|
||||
#endif // __GNUC__
|
||||
|
||||
// This is a stateful allocator, but the state lives outside of the
|
||||
// allocator (in whatever test is using the allocator). This is odd
|
||||
// but helps in tests where the allocator is propagated into nested
|
||||
// containers - that chain of allocators uses the same state and is
|
||||
// thus easier to query for aggregate allocation information.
|
||||
template <typename T>
|
||||
class CountingAllocator : public std::allocator<T> {
|
||||
public:
|
||||
using Alloc = std::allocator<T>;
|
||||
using pointer = typename Alloc::pointer;
|
||||
using size_type = typename Alloc::size_type;
|
||||
|
||||
CountingAllocator() : bytes_used_(nullptr), instance_count_(nullptr) {}
|
||||
explicit CountingAllocator(int64_t* b)
|
||||
: bytes_used_(b), instance_count_(nullptr) {}
|
||||
CountingAllocator(int64_t* b, int64_t* a)
|
||||
: bytes_used_(b), instance_count_(a) {}
|
||||
|
||||
template <typename U>
|
||||
explicit CountingAllocator(const CountingAllocator<U>& x)
|
||||
: Alloc(x),
|
||||
bytes_used_(x.bytes_used_),
|
||||
instance_count_(x.instance_count_) {}
|
||||
|
||||
pointer allocate(size_type n, const void* const hint = nullptr) {
|
||||
assert(bytes_used_ != nullptr);
|
||||
*bytes_used_ += n * sizeof(T);
|
||||
return Alloc::allocate(n, hint);
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type n) {
|
||||
Alloc::deallocate(p, n);
|
||||
assert(bytes_used_ != nullptr);
|
||||
*bytes_used_ -= n * sizeof(T);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void construct(pointer p, Args&&... args) {
|
||||
Alloc::construct(p, absl::forward<Args>(args)...);
|
||||
if (instance_count_) {
|
||||
*instance_count_ += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void destroy(pointer p) {
|
||||
Alloc::destroy(p);
|
||||
if (instance_count_) {
|
||||
*instance_count_ -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
class rebind {
|
||||
public:
|
||||
using other = CountingAllocator<U>;
|
||||
};
|
||||
|
||||
int64_t* bytes_used_;
|
||||
int64_t* instance_count_;
|
||||
};
|
||||
|
||||
TEST(AllocatorSupportTest, CountInlineAllocations) {
|
||||
constexpr size_t inlined_size = 4;
|
||||
using Alloc = CountingAllocator<int>;
|
||||
using Alloc = absl::container_internal::CountingAllocator<int>;
|
||||
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
|
||||
|
||||
int64_t allocated = 0;
|
||||
|
|
@ -722,7 +663,7 @@ TEST(AllocatorSupportTest, CountInlineAllocations) {
|
|||
|
||||
TEST(AllocatorSupportTest, CountOutoflineAllocations) {
|
||||
constexpr size_t inlined_size = 4;
|
||||
using Alloc = CountingAllocator<int>;
|
||||
using Alloc = absl::container_internal::CountingAllocator<int>;
|
||||
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
|
||||
|
||||
int64_t allocated = 0;
|
||||
|
|
@ -743,7 +684,7 @@ TEST(AllocatorSupportTest, CountOutoflineAllocations) {
|
|||
|
||||
TEST(AllocatorSupportTest, CountCopyInlineAllocations) {
|
||||
constexpr size_t inlined_size = 4;
|
||||
using Alloc = CountingAllocator<int>;
|
||||
using Alloc = absl::container_internal::CountingAllocator<int>;
|
||||
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
|
||||
|
||||
int64_t allocated1 = 0;
|
||||
|
|
@ -771,7 +712,7 @@ TEST(AllocatorSupportTest, CountCopyInlineAllocations) {
|
|||
|
||||
TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) {
|
||||
constexpr size_t inlined_size = 4;
|
||||
using Alloc = CountingAllocator<int>;
|
||||
using Alloc = absl::container_internal::CountingAllocator<int>;
|
||||
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
|
||||
|
||||
int64_t allocated1 = 0;
|
||||
|
|
@ -803,7 +744,7 @@ TEST(AllocatorSupportTest, SizeValAllocConstructor) {
|
|||
using testing::SizeIs;
|
||||
|
||||
constexpr size_t inlined_size = 4;
|
||||
using Alloc = CountingAllocator<int>;
|
||||
using Alloc = absl::container_internal::CountingAllocator<int>;
|
||||
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
|
||||
|
||||
{
|
||||
|
|
@ -827,16 +768,16 @@ TEST(AllocatorSupportTest, SizeValAllocConstructor) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef ADDRESS_SANITIZER
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
|
||||
absl::FixedArray<int, 32> a(10);
|
||||
int* raw = a.data();
|
||||
raw[0] = 0;
|
||||
raw[9] = 0;
|
||||
EXPECT_DEATH(raw[-2] = 0, "container-overflow");
|
||||
EXPECT_DEATH(raw[-1] = 0, "container-overflow");
|
||||
EXPECT_DEATH(raw[10] = 0, "container-overflow");
|
||||
EXPECT_DEATH(raw[31] = 0, "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[-2] = 0, "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[10] = 0, "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[31] = 0, "container-overflow");
|
||||
}
|
||||
|
||||
TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
|
||||
|
|
@ -844,10 +785,10 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
|
|||
char* raw = a.data();
|
||||
raw[0] = 0;
|
||||
raw[11] = 0;
|
||||
EXPECT_DEATH(raw[-7] = 0, "container-overflow");
|
||||
EXPECT_DEATH(raw[-1] = 0, "container-overflow");
|
||||
EXPECT_DEATH(raw[12] = 0, "container-overflow");
|
||||
EXPECT_DEATH(raw[17] = 0, "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[-7] = 0, "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[12] = 0, "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[17] = 0, "container-overflow");
|
||||
}
|
||||
|
||||
TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
|
||||
|
|
@ -855,8 +796,8 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
|
|||
uint64_t* raw = a.data();
|
||||
raw[0] = 0;
|
||||
raw[19] = 0;
|
||||
EXPECT_DEATH(raw[-1] = 0, "container-overflow");
|
||||
EXPECT_DEATH(raw[20] = 0, "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[20] = 0, "container-overflow");
|
||||
}
|
||||
|
||||
TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
|
||||
|
|
@ -868,13 +809,13 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
|
|||
// there is only a 8-byte red zone before the container range, so we only
|
||||
// access the last 4 bytes of the struct to make sure it stays within the red
|
||||
// zone.
|
||||
EXPECT_DEATH(raw[-1].z_ = 0, "container-overflow");
|
||||
EXPECT_DEATH(raw[10] = ThreeInts(), "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[-1].z_ = 0, "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[10] = ThreeInts(), "container-overflow");
|
||||
// The actual size of storage is kDefaultBytes=256, 21*12 = 252,
|
||||
// so reading raw[21] should still trigger the correct warning.
|
||||
EXPECT_DEATH(raw[21] = ThreeInts(), "container-overflow");
|
||||
EXPECT_DEATH_IF_SUPPORTED(raw[21] = ThreeInts(), "container-overflow");
|
||||
}
|
||||
#endif // ADDRESS_SANITIZER
|
||||
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||
|
||||
TEST(FixedArrayTest, AbslHashValueWorks) {
|
||||
using V = absl::FixedArray<int>;
|
||||
|
|
|
|||
|
|
@ -234,7 +234,8 @@ class flat_hash_map : public absl::container_internal::raw_hash_map<
|
|||
//
|
||||
// size_type erase(const key_type& key):
|
||||
//
|
||||
// Erases the element with the matching key, if it exists.
|
||||
// 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()
|
||||
|
|
@ -383,6 +384,11 @@ class flat_hash_map : public absl::container_internal::raw_hash_map<
|
|||
// 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()
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/container/internal/hash_generator_testing.h"
|
||||
#include "absl/container/internal/unordered_map_constructor_test.h"
|
||||
#include "absl/container/internal/unordered_map_lookup_test.h"
|
||||
|
|
@ -34,6 +35,19 @@ using ::testing::IsEmpty;
|
|||
using ::testing::Pair;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
|
||||
// Check that absl::flat_hash_map works in a global constructor.
|
||||
struct BeforeMain {
|
||||
BeforeMain() {
|
||||
absl::flat_hash_map<int, int> x;
|
||||
x.insert({1, 1});
|
||||
ABSL_RAW_CHECK(x.find(0) == x.end(), "x should not contain 0");
|
||||
auto it = x.find(1);
|
||||
ABSL_RAW_CHECK(it != x.end(), "x should contain 1");
|
||||
ABSL_RAW_CHECK(it->second, "1 should map to 1");
|
||||
}
|
||||
};
|
||||
const BeforeMain before_main;
|
||||
|
||||
template <class K, class V>
|
||||
using Map = flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual,
|
||||
Alloc<std::pair<const K, V>>>;
|
||||
|
|
@ -253,6 +267,47 @@ TEST(FlatHashMap, EraseIf) {
|
|||
}
|
||||
}
|
||||
|
||||
// This test requires std::launder for mutable key access in node handles.
|
||||
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
|
||||
TEST(FlatHashMap, NodeHandleMutableKeyAccess) {
|
||||
flat_hash_map<std::string, std::string> map;
|
||||
|
||||
map["key1"] = "mapped";
|
||||
|
||||
auto nh = map.extract(map.begin());
|
||||
nh.key().resize(3);
|
||||
map.insert(std::move(nh));
|
||||
|
||||
EXPECT_THAT(map, testing::ElementsAre(Pair("key", "mapped")));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(FlatHashMap, Reserve) {
|
||||
// Verify that if we reserve(size() + n) then we can perform n insertions
|
||||
// without a rehash, i.e., without invalidating any references.
|
||||
for (size_t trial = 0; trial < 20; ++trial) {
|
||||
for (size_t initial = 3; initial < 100; ++initial) {
|
||||
// Fill in `initial` entries, then erase 2 of them, then reserve space for
|
||||
// two inserts and check for reference stability while doing the inserts.
|
||||
flat_hash_map<size_t, size_t> map;
|
||||
for (size_t i = 0; i < initial; ++i) {
|
||||
map[i] = i;
|
||||
}
|
||||
map.erase(0);
|
||||
map.erase(1);
|
||||
map.reserve(map.size() + 2);
|
||||
size_t& a2 = map[2];
|
||||
// In the event of a failure, asan will complain in one of these two
|
||||
// assignments.
|
||||
map[initial] = a2;
|
||||
map[initial + 1] = a2;
|
||||
// Fail even when not under asan:
|
||||
size_t& a2new = map[2];
|
||||
EXPECT_EQ(&a2, &a2new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
|
|
|
|||
|
|
@ -227,7 +227,8 @@ class flat_hash_set
|
|||
//
|
||||
// size_type erase(const key_type& key):
|
||||
//
|
||||
// Erases the element with the matching key, if it exists.
|
||||
// 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()
|
||||
|
|
@ -323,7 +324,7 @@ class flat_hash_set
|
|||
|
||||
// flat_hash_set::merge()
|
||||
//
|
||||
// Extracts elements from a given `source` flat hash map into this
|
||||
// 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;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/container/internal/hash_generator_testing.h"
|
||||
#include "absl/container/internal/unordered_set_constructor_test.h"
|
||||
#include "absl/container/internal/unordered_set_lookup_test.h"
|
||||
|
|
@ -36,6 +37,17 @@ using ::testing::Pointee;
|
|||
using ::testing::UnorderedElementsAre;
|
||||
using ::testing::UnorderedElementsAreArray;
|
||||
|
||||
// Check that absl::flat_hash_set works in a global constructor.
|
||||
struct BeforeMain {
|
||||
BeforeMain() {
|
||||
absl::flat_hash_set<int> x;
|
||||
x.insert(1);
|
||||
ABSL_RAW_CHECK(!x.contains(0), "x should not contain 0");
|
||||
ABSL_RAW_CHECK(x.contains(1), "x should contain 1");
|
||||
}
|
||||
};
|
||||
const BeforeMain before_main;
|
||||
|
||||
template <class T>
|
||||
using Set =
|
||||
absl::flat_hash_set<T, StatefulTestingHash, StatefulTestingEqual, Alloc<T>>;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue