| |
| out2x |
| 8build/make/tools/ide_query/prober_scripts/cpp/general.cc8build/make/tools/ide_query/prober_scripts/cpp/general.cc:ô |
| 8build/make/tools/ide_query/prober_scripts/cpp/general.cc8build/make/tools/ide_query/prober_scripts/cpp/general.cc"8prebuilts/clang/host/linux-x86/clang-r584948/bin/clang++"-nostdlibinc"-mthumb"-Os"-fomit-frame-pointer"-mllvm"-enable-shrink-wrap=false"-O2"-Wall"-Wextra"-Wpointer-arith"-Wunguarded-availability"-Werror=bool-operation"-Werror=date-time"-Werror=int-conversion"-Werror=multichar"-Werror=pragma-pack"&-Werror=pragma-pack-suspicious-include"-Werror=sizeof-array-div" -Werror=sizeof-pointer-memaccess"-Werror=string-plus-int"'-Werror=unreachable-code-loop-increment""-Wno-error=deprecated-declarations"-Wno-c23-extensions"-Wno-c99-designator"-Wno-gnu-folding-constant""-Wno-inconsistent-missing-override"-Wno-error=reorder-init-list"-Wno-reorder-init-list"-Wno-sign-compare"-Wno-unused" -DANDROID"-DNDEBUG"-UDEBUG"(-D__compiler_offsetof=__builtin_offsetof"*-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__" -faddrsig"-fdebug-default-version=5"-fcolor-diagnostics"-ffp-contract=off"-fno-exceptions"-fno-strict-aliasing"-fmessage-length=0"-gsimple-template-names"-gz=zstd"-no-canonical-prefixes""-fdebug-prefix-map=/proc/self/cwd="-ftrivial-auto-var-init=zero"-g"-ffunction-sections"-fdata-sections"-fno-short-enums"-funwind-tables"-fstack-protector-strong"-Wa,--noexecstack"-D_FORTIFY_SOURCE=3"-Werror=non-virtual-dtor"-Werror=address"-Werror=sequence-point"-Werror=format-security"-msoft-float"-march=armv7-a"-mfloat-abi=softfp" |
| -mfpu=neon"/-Ibuild/make/tools/ide_query/prober_scripts/cpp"³-Iout/soong/.intermediates/build/make/tools/ide_query/prober_scripts/cpp/ide_query_proberscript_cc/android_arm_armv7-a-neon/gen/proto/build/make/tools/ide_query/prober_scripts/cpp"
-Iout/soong/.intermediates/build/make/tools/ide_query/prober_scripts/cpp/ide_query_proberscript_cc/android_arm_armv7-a-neon/gen/proto"-D__LIBC_API__=10000"-D__LIBM_API__=10000"-D__LIBDL_API__=10000"-Iexternal/protobuf/src"*-Iexternal/protobuf/third_party/utf8_range"k-Iout/soong/.intermediates/external/abseil-cpp/absl_base_config_hdrs/gen/external/abseil-cpp/my_include_dir"W-Iout/soong/.intermediates/external/abseil-cpp/absl_base_config_hdrs/gen/my_include_dir"q-Iout/soong/.intermediates/external/abseil-cpp/absl_base_core_headers_hdrs/gen/external/abseil-cpp/my_include_dir"]-Iout/soong/.intermediates/external/abseil-cpp/absl_base_core_headers_hdrs/gen/my_include_dir"x-Iout/soong/.intermediates/external/abseil-cpp/absl_base_dynamic_annotations_hdrs/gen/external/abseil-cpp/my_include_dir"d-Iout/soong/.intermediates/external/abseil-cpp/absl_base_dynamic_annotations_hdrs/gen/my_include_dir"p-Iout/soong/.intermediates/external/abseil-cpp/absl_meta_type_traits_hdrs/gen/external/abseil-cpp/my_include_dir"\-Iout/soong/.intermediates/external/abseil-cpp/absl_meta_type_traits_hdrs/gen/my_include_dir"g-Iout/soong/.intermediates/external/abseil-cpp/absl_utility_hdrs/gen/external/abseil-cpp/my_include_dir"S-Iout/soong/.intermediates/external/abseil-cpp/absl_utility_hdrs/gen/my_include_dir"n-Iout/soong/.intermediates/external/abseil-cpp/absl_types_optional_hdrs/gen/external/abseil-cpp/my_include_dir"Z-Iout/soong/.intermediates/external/abseil-cpp/absl_types_optional_hdrs/gen/my_include_dir"p-Iout/soong/.intermediates/external/abseil-cpp/absl_container_common_hdrs/gen/external/abseil-cpp/my_include_dir"\-Iout/soong/.intermediates/external/abseil-cpp/absl_container_common_hdrs/gen/my_include_dir"~-Iout/soong/.intermediates/external/abseil-cpp/absl_container_common_policy_traits_hdrs/gen/external/abseil-cpp/my_include_dir"j-Iout/soong/.intermediates/external/abseil-cpp/absl_container_common_policy_traits_hdrs/gen/my_include_dir"z-Iout/soong/.intermediates/external/abseil-cpp/absl_container_compressed_tuple_hdrs/gen/external/abseil-cpp/my_include_dir"f-Iout/soong/.intermediates/external/abseil-cpp/absl_container_compressed_tuple_hdrs/gen/my_include_dir"f-Iout/soong/.intermediates/external/abseil-cpp/absl_memory_hdrs/gen/external/abseil-cpp/my_include_dir"R-Iout/soong/.intermediates/external/abseil-cpp/absl_memory_hdrs/gen/my_include_dir"z-Iout/soong/.intermediates/external/abseil-cpp/absl_container_container_memory_hdrs/gen/external/abseil-cpp/my_include_dir"f-Iout/soong/.intermediates/external/abseil-cpp/absl_container_container_memory_hdrs/gen/my_include_dir"p-Iout/soong/.intermediates/external/abseil-cpp/absl_base_atomic_hook_hdrs/gen/external/abseil-cpp/my_include_dir"\-Iout/soong/.intermediates/external/abseil-cpp/absl_base_atomic_hook_hdrs/gen/my_include_dir"r-Iout/soong/.intermediates/external/abseil-cpp/absl_base_base_internal_hdrs/gen/external/abseil-cpp/my_include_dir"^-Iout/soong/.intermediates/external/abseil-cpp/absl_base_base_internal_hdrs/gen/my_include_dir"x-Iout/soong/.intermediates/external/abseil-cpp/absl_base_cycleclock_internal_hdrs/gen/external/abseil-cpp/my_include_dir"d-Iout/soong/.intermediates/external/abseil-cpp/absl_base_cycleclock_internal_hdrs/gen/my_include_dir"q-Iout/soong/.intermediates/external/abseil-cpp/absl_base_log_severity_hdrs/gen/external/abseil-cpp/my_include_dir"]-Iout/soong/.intermediates/external/abseil-cpp/absl_base_log_severity_hdrs/gen/my_include_dir"p-Iout/soong/.intermediates/external/abseil-cpp/absl_base_nullability_hdrs/gen/external/abseil-cpp/my_include_dir"\-Iout/soong/.intermediates/external/abseil-cpp/absl_base_nullability_hdrs/gen/my_include_dir"p-Iout/soong/.intermediates/external/abseil-cpp/absl_base_errno_saver_hdrs/gen/external/abseil-cpp/my_include_dir"\-Iout/soong/.intermediates/external/abseil-cpp/absl_base_errno_saver_hdrs/gen/my_include_dir"y-Iout/soong/.intermediates/external/abseil-cpp/absl_base_raw_logging_internal_hdrs/gen/external/abseil-cpp/my_include_dir"e-Iout/soong/.intermediates/external/abseil-cpp/absl_base_raw_logging_internal_hdrs/gen/my_include_dir"r-Iout/soong/.intermediates/external/abseil-cpp/absl_base_spinlock_wait_hdrs/gen/external/abseil-cpp/my_include_dir"^-Iout/soong/.intermediates/external/abseil-cpp/absl_base_spinlock_wait_hdrs/gen/my_include_dir"d-Iout/soong/.intermediates/external/abseil-cpp/absl_base_hdrs/gen/external/abseil-cpp/my_include_dir"P-Iout/soong/.intermediates/external/abseil-cpp/absl_base_hdrs/gen/my_include_dir"k-Iout/soong/.intermediates/external/abseil-cpp/absl_base_endian_hdrs/gen/external/abseil-cpp/my_include_dir"W-Iout/soong/.intermediates/external/abseil-cpp/absl_base_endian_hdrs/gen/my_include_dir"l-Iout/soong/.intermediates/external/abseil-cpp/absl_numeric_bits_hdrs/gen/external/abseil-cpp/my_include_dir"X-Iout/soong/.intermediates/external/abseil-cpp/absl_numeric_bits_hdrs/gen/my_include_dir"-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_bounded_utf8_length_sequence_hdrs/gen/external/abseil-cpp/my_include_dir"r-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_bounded_utf8_length_sequence_hdrs/gen/my_include_dir"}-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_utf8_for_code_point_hdrs/gen/external/abseil-cpp/my_include_dir"i-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_utf8_for_code_point_hdrs/gen/my_include_dir"~-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_decode_rust_punycode_hdrs/gen/external/abseil-cpp/my_include_dir"j-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_decode_rust_punycode_hdrs/gen/my_include_dir"w-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_demangle_rust_hdrs/gen/external/abseil-cpp/my_include_dir"c-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_demangle_rust_hdrs/gen/my_include_dir"{-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_demangle_internal_hdrs/gen/external/abseil-cpp/my_include_dir"g-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_demangle_internal_hdrs/gen/my_include_dir"s-Iout/soong/.intermediates/external/abseil-cpp/absl_base_throw_delegate_hdrs/gen/external/abseil-cpp/my_include_dir"_-Iout/soong/.intermediates/external/abseil-cpp/absl_base_throw_delegate_hdrs/gen/my_include_dir"s-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_string_view_hdrs/gen/external/abseil-cpp/my_include_dir"_-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_string_view_hdrs/gen/my_include_dir"o-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_charset_hdrs/gen/external/abseil-cpp/my_include_dir"[-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_charset_hdrs/gen/my_include_dir"p-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_internal_hdrs/gen/external/abseil-cpp/my_include_dir"\-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_internal_hdrs/gen/my_include_dir"}-Iout/soong/.intermediates/external/abseil-cpp/absl_base_iterator_traits_internal_hdrs/gen/external/abseil-cpp/my_include_dir"i-Iout/soong/.intermediates/external/abseil-cpp/absl_base_iterator_traits_internal_hdrs/gen/my_include_dir"m-Iout/soong/.intermediates/external/abseil-cpp/absl_types_compare_hdrs/gen/external/abseil-cpp/my_include_dir"Y-Iout/soong/.intermediates/external/abseil-cpp/absl_types_compare_hdrs/gen/my_include_dir"n-Iout/soong/.intermediates/external/abseil-cpp/absl_numeric_int128_hdrs/gen/external/abseil-cpp/my_include_dir"Z-Iout/soong/.intermediates/external/abseil-cpp/absl_numeric_int128_hdrs/gen/my_include_dir"g-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_hdrs/gen/external/abseil-cpp/my_include_dir"S-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_hdrs/gen/my_include_dir"i-Iout/soong/.intermediates/external/abseil-cpp/absl_algorithm_hdrs/gen/external/abseil-cpp/my_include_dir"U-Iout/soong/.intermediates/external/abseil-cpp/absl_algorithm_hdrs/gen/my_include_dir"y-Iout/soong/.intermediates/external/abseil-cpp/absl_hash_weakly_mixed_integer_hdrs/gen/external/abseil-cpp/my_include_dir"e-Iout/soong/.intermediates/external/abseil-cpp/absl_hash_weakly_mixed_integer_hdrs/gen/my_include_dir"j-Iout/soong/.intermediates/external/abseil-cpp/absl_types_span_hdrs/gen/external/abseil-cpp/my_include_dir"V-Iout/soong/.intermediates/external/abseil-cpp/absl_types_span_hdrs/gen/my_include_dir"p-Iout/soong/.intermediates/external/abseil-cpp/absl_container_layout_hdrs/gen/external/abseil-cpp/my_include_dir"\-Iout/soong/.intermediates/external/abseil-cpp/absl_container_layout_hdrs/gen/my_include_dir"-Iout/soong/.intermediates/external/abseil-cpp/absl_container_inlined_vector_internal_hdrs/gen/external/abseil-cpp/my_include_dir"m-Iout/soong/.intermediates/external/abseil-cpp/absl_container_inlined_vector_internal_hdrs/gen/my_include_dir"x-Iout/soong/.intermediates/external/abseil-cpp/absl_container_inlined_vector_hdrs/gen/external/abseil-cpp/my_include_dir"d-Iout/soong/.intermediates/external/abseil-cpp/absl_container_inlined_vector_hdrs/gen/my_include_dir"n-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_cpu_detect_hdrs/gen/external/abseil-cpp/my_include_dir"Z-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_cpu_detect_hdrs/gen/my_include_dir"m-Iout/soong/.intermediates/external/abseil-cpp/absl_base_prefetch_hdrs/gen/external/abseil-cpp/my_include_dir"Y-Iout/soong/.intermediates/external/abseil-cpp/absl_base_prefetch_hdrs/gen/my_include_dir"p-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_crc_internal_hdrs/gen/external/abseil-cpp/my_include_dir"\-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_crc_internal_hdrs/gen/my_include_dir"-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_non_temporal_arm_intrinsics_hdrs/gen/external/abseil-cpp/my_include_dir"k-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_non_temporal_arm_intrinsics_hdrs/gen/my_include_dir"w-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_non_temporal_memcpy_hdrs/gen/external/abseil-cpp/my_include_dir"c-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_non_temporal_memcpy_hdrs/gen/my_include_dir"u-Iout/soong/.intermediates/external/abseil-cpp/absl_container_fixed_array_hdrs/gen/external/abseil-cpp/my_include_dir"a-Iout/soong/.intermediates/external/abseil-cpp/absl_container_fixed_array_hdrs/gen/my_include_dir"x-Iout/soong/.intermediates/external/abseil-cpp/absl_functional_any_invocable_hdrs/gen/external/abseil-cpp/my_include_dir"d-Iout/soong/.intermediates/external/abseil-cpp/absl_functional_any_invocable_hdrs/gen/my_include_dir"w-Iout/soong/.intermediates/external/abseil-cpp/absl_functional_function_ref_hdrs/gen/external/abseil-cpp/my_include_dir"c-Iout/soong/.intermediates/external/abseil-cpp/absl_functional_function_ref_hdrs/gen/my_include_dir"v-Iout/soong/.intermediates/external/abseil-cpp/absl_numeric_representation_hdrs/gen/external/abseil-cpp/my_include_dir"b-Iout/soong/.intermediates/external/abseil-cpp/absl_numeric_representation_hdrs/gen/my_include_dir"{-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_str_format_internal_hdrs/gen/external/abseil-cpp/my_include_dir"g-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_str_format_internal_hdrs/gen/my_include_dir"r-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_str_format_hdrs/gen/external/abseil-cpp/my_include_dir"^-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_str_format_hdrs/gen/my_include_dir"j-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_crc32c_hdrs/gen/external/abseil-cpp/my_include_dir"V-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_crc32c_hdrs/gen/my_include_dir"r-Iout/soong/.intermediates/external/abseil-cpp/absl_base_no_destructor_hdrs/gen/external/abseil-cpp/my_include_dir"^-Iout/soong/.intermediates/external/abseil-cpp/absl_base_no_destructor_hdrs/gen/my_include_dir"r-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_crc_cord_state_hdrs/gen/external/abseil-cpp/my_include_dir"^-Iout/soong/.intermediates/external/abseil-cpp/absl_crc_crc_cord_state_hdrs/gen/my_include_dir"u-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cord_internal_hdrs/gen/external/abseil-cpp/my_include_dir"a-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cord_internal_hdrs/gen/my_include_dir"|-Iout/soong/.intermediates/external/abseil-cpp/absl_profiling_exponential_biased_hdrs/gen/external/abseil-cpp/my_include_dir"h-Iout/soong/.intermediates/external/abseil-cpp/absl_profiling_exponential_biased_hdrs/gen/my_include_dir"w-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_functions_hdrs/gen/external/abseil-cpp/my_include_dir"c-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_functions_hdrs/gen/my_include_dir"t-Iout/soong/.intermediates/external/abseil-cpp/absl_base_malloc_internal_hdrs/gen/external/abseil-cpp/my_include_dir"`-Iout/soong/.intermediates/external/abseil-cpp/absl_base_malloc_internal_hdrs/gen/my_include_dir"-Iout/soong/.intermediates/external/abseil-cpp/absl_synchronization_graphcycles_internal_hdrs/gen/external/abseil-cpp/my_include_dir"p-Iout/soong/.intermediates/external/abseil-cpp/absl_synchronization_graphcycles_internal_hdrs/gen/my_include_dir"}-Iout/soong/.intermediates/external/abseil-cpp/absl_time_internal_cctz_civil_time_hdrs/gen/external/abseil-cpp/my_include_dir"i-Iout/soong/.intermediates/external/abseil-cpp/absl_time_internal_cctz_civil_time_hdrs/gen/my_include_dir"|-Iout/soong/.intermediates/external/abseil-cpp/absl_time_internal_cctz_time_zone_hdrs/gen/external/abseil-cpp/my_include_dir"h-Iout/soong/.intermediates/external/abseil-cpp/absl_time_internal_cctz_time_zone_hdrs/gen/my_include_dir"d-Iout/soong/.intermediates/external/abseil-cpp/absl_time_hdrs/gen/external/abseil-cpp/my_include_dir"P-Iout/soong/.intermediates/external/abseil-cpp/absl_time_hdrs/gen/my_include_dir"-Iout/soong/.intermediates/external/abseil-cpp/absl_synchronization_kernel_timeout_internal_hdrs/gen/external/abseil-cpp/my_include_dir"s-Iout/soong/.intermediates/external/abseil-cpp/absl_synchronization_kernel_timeout_internal_hdrs/gen/my_include_dir"u-Iout/soong/.intermediates/external/abseil-cpp/absl_base_tracing_internal_hdrs/gen/external/abseil-cpp/my_include_dir"a-Iout/soong/.intermediates/external/abseil-cpp/absl_base_tracing_internal_hdrs/gen/my_include_dir"|-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_debugging_internal_hdrs/gen/external/abseil-cpp/my_include_dir"h-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_debugging_internal_hdrs/gen/my_include_dir"t-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_stacktrace_hdrs/gen/external/abseil-cpp/my_include_dir"`-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_stacktrace_hdrs/gen/my_include_dir"s-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_symbolize_hdrs/gen/external/abseil-cpp/my_include_dir"_-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_symbolize_hdrs/gen/my_include_dir"o-Iout/soong/.intermediates/external/abseil-cpp/absl_synchronization_hdrs/gen/external/abseil-cpp/my_include_dir"[-Iout/soong/.intermediates/external/abseil-cpp/absl_synchronization_hdrs/gen/my_include_dir"t-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_handle_hdrs/gen/external/abseil-cpp/my_include_dir"`-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_handle_hdrs/gen/my_include_dir"|-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_update_tracker_hdrs/gen/external/abseil-cpp/my_include_dir"h-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_update_tracker_hdrs/gen/my_include_dir"x-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_statistics_hdrs/gen/external/abseil-cpp/my_include_dir"d-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_statistics_hdrs/gen/my_include_dir"r-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_info_hdrs/gen/external/abseil-cpp/my_include_dir"^-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_info_hdrs/gen/my_include_dir"z-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_update_scope_hdrs/gen/external/abseil-cpp/my_include_dir"f-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cordz_update_scope_hdrs/gen/my_include_dir"l-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cord_hdrs/gen/external/abseil-cpp/my_include_dir"X-Iout/soong/.intermediates/external/abseil-cpp/absl_strings_cord_hdrs/gen/my_include_dir"o-Iout/soong/.intermediates/external/abseil-cpp/absl_container_btree_hdrs/gen/external/abseil-cpp/my_include_dir"[-Iout/soong/.intermediates/external/abseil-cpp/absl_container_btree_hdrs/gen/my_include_dir"i-Iout/soong/.intermediates/external/abseil-cpp/absl_hash_city_hdrs/gen/external/abseil-cpp/my_include_dir"U-Iout/soong/.intermediates/external/abseil-cpp/absl_hash_city_hdrs/gen/my_include_dir"s-Iout/soong/.intermediates/external/abseil-cpp/absl_hash_low_level_hash_hdrs/gen/external/abseil-cpp/my_include_dir"_-Iout/soong/.intermediates/external/abseil-cpp/absl_hash_low_level_hash_hdrs/gen/my_include_dir"m-Iout/soong/.intermediates/external/abseil-cpp/absl_types_variant_hdrs/gen/external/abseil-cpp/my_include_dir"Y-Iout/soong/.intermediates/external/abseil-cpp/absl_types_variant_hdrs/gen/my_include_dir"d-Iout/soong/.intermediates/external/abseil-cpp/absl_hash_hdrs/gen/external/abseil-cpp/my_include_dir"P-Iout/soong/.intermediates/external/abseil-cpp/absl_hash_hdrs/gen/my_include_dir"-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hash_function_defaults_hdrs/gen/external/abseil-cpp/my_include_dir"l-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hash_function_defaults_hdrs/gen/my_include_dir"-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hash_container_defaults_hdrs/gen/external/abseil-cpp/my_include_dir"m-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hash_container_defaults_hdrs/gen/my_include_dir"|-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hash_policy_traits_hdrs/gen/external/abseil-cpp/my_include_dir"h-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hash_policy_traits_hdrs/gen/my_include_dir"-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hashtable_control_bytes_hdrs/gen/external/abseil-cpp/my_include_dir"m-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hashtable_control_bytes_hdrs/gen/my_include_dir"-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hashtable_debug_hooks_hdrs/gen/external/abseil-cpp/my_include_dir"k-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hashtable_debug_hooks_hdrs/gen/my_include_dir"y-Iout/soong/.intermediates/external/abseil-cpp/absl_profiling_sample_recorder_hdrs/gen/external/abseil-cpp/my_include_dir"e-Iout/soong/.intermediates/external/abseil-cpp/absl_profiling_sample_recorder_hdrs/gen/my_include_dir"|-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hashtablez_sampler_hdrs/gen/external/abseil-cpp/my_include_dir"h-Iout/soong/.intermediates/external/abseil-cpp/absl_container_hashtablez_sampler_hdrs/gen/my_include_dir"-Iout/soong/.intermediates/external/abseil-cpp/absl_container_raw_hash_set_resize_impl_hdrs/gen/external/abseil-cpp/my_include_dir"n-Iout/soong/.intermediates/external/abseil-cpp/absl_container_raw_hash_set_resize_impl_hdrs/gen/my_include_dir"v-Iout/soong/.intermediates/external/abseil-cpp/absl_container_raw_hash_set_hdrs/gen/external/abseil-cpp/my_include_dir"b-Iout/soong/.intermediates/external/abseil-cpp/absl_container_raw_hash_set_hdrs/gen/my_include_dir"v-Iout/soong/.intermediates/external/abseil-cpp/absl_container_raw_hash_map_hdrs/gen/external/abseil-cpp/my_include_dir"b-Iout/soong/.intermediates/external/abseil-cpp/absl_container_raw_hash_map_hdrs/gen/my_include_dir"s-Iout/soong/.intermediates/external/abseil-cpp/absl_algorithm_container_hdrs/gen/external/abseil-cpp/my_include_dir"_-Iout/soong/.intermediates/external/abseil-cpp/absl_algorithm_container_hdrs/gen/my_include_dir"w-Iout/soong/.intermediates/external/abseil-cpp/absl_container_flat_hash_map_hdrs/gen/external/abseil-cpp/my_include_dir"c-Iout/soong/.intermediates/external/abseil-cpp/absl_container_flat_hash_map_hdrs/gen/my_include_dir"w-Iout/soong/.intermediates/external/abseil-cpp/absl_container_flat_hash_set_hdrs/gen/external/abseil-cpp/my_include_dir"c-Iout/soong/.intermediates/external/abseil-cpp/absl_container_flat_hash_set_hdrs/gen/my_include_dir"v-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_nullguard_hdrs/gen/external/abseil-cpp/my_include_dir"b-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_nullguard_hdrs/gen/my_include_dir"w-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_nullstream_hdrs/gen/external/abseil-cpp/my_include_dir"c-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_nullstream_hdrs/gen/my_include_dir"}-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_append_truncated_hdrs/gen/external/abseil-cpp/my_include_dir"i-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_append_truncated_hdrs/gen/my_include_dir"s-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_config_hdrs/gen/external/abseil-cpp/my_include_dir"_-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_config_hdrs/gen/my_include_dir"t-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_globals_hdrs/gen/external/abseil-cpp/my_include_dir"`-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_globals_hdrs/gen/my_include_dir"s-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_format_hdrs/gen/external/abseil-cpp/my_include_dir"_-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_format_hdrs/gen/my_include_dir"x-Iout/soong/.intermediates/external/abseil-cpp/absl_cleanup_cleanup_internal_hdrs/gen/external/abseil-cpp/my_include_dir"d-Iout/soong/.intermediates/external/abseil-cpp/absl_cleanup_cleanup_internal_hdrs/gen/my_include_dir"g-Iout/soong/.intermediates/external/abseil-cpp/absl_cleanup_hdrs/gen/external/abseil-cpp/my_include_dir"S-Iout/soong/.intermediates/external/abseil-cpp/absl_cleanup_hdrs/gen/my_include_dir"t-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_fnmatch_hdrs/gen/external/abseil-cpp/my_include_dir"`-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_fnmatch_hdrs/gen/my_include_dir"x-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_vlog_config_hdrs/gen/external/abseil-cpp/my_include_dir"d-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_vlog_config_hdrs/gen/my_include_dir"k-Iout/soong/.intermediates/external/abseil-cpp/absl_log_globals_hdrs/gen/external/abseil-cpp/my_include_dir"W-Iout/soong/.intermediates/external/abseil-cpp/absl_log_globals_hdrs/gen/my_include_dir"m-Iout/soong/.intermediates/external/abseil-cpp/absl_log_log_entry_hdrs/gen/external/abseil-cpp/my_include_dir"Y-Iout/soong/.intermediates/external/abseil-cpp/absl_log_log_entry_hdrs/gen/my_include_dir"l-Iout/soong/.intermediates/external/abseil-cpp/absl_log_log_sink_hdrs/gen/external/abseil-cpp/my_include_dir"X-Iout/soong/.intermediates/external/abseil-cpp/absl_log_log_sink_hdrs/gen/my_include_dir"y-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_log_sink_set_hdrs/gen/external/abseil-cpp/my_include_dir"e-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_log_sink_set_hdrs/gen/my_include_dir"r-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_proto_hdrs/gen/external/abseil-cpp/my_include_dir"^-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_proto_hdrs/gen/my_include_dir"}-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_structured_proto_hdrs/gen/external/abseil-cpp/my_include_dir"i-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_structured_proto_hdrs/gen/my_include_dir"m-Iout/soong/.intermediates/external/abseil-cpp/absl_base_strerror_hdrs/gen/external/abseil-cpp/my_include_dir"Y-Iout/soong/.intermediates/external/abseil-cpp/absl_base_strerror_hdrs/gen/my_include_dir"w-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_examine_stack_hdrs/gen/external/abseil-cpp/my_include_dir"c-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_examine_stack_hdrs/gen/my_include_dir"u-Iout/soong/.intermediates/external/abseil-cpp/absl_log_log_sink_registry_hdrs/gen/external/abseil-cpp/my_include_dir"a-Iout/soong/.intermediates/external/abseil-cpp/absl_log_log_sink_registry_hdrs/gen/my_include_dir"x-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_log_message_hdrs/gen/external/abseil-cpp/my_include_dir"d-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_log_message_hdrs/gen/my_include_dir"r-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_strip_hdrs/gen/external/abseil-cpp/my_include_dir"^-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_strip_hdrs/gen/my_include_dir"t-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_leak_check_hdrs/gen/external/abseil-cpp/my_include_dir"`-Iout/soong/.intermediates/external/abseil-cpp/absl_debugging_leak_check_hdrs/gen/my_include_dir"u-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_check_op_hdrs/gen/external/abseil-cpp/my_include_dir"a-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_check_op_hdrs/gen/my_include_dir"t-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_voidify_hdrs/gen/external/abseil-cpp/my_include_dir"`-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_voidify_hdrs/gen/my_include_dir"w-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_conditions_hdrs/gen/external/abseil-cpp/my_include_dir"c-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_conditions_hdrs/gen/my_include_dir"w-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_check_impl_hdrs/gen/external/abseil-cpp/my_include_dir"c-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_check_impl_hdrs/gen/my_include_dir"n-Iout/soong/.intermediates/external/abseil-cpp/absl_log_absl_check_hdrs/gen/external/abseil-cpp/my_include_dir"Z-Iout/soong/.intermediates/external/abseil-cpp/absl_log_absl_check_hdrs/gen/my_include_dir"s-Iout/soong/.intermediates/external/abseil-cpp/absl_log_absl_vlog_is_on_hdrs/gen/external/abseil-cpp/my_include_dir"_-Iout/soong/.intermediates/external/abseil-cpp/absl_log_absl_vlog_is_on_hdrs/gen/my_include_dir"u-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_log_impl_hdrs/gen/external/abseil-cpp/my_include_dir"a-Iout/soong/.intermediates/external/abseil-cpp/absl_log_internal_log_impl_hdrs/gen/my_include_dir"l-Iout/soong/.intermediates/external/abseil-cpp/absl_log_absl_log_hdrs/gen/external/abseil-cpp/my_include_dir"X-Iout/soong/.intermediates/external/abseil-cpp/absl_log_absl_log_hdrs/gen/my_include_dir"f-Iout/soong/.intermediates/external/abseil-cpp/absl_status_hdrs/gen/external/abseil-cpp/my_include_dir"R-Iout/soong/.intermediates/external/abseil-cpp/absl_status_hdrs/gen/my_include_dir"Y-Iprebuilts/clang/host/linux-x86/clang-r584948/android_libc++/platform/arm/include/c++/v1"=-Iprebuilts/clang/host/linux-x86/clang-r584948/include/c++/v1" -Ibionic/libc/async_safe/include"-Isystem/logging/liblog/include"'-Ibionic/libc/system_properties/include"<-Isystem/core/property_service/libpropertyinfoparser/include"-isystem"bionic/libc/include"-isystem"bionic/libc/kernel/uapi/asm-arm"-isystem"bionic/libc/kernel/uapi"-isystem"bionic/libc/kernel/android/scsi"-isystem"bionic/libc/kernel/android/uapi"-target"armv7a-linux-androideabi10000"-DANDROID_STRICT"-fPIE"-Werror"-Wno-unused-parameter"-DGOOGLE_PROTOBUF_NO_RTTI"-Wimplicit-fallthrough"*-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS"-Wno-gnu-include-next"-fvisibility-inlines-hidden"-mllvm"-enable-shrink-wrap=false"-std=gnu++20" -fno-rtti"-Isystem/core/include"-Isystem/logging/liblog/include"-Isystem/media/audio/include"-Ihardware/libhardware/include"%-Ihardware/libhardware_legacy/include"-Ihardware/ril/include"-Iframeworks/native/include""-Iframeworks/native/opengl/include"-Iframeworks/av/include"-Werror=address-of-temporary"-Werror=dangling" -Werror=format-insufficient-args"-Werror=fortify-source"+-Werror=incompatible-function-pointer-types"-Werror=int-in-bool-context"-Werror=int-to-pointer-cast"-Werror=null-dereference"-Werror=return-type"-Werror=xor-used-as-pow"-Wno-missing-field-initializers"-Wno-packed-non-pod"(-Wno-error=tautological-constant-compare""-Wno-implicit-int-float-conversion"!-Wno-tautological-overlap-compare"-Wno-deprecated-copy""-Wno-zero-as-null-pointer-constant")-Wno-deprecated-anon-enum-enum-conversion"$-Wno-deprecated-enum-enum-conversion"-Wno-error=pessimizing-move"-Wno-non-c-typedef-for-linkage"-Wno-align-mismatch"#-Wno-error=unused-but-set-parameter"-Wno-error=deprecated"-Wno-error=invalid-offsetof"-Wno-nontrivial-memcall"-Wno-invalid-specialization"'-Wno-unterminated-string-initialization"(-Wno-implicit-int-conversion-on-negation"$-Wno-default-const-init-field-unsafe""-Wno-default-const-init-var-unsafe",-Wno-preferred-type-bitfield-enum-conversion"-Wno-implicit-enum-enum-cast"-Wno-vla-cxx-extension" -Wno-cast-function-type-mismatch"-Wno-character-conversion"&-Wno-error=uninitialized-const-pointer"8build/make/tools/ide_query/prober_scripts/cpp/general.cc2Egenfiles_for_build/make/tools/ide_query/prober_scripts/cpp/general.cc:êÉg |
| Egenfiles_for_build/make/tools/ide_query/prober_scripts/cpp/general.cc*År |
| dsoong/.intermediates/external/abseil-cpp/absl_strings_hdrs/gen/my_include_dir/absl/strings/numbers.hÜq// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: numbers.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This package contains functions for converting strings to numbers. For |
| // converting numbers to strings, use `StrCat()` or `StrAppend()` in str_cat.h, |
| // which automatically detect and convert most number values appropriately. |
| |
| #ifndef ABSL_STRINGS_NUMBERS_H_ |
| #define ABSL_STRINGS_NUMBERS_H_ |
| |
| #ifdef __SSSE3__ |
| #include <tmmintrin.h> |
| #endif |
| |
| #ifdef _MSC_VER |
| #include <intrin.h> |
| #endif |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstdlib> |
| #include <cstring> |
| #include <ctime> |
| #include <limits> |
| #include <string> |
| #include <type_traits> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/endian.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/port.h" |
| #include "absl/numeric/bits.h" |
| #include "absl/numeric/int128.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // SimpleAtoi() |
| // |
| // Converts the given string (optionally followed or preceded by ASCII |
| // whitespace) into an integer value, returning `true` if successful. The string |
| // must reflect a base-10 integer whose value falls within the range of the |
| // integer type (optionally preceded by a `+` or `-`). If any errors are |
| // encountered, this function returns `false`, leaving `out` in an unspecified |
| // state. |
| template <typename int_type> |
| [[nodiscard]] bool SimpleAtoi(absl::string_view str, |
| int_type* absl_nonnull out); |
| |
| // SimpleAtof() |
| // |
| // Converts the given string (optionally followed or preceded by ASCII |
| // whitespace) into a float, which may be rounded on overflow or underflow, |
| // returning `true` if successful. |
| // See https://en.cppreference.com/w/c/string/byte/strtof for details about the |
| // allowed formats for `str`, except SimpleAtof() is locale-independent and will |
| // always use the "C" locale. If any errors are encountered, this function |
| // returns `false`, leaving `out` in an unspecified state. |
| [[nodiscard]] bool SimpleAtof(absl::string_view str, float* absl_nonnull out); |
| |
| // SimpleAtod() |
| // |
| // Converts the given string (optionally followed or preceded by ASCII |
| // whitespace) into a double, which may be rounded on overflow or underflow, |
| // returning `true` if successful. |
| // See https://en.cppreference.com/w/c/string/byte/strtof for details about the |
| // allowed formats for `str`, except SimpleAtod is locale-independent and will |
| // always use the "C" locale. If any errors are encountered, this function |
| // returns `false`, leaving `out` in an unspecified state. |
| [[nodiscard]] bool SimpleAtod(absl::string_view str, double* absl_nonnull out); |
| |
| // SimpleAtob() |
| // |
| // Converts the given string into a boolean, returning `true` if successful. |
| // The following case-insensitive strings are interpreted as boolean `true`: |
| // "true", "t", "yes", "y", "1". The following case-insensitive strings |
| // are interpreted as boolean `false`: "false", "f", "no", "n", "0". If any |
| // errors are encountered, this function returns `false`, leaving `out` in an |
| // unspecified state. |
| [[nodiscard]] bool SimpleAtob(absl::string_view str, bool* absl_nonnull out); |
| |
| // SimpleHexAtoi() |
| // |
| // Converts a hexadecimal string (optionally followed or preceded by ASCII |
| // whitespace) to an integer, returning `true` if successful. Only valid base-16 |
| // hexadecimal integers whose value falls within the range of the integer type |
| // (optionally preceded by a `+` or `-`) can be converted. A valid hexadecimal |
| // value may include both upper and lowercase character symbols, and may |
| // optionally include a leading "0x" (or "0X") number prefix, which is ignored |
| // by this function. If any errors are encountered, this function returns |
| // `false`, leaving `out` in an unspecified state. |
| template <typename int_type> |
| [[nodiscard]] bool SimpleHexAtoi(absl::string_view str, |
| int_type* absl_nonnull out); |
| |
| // Overloads of SimpleHexAtoi() for 128 bit integers. |
| [[nodiscard]] inline bool SimpleHexAtoi(absl::string_view str, |
| absl::int128* absl_nonnull out); |
| [[nodiscard]] inline bool SimpleHexAtoi(absl::string_view str, |
| absl::uint128* absl_nonnull out); |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| // End of public API. Implementation details follow. |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace numbers_internal { |
| |
| template <typename int_type> |
| constexpr bool is_signed() { |
| if constexpr (std::is_arithmetic<int_type>::value) { |
| // Use std::numeric_limits<T>::is_signed where it's defined to work. |
| return std::numeric_limits<int_type>::is_signed; |
| } |
| // TODO(jorg): This signed-ness check is used because it works correctly |
| // with enums, and it also serves to check that int_type is not a pointer. |
| // If one day something like std::is_signed<enum E> works, switch to it. |
| return static_cast<int_type>(1) - 2 < 0; |
| } |
| |
| // Digit conversion. |
| ABSL_DLL extern const char kHexChar[17]; // 0123456789abcdef |
| ABSL_DLL extern const char |
| kHexTable[513]; // 000102030405060708090a0b0c0d0e0f1011... |
| |
| // Writes a two-character representation of 'i' to 'buf'. 'i' must be in the |
| // range 0 <= i < 100, and buf must have space for two characters. Example: |
| // char buf[2]; |
| // PutTwoDigits(42, buf); |
| // // buf[0] == '4' |
| // // buf[1] == '2' |
| void PutTwoDigits(uint32_t i, char* absl_nonnull buf); |
| |
| // safe_strto?() functions for implementing SimpleAtoi() |
| |
| bool safe_strto8_base(absl::string_view text, int8_t* absl_nonnull value, |
| int base); |
| bool safe_strto16_base(absl::string_view text, int16_t* absl_nonnull value, |
| int base); |
| bool safe_strto32_base(absl::string_view text, int32_t* absl_nonnull value, |
| int base); |
| bool safe_strto64_base(absl::string_view text, int64_t* absl_nonnull value, |
| int base); |
| bool safe_strto128_base(absl::string_view text, |
| absl::int128* absl_nonnull value, int base); |
| bool safe_strtou8_base(absl::string_view text, uint8_t* absl_nonnull value, |
| int base); |
| bool safe_strtou16_base(absl::string_view text, uint16_t* absl_nonnull value, |
| int base); |
| bool safe_strtou32_base(absl::string_view text, uint32_t* absl_nonnull value, |
| int base); |
| bool safe_strtou64_base(absl::string_view text, uint64_t* absl_nonnull value, |
| int base); |
| bool safe_strtou128_base(absl::string_view text, |
| absl::uint128* absl_nonnull value, int base); |
| |
| static const int kFastToBufferSize = 32; |
| static const int kSixDigitsToBufferSize = 16; |
| |
| // Helper function for fast formatting of floating-point values. |
| // The result is the same as printf's "%g", a.k.a. "%.6g"; that is, six |
| // significant digits are returned, trailing zeros are removed, and numbers |
| // outside the range 0.0001-999999 are output using scientific notation |
| // (1.23456e+06). This routine is heavily optimized. |
| // Required buffer size is `kSixDigitsToBufferSize`. |
| size_t SixDigitsToBuffer(double d, char* absl_nonnull buffer); |
| |
| // WARNING: These functions may write more characters than necessary, because |
| // they are intended for speed. All functions take an output buffer |
| // as an argument and return a pointer to the last byte they wrote, which is the |
| // terminating '\0'. At most `kFastToBufferSize` bytes are written. |
| char* absl_nonnull FastIntToBuffer(int32_t i, char* absl_nonnull buffer) |
| ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize); |
| char* absl_nonnull FastIntToBuffer(uint32_t n, char* absl_nonnull out_str) |
| ABSL_INTERNAL_NEED_MIN_SIZE(out_str, kFastToBufferSize); |
| char* absl_nonnull FastIntToBuffer(int64_t i, char* absl_nonnull buffer) |
| ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize); |
| char* absl_nonnull FastIntToBuffer(uint64_t i, char* absl_nonnull buffer) |
| ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize); |
| |
| // For enums and integer types that are not an exact match for the types above, |
| // use templates to call the appropriate one of the four overloads above. |
| template <typename int_type> |
| char* absl_nonnull FastIntToBuffer(int_type i, char* absl_nonnull buffer) |
| ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize) { |
| static_assert(sizeof(i) <= 64 / 8, |
| "FastIntToBuffer works only with 64-bit-or-less integers."); |
| // These conditions are constexpr bools to suppress MSVC warning C4127. |
| constexpr bool kIsSigned = is_signed<int_type>(); |
| constexpr bool kUse64Bit = sizeof(i) > 32 / 8; |
| if (kIsSigned) { |
| if (kUse64Bit) { |
| return FastIntToBuffer(static_cast<int64_t>(i), buffer); |
| } else { |
| return FastIntToBuffer(static_cast<int32_t>(i), buffer); |
| } |
| } else { |
| if (kUse64Bit) { |
| return FastIntToBuffer(static_cast<uint64_t>(i), buffer); |
| } else { |
| return FastIntToBuffer(static_cast<uint32_t>(i), buffer); |
| } |
| } |
| } |
| |
| // Implementation of SimpleAtoi, generalized to support arbitrary base (used |
| // with base different from 10 elsewhere in Abseil implementation). |
| template <typename int_type> |
| [[nodiscard]] bool safe_strtoi_base(absl::string_view s, |
| int_type* absl_nonnull out, int base) { |
| static_assert(sizeof(*out) == 1 || sizeof(*out) == 2 || sizeof(*out) == 4 || |
| sizeof(*out) == 8, |
| "SimpleAtoi works only with 8, 16, 32, or 64-bit integers."); |
| static_assert(!std::is_floating_point<int_type>::value, |
| "Use SimpleAtof or SimpleAtod instead."); |
| bool parsed; |
| // These conditions are constexpr bools to suppress MSVC warning C4127. |
| constexpr bool kIsSigned = is_signed<int_type>(); |
| constexpr int kIntTypeSize = sizeof(*out) * 8; |
| if (kIsSigned) { |
| if (kIntTypeSize == 64) { |
| int64_t val; |
| parsed = numbers_internal::safe_strto64_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } else if (kIntTypeSize == 32) { |
| int32_t val; |
| parsed = numbers_internal::safe_strto32_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } else if (kIntTypeSize == 16) { |
| int16_t val; |
| parsed = numbers_internal::safe_strto16_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } else if (kIntTypeSize == 8) { |
| int8_t val; |
| parsed = numbers_internal::safe_strto8_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } |
| } else { |
| if (kIntTypeSize == 64) { |
| uint64_t val; |
| parsed = numbers_internal::safe_strtou64_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } else if (kIntTypeSize == 32) { |
| uint32_t val; |
| parsed = numbers_internal::safe_strtou32_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } else if (kIntTypeSize == 16) { |
| uint16_t val; |
| parsed = numbers_internal::safe_strtou16_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } else if (kIntTypeSize == 8) { |
| uint8_t val; |
| parsed = numbers_internal::safe_strtou8_base(s, &val, base); |
| *out = static_cast<int_type>(val); |
| } |
| } |
| return parsed; |
| } |
| |
| // FastHexToBufferZeroPad16() |
| // |
| // Outputs `val` into `out` as if by `snprintf(out, 17, "%016x", val)` but |
| // without the terminating null character. Thus `out` must be of length >= 16. |
| // Returns the number of non-pad digits of the output (it can never be zero |
| // since 0 has one digit). |
| inline size_t FastHexToBufferZeroPad16(uint64_t val, char* absl_nonnull out) { |
| #ifdef ABSL_INTERNAL_HAVE_SSSE3 |
| uint64_t be = absl::big_endian::FromHost64(val); |
| const auto kNibbleMask = _mm_set1_epi8(0xf); |
| const auto kHexDigits = _mm_setr_epi8('0', '1', '2', '3', '4', '5', '6', '7', |
| '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); |
| auto v = _mm_loadl_epi64(reinterpret_cast<__m128i*>(&be)); // load lo dword |
| auto v4 = _mm_srli_epi64(v, 4); // shift 4 right |
| auto il = _mm_unpacklo_epi8(v4, v); // interleave bytes |
| auto m = _mm_and_si128(il, kNibbleMask); // mask out nibbles |
| auto hexchars = _mm_shuffle_epi8(kHexDigits, m); // hex chars |
| _mm_storeu_si128(reinterpret_cast<__m128i*>(out), hexchars); |
| #else |
| for (int i = 0; i < 8; ++i) { |
| auto byte = (val >> (56 - 8 * i)) & 0xFF; |
| auto* hex = &absl::numbers_internal::kHexTable[byte * 2]; |
| std::memcpy(out + 2 * i, hex, 2); |
| } |
| #endif |
| // | 0x1 so that even 0 has 1 digit. |
| return 16 - static_cast<size_t>(countl_zero(val | 0x1) / 4); |
| } |
| |
| } // namespace numbers_internal |
| |
| template <typename int_type> |
| [[nodiscard]] bool SimpleAtoi(absl::string_view str, |
| int_type* absl_nonnull out) { |
| return numbers_internal::safe_strtoi_base(str, out, 10); |
| } |
| |
| [[nodiscard]] inline bool SimpleAtoi(absl::string_view str, |
| absl::int128* absl_nonnull out) { |
| return numbers_internal::safe_strto128_base(str, out, 10); |
| } |
| |
| [[nodiscard]] inline bool SimpleAtoi(absl::string_view str, |
| absl::uint128* absl_nonnull out) { |
| return numbers_internal::safe_strtou128_base(str, out, 10); |
| } |
| |
| template <typename int_type> |
| [[nodiscard]] bool SimpleHexAtoi(absl::string_view str, |
| int_type* absl_nonnull out) { |
| return numbers_internal::safe_strtoi_base(str, out, 16); |
| } |
| |
| [[nodiscard]] inline bool SimpleHexAtoi(absl::string_view str, |
| absl::int128* absl_nonnull out) { |
| return numbers_internal::safe_strto128_base(str, out, 16); |
| } |
| |
| [[nodiscard]] inline bool SimpleHexAtoi(absl::string_view str, |
| absl::uint128* absl_nonnull out) { |
| return numbers_internal::safe_strtou128_base(str, out, 16); |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_NUMBERS_H_ |
| *§ |
| psoong/.intermediates/external/abseil-cpp/absl_container_btree_hdrs/gen/my_include_dir/absl/container/btree_map.h±// Copyright 2018 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: btree_map.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines B-tree maps: sorted associative containers mapping |
| // keys to values. |
| // |
| // * `absl::btree_map<>` |
| // * `absl::btree_multimap<>` |
| // |
| // These B-tree types are similar to the corresponding types in the STL |
| // (`std::map` and `std::multimap`) and generally conform to the STL interfaces |
| // of those types. However, because they are implemented using B-trees, they |
| // are more efficient in most situations. |
| // |
| // Unlike `std::map` and `std::multimap`, which are commonly implemented using |
| // red-black tree nodes, B-tree maps use more generic B-tree nodes able to hold |
| // multiple values per node. Holding multiple values per node often makes |
| // B-tree maps perform better than their `std::map` counterparts, because |
| // multiple entries can be checked within the same cache hit. |
| // |
| // However, these types should not be considered drop-in replacements for |
| // `std::map` and `std::multimap` as there are some API differences, which are |
| // noted in this header file. The most consequential differences with respect to |
| // migrating to b-tree from the STL types are listed in the next paragraph. |
| // Other API differences are minor. |
| // |
| // Importantly, insertions and deletions may invalidate outstanding iterators, |
| // pointers, and references to elements. Such invalidations are typically only |
| // an issue if insertion and deletion operations are interleaved with the use of |
| // more than one iterator, pointer, or reference simultaneously. For this |
| // reason, `insert()`, `erase()`, and `extract_and_get_next()` return a valid |
| // iterator at the current position. Another important difference is that |
| // key-types must be copy-constructible. |
| // |
| // There are other API differences: first, btree iterators can be subtracted, |
| // and this is faster than using `std::distance`. Additionally, btree |
| // iterators can be advanced via `operator+=` and `operator-=`, which is faster |
| // than using `std::advance`. |
| // |
| // B-tree maps are not exception-safe. |
| |
| #ifndef ABSL_CONTAINER_BTREE_MAP_H_ |
| #define ABSL_CONTAINER_BTREE_MAP_H_ |
| |
| #include "absl/base/attributes.h" |
| #include "absl/container/internal/btree.h" // IWYU pragma: export |
| #include "absl/container/internal/btree_container.h" // IWYU pragma: export |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| namespace container_internal { |
| |
| template <typename Key, typename Data, typename Compare, typename Alloc, |
| int TargetNodeSize, bool IsMulti> |
| struct map_params; |
| |
| } // namespace container_internal |
| |
| // absl::btree_map<> |
| // |
| // An `absl::btree_map<K, V>` is an ordered associative container of |
| // unique keys and associated values designed to be a more efficient replacement |
| // for `std::map` (in most cases). |
| // |
| // Keys are sorted using an (optional) comparison function, which defaults to |
| // `std::less<K>`. |
| // |
| // An `absl::btree_map<K, V>` uses a default allocator of |
| // `std::allocator<std::pair<const K, V>>` to allocate (and deallocate) |
| // nodes, and construct and destruct values within those nodes. You may |
| // instead specify a custom allocator `A` (which in turn requires specifying a |
| // custom comparator `C`) as in `absl::btree_map<K, V, C, A>`. |
| // |
| template <typename Key, typename Value, typename Compare = std::less<Key>, |
| typename Alloc = std::allocator<std::pair<const Key, Value>>> |
| class ABSL_ATTRIBUTE_OWNER btree_map |
| : public container_internal::btree_map_container< |
| container_internal::btree<container_internal::map_params< |
| Key, Value, Compare, Alloc, /*TargetNodeSize=*/256, |
| /*IsMulti=*/false>>> { |
| using Base = typename btree_map::btree_map_container; |
| |
| public: |
| // Constructors and Assignment Operators |
| // |
| // A `btree_map` supports the same overload set as `std::map` |
| // for construction and assignment: |
| // |
| // * Default constructor |
| // |
| // absl::btree_map<int, std::string> map1; |
| // |
| // * Initializer List constructor |
| // |
| // absl::btree_map<int, std::string> map2 = |
| // {{1, "huey"}, {2, "dewey"}, {3, "louie"},}; |
| // |
| // * Copy constructor |
| // |
| // absl::btree_map<int, std::string> map3(map2); |
| // |
| // * Copy assignment operator |
| // |
| // absl::btree_map<int, std::string> map4; |
| // map4 = map3; |
| // |
| // * Move constructor |
| // |
| // // Move is guaranteed efficient |
| // absl::btree_map<int, std::string> map5(std::move(map4)); |
| // |
| // * Move assignment operator |
| // |
| // // May be efficient if allocators are compatible |
| // absl::btree_map<int, std::string> map6; |
| // map6 = std::move(map5); |
| // |
| // * Range constructor |
| // |
| // std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}}; |
| // absl::btree_map<int, std::string> map7(v.begin(), v.end()); |
| btree_map() {} |
| using Base::Base; |
| |
| // btree_map::begin() |
| // |
| // Returns an iterator to the beginning of the `btree_map`. |
| using Base::begin; |
| |
| // btree_map::cbegin() |
| // |
| // Returns a const iterator to the beginning of the `btree_map`. |
| using Base::cbegin; |
| |
| // btree_map::end() |
| // |
| // Returns an iterator to the end of the `btree_map`. |
| using Base::end; |
| |
| // btree_map::cend() |
| // |
| // Returns a const iterator to the end of the `btree_map`. |
| using Base::cend; |
| |
| // btree_map::empty() |
| // |
| // Returns whether or not the `btree_map` is empty. |
| using Base::empty; |
| |
| // btree_map::max_size() |
| // |
| // Returns the largest theoretical possible number of elements within a |
| // `btree_map` under current memory constraints. This value can be thought |
| // of as the largest value of `std::distance(begin(), end())` for a |
| // `btree_map<Key, T>`. |
| using Base::max_size; |
| |
| // btree_map::size() |
| // |
| // Returns the number of elements currently within the `btree_map`. |
| using Base::size; |
| |
| // btree_map::clear() |
| // |
| // Removes all elements from the `btree_map`. Invalidates any references, |
| // pointers, or iterators referring to contained elements. |
| using Base::clear; |
| |
| // btree_map::erase() |
| // |
| // Erases elements within the `btree_map`. If an erase occurs, any references, |
| // pointers, or iterators are invalidated. |
| // Overloads are listed below. |
| // |
| // iterator erase(iterator position): |
| // iterator erase(const_iterator position): |
| // |
| // Erases the element at `position` of the `btree_map`, returning |
| // the iterator pointing to the element after the one that was erased |
| // (or end() if none exists). |
| // |
| // iterator erase(const_iterator first, const_iterator last): |
| // |
| // Erases the elements in the open interval [`first`, `last`), returning |
| // the iterator pointing to the element after the interval that was erased |
| // (or end() if none exists). |
| // |
| // template <typename K> size_type erase(const K& key): |
| // |
| // Erases the element with the matching key, if it exists, returning the |
| // number of elements erased (0 or 1). |
| using Base::erase; |
| |
| // btree_map::insert() |
| // |
| // Inserts an element of the specified value into the `btree_map`, |
| // returning an iterator pointing to the newly inserted element, provided that |
| // an element with the given key does not already exist. If an insertion |
| // occurs, any references, pointers, or iterators are invalidated. |
| // Overloads are listed below. |
| // |
| // std::pair<iterator,bool> insert(const value_type& value): |
| // |
| // Inserts a value into the `btree_map`. Returns a pair consisting of an |
| // iterator to the inserted element (or to the element that prevented the |
| // insertion) and a bool denoting whether the insertion took place. |
| // |
| // std::pair<iterator,bool> insert(value_type&& value): |
| // |
| // Inserts a moveable value into the `btree_map`. Returns a pair |
| // consisting of an iterator to the inserted element (or to the element that |
| // prevented the insertion) and a bool denoting whether the insertion took |
| // place. |
| // |
| // iterator insert(const_iterator hint, const value_type& value): |
| // iterator insert(const_iterator hint, value_type&& value): |
| // |
| // Inserts a value, using the position of `hint` as a non-binding suggestion |
| // for where to begin the insertion search. Returns an iterator to the |
| // inserted element, or to the existing element that prevented the |
| // insertion. |
| // |
| // void insert(InputIterator first, InputIterator last): |
| // |
| // Inserts a range of values [`first`, `last`). |
| // |
| // void insert(std::initializer_list<init_type> ilist): |
| // |
| // Inserts the elements within the initializer list `ilist`. |
| using Base::insert; |
| |
| // btree_map::insert_or_assign() |
| // |
| // Inserts an element of the specified value into the `btree_map` provided |
| // that a value with the given key does not already exist, or replaces the |
| // corresponding mapped type with the forwarded `obj` argument if a key for |
| // that value already exists, returning an iterator pointing to the newly |
| // inserted element. Overloads are listed below. |
| // |
| // pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj): |
| // pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj): |
| // |
| // Inserts/Assigns (or moves) the element of the specified key into the |
| // `btree_map`. If the returned bool is true, insertion took place, and if |
| // it's false, assignment took place. |
| // |
| // iterator insert_or_assign(const_iterator hint, |
| // const key_type& k, M&& obj): |
| // iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj): |
| // |
| // Inserts/Assigns (or moves) the element of the specified key into the |
| // `btree_map` using the position of `hint` as a non-binding suggestion |
| // for where to begin the insertion search. |
| using Base::insert_or_assign; |
| |
| // btree_map::emplace() |
| // |
| // Inserts an element of the specified value by constructing it in-place |
| // within the `btree_map`, provided that no element with the given key |
| // already exists. |
| // |
| // The element may be constructed even if there already is an element with the |
| // key in the container, in which case the newly constructed element will be |
| // destroyed immediately. Prefer `try_emplace()` unless your key is not |
| // copyable or moveable. |
| // |
| // If an insertion occurs, any references, pointers, or iterators are |
| // invalidated. |
| using Base::emplace; |
| |
| // btree_map::emplace_hint() |
| // |
| // Inserts an element of the specified value by constructing it in-place |
| // within the `btree_map`, using the position of `hint` as a non-binding |
| // suggestion for where to begin the insertion search, and only inserts |
| // provided that no element with the given key already exists. |
| // |
| // The element may be constructed even if there already is an element with the |
| // key in the container, in which case the newly constructed element will be |
| // destroyed immediately. Prefer `try_emplace()` unless your key is not |
| // copyable or moveable. |
| // |
| // If an insertion occurs, any references, pointers, or iterators are |
| // invalidated. |
| using Base::emplace_hint; |
| |
| // btree_map::try_emplace() |
| // |
| // Inserts an element of the specified value by constructing it in-place |
| // within the `btree_map`, provided that no element with the given key |
| // already exists. Unlike `emplace()`, if an element with the given key |
| // already exists, we guarantee that no element is constructed. |
| // |
| // If an insertion occurs, any references, pointers, or iterators are |
| // invalidated. |
| // |
| // Overloads are listed below. |
| // |
| // std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args): |
| // std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args): |
| // |
| // Inserts (via copy or move) the element of the specified key into the |
| // `btree_map`. |
| // |
| // iterator try_emplace(const_iterator hint, |
| // const key_type& k, Args&&... args): |
| // iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args): |
| // |
| // Inserts (via copy or move) the element of the specified key into the |
| // `btree_map` using the position of `hint` as a non-binding suggestion |
| // for where to begin the insertion search. |
| using Base::try_emplace; |
| |
| // btree_map::extract() |
| // |
| // Extracts the indicated element, erasing it in the process, and returns it |
| // as a C++17-compatible node handle. Any references, pointers, or iterators |
| // are invalidated. Overloads are listed below. |
| // |
| // node_type extract(const_iterator position): |
| // |
| // Extracts the element at the indicated position and returns a node handle |
| // owning that extracted data. |
| // |
| // template <typename K> node_type extract(const K& k): |
| // |
| // Extracts the element with the key matching the passed key value and |
| // returns a node handle owning that extracted data. If the `btree_map` |
| // does not contain an element with a matching key, this function returns an |
| // empty node handle. |
| // |
| // NOTE: when compiled in an earlier version of C++ than C++17, |
| // `node_type::key()` returns a const reference to the key instead of a |
| // mutable reference. We cannot safely return a mutable reference without |
| // std::launder (which is not available before C++17). |
| // |
| // NOTE: In this context, `node_type` refers to the C++17 concept of a |
| // move-only type that owns and provides access to the elements in associative |
| // containers (https://en.cppreference.com/w/cpp/container/node_handle). |
| // It does NOT refer to the data layout of the underlying btree. |
| using Base::extract; |
| |
| // btree_map::extract_and_get_next() |
| // |
| // Extracts the indicated element, erasing it in the process, and returns it |
| // as a C++17-compatible node handle along with an iterator to the next |
| // element. |
| // |
| // extract_and_get_next_return_type extract_and_get_next( |
| // const_iterator position): |
| // |
| // Extracts the element at the indicated position, returns a struct |
| // containing a member named `node`: a node handle owning that extracted |
| // data and a member named `next`: an iterator pointing to the next element |
| // in the btree. |
| using Base::extract_and_get_next; |
| |
| // btree_map::merge() |
| // |
| // Extracts elements from a given `source` btree_map into this |
| // `btree_map`. If the destination `btree_map` already contains an |
| // element with an equivalent key, that element is not extracted. |
| using Base::merge; |
| |
| // btree_map::swap(btree_map& other) |
| // |
| // Exchanges the contents of this `btree_map` with those of the `other` |
| // btree_map, avoiding invocation of any move, copy, or swap operations on |
| // individual elements. |
| // |
| // All iterators and references on the `btree_map` remain valid, excepting |
| // for the past-the-end iterator, which is invalidated. |
| using Base::swap; |
| |
| // btree_map::at() |
| // |
| // Returns a reference to the mapped value of the element with key equivalent |
| // to the passed key. |
| using Base::at; |
| |
| // btree_map::contains() |
| // |
| // template <typename K> bool contains(const K& key) const: |
| // |
| // Determines whether an element comparing equal to the given `key` exists |
| // within the `btree_map`, returning `true` if so or `false` otherwise. |
| // |
| // Supports heterogeneous lookup, provided that the map has a compatible |
| // heterogeneous comparator. |
| using Base::contains; |
| |
| // btree_map::count() |
| // |
| // template <typename K> size_type count(const K& key) const: |
| // |
| // Returns the number of elements comparing equal to the given `key` within |
| // the `btree_map`. Note that this function will return either `1` or `0` |
| // since duplicate elements are not allowed within a `btree_map`. |
| // |
| // Supports heterogeneous lookup, provided that the map has a compatible |
| // heterogeneous comparator. |
| using Base::count; |
| |
| // btree_map::equal_range() |
| // |
| // Returns a half-open range [first, last), defined by a `std::pair` of two |
| // iterators, containing all elements with the passed key in the `btree_map`. |
| using Base::equal_range; |
| |
| // btree_map::find() |
| // |
| // template <typename K> iterator find(const K& key): |
| // template <typename K> const_iterator find(const K& key) const: |
| // |
| // Finds an element with the passed `key` within the `btree_map`. |
| // |
| // Supports heterogeneous lookup, provided that the map has a compatible |
| // heterogeneous comparator. |
| using Base::find; |
| |
| // btree_map::lower_bound() |
| // |
| // template <typename K> iterator lower_bound(const K& key): |
| // template <typename K> const_iterator lower_bound(const K& key) const: |
| // |
| // Finds the first element with a key that is not less than `key` within the |
| // `btree_map`. |
| // |
| // Supports heterogeneous lookup, provided that the map has a compatible |
| // heterogeneous comparator. |
| using Base::lower_bound; |
| |
| // btree_map::upper_bound() |
| // |
| // template <typename K> iterator upper_bound(const K& key): |
| // template <typename K> const_iterator upper_bound(const K& key) const: |
| // |
| // Finds the first element with a key that is greater than `key` within the |
| // `btree_map`. |
| // |
| // Supports heterogeneous lookup, provided that the map has a compatible |
| // heterogeneous comparator. |
| using Base::upper_bound; |
| |
| // btree_map::operator[]() |
| // |
| // Returns a reference to the value mapped to the passed key within the |
| // `btree_map`, performing an `insert()` if the key does not already |
| // exist. |
| // |
| // If an insertion occurs, any references, pointers, or iterators are |
| // invalidated. Otherwise iterators are not affected and references are not |
| // invalidated. Overloads are listed below. |
| // |
| // T& operator[](key_type&& key): |
| // T& operator[](const key_type& key): |
| // |
| // Inserts a value_type object constructed in-place if the element with the |
| // given key does not exist. |
| using Base::operator[]; |
| |
| // btree_map::get_allocator() |
| // |
| // Returns the allocator function associated with this `btree_map`. |
| using Base::get_allocator; |
| |
| // btree_map::key_comp(); |
| // |
| // Returns the key comparator associated with this `btree_map`. |
| using Base::key_comp; |
| |
| // btree_map::value_comp(); |
| // |
| // Returns the value comparator associated with this `btree_map`. |
| using Base::value_comp; |
| }; |
| |
| // absl::swap(absl::btree_map<>, absl::btree_map<>) |
| // |
| // Swaps the contents of two `absl::btree_map` containers. |
| template <typename K, typename V, typename C, typename A> |
| void swap(btree_map<K, V, C, A> &x, btree_map<K, V, C, A> &y) { |
| return x.swap(y); |
| } |
| |
| // absl::erase_if(absl::btree_map<>, Pred) |
| // |
| // Erases all elements that satisfy the predicate pred from the container. |
| // Returns the number of erased elements. |
| template <typename K, typename V, typename C, typename A, typename Pred> |
| typename btree_map<K, V, C, A>::size_type erase_if( |
| btree_map<K, V, C, A> &map, Pred pred) { |
| return container_internal::btree_access::erase_if(map, std::move(pred)); |
| } |
| |
| // absl::btree_multimap |
| // |
| // An `absl::btree_multimap<K, V>` is an ordered associative container of |
| // keys and associated values designed to be a more efficient replacement for |
| // `std::multimap` (in most cases). Unlike `absl::btree_map`, a B-tree multimap |
| // allows multiple elements with equivalent keys. |
| // |
| // Keys are sorted using an (optional) comparison function, which defaults to |
| // `std::less<K>`. |
| // |
| // An `absl::btree_multimap<K, V>` uses a default allocator of |
| // `std::allocator<std::pair<const K, V>>` to allocate (and deallocate) |
| // nodes, and construct and destruct values within those nodes. You may |
| // instead specify a custom allocator `A` (which in turn requires specifying a |
| // custom comparator `C`) as in `absl::btree_multimap<K, V, C, A>`. |
| // |
| template <typename Key, typename Value, typename Compare = std::less<Key>, |
| typename Alloc = std::allocator<std::pair<const Key, Value>>> |
| class ABSL_ATTRIBUTE_OWNER btree_multimap |
| : public container_internal::btree_multimap_container< |
| container_internal::btree<container_internal::map_params< |
| Key, Value, Compare, Alloc, /*TargetNodeSize=*/256, |
| /*IsMulti=*/true>>> { |
| using Base = typename btree_multimap::btree_multimap_container; |
| |
| public: |
| // Constructors and Assignment Operators |
| // |
| // A `btree_multimap` supports the same overload set as `std::multimap` |
| // for construction and assignment: |
| // |
| // * Default constructor |
| // |
| // absl::btree_multimap<int, std::string> map1; |
| // |
| // * Initializer List constructor |
| // |
| // absl::btree_multimap<int, std::string> map2 = |
| // {{1, "huey"}, {2, "dewey"}, {3, "louie"},}; |
| // |
| // * Copy constructor |
| // |
| // absl::btree_multimap<int, std::string> map3(map2); |
| // |
| // * Copy assignment operator |
| // |
| // absl::btree_multimap<int, std::string> map4; |
| // map4 = map3; |
| // |
| // * Move constructor |
| // |
| // // Move is guaranteed efficient |
| // absl::btree_multimap<int, std::string> map5(std::move(map4)); |
| // |
| // * Move assignment operator |
| // |
| // // May be efficient if allocators are compatible |
| // absl::btree_multimap<int, std::string> map6; |
| // map6 = std::move(map5); |
| // |
| // * Range constructor |
| // |
| // std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}}; |
| // absl::btree_multimap<int, std::string> map7(v.begin(), v.end()); |
| btree_multimap() {} |
| using Base::Base; |
| |
| // btree_multimap::begin() |
| // |
| // Returns an iterator to the beginning of the `btree_multimap`. |
| using Base::begin; |
| |
| // btree_multimap::cbegin() |
| // |
| // Returns a const iterator to the beginning of the `btree_multimap`. |
| using Base::cbegin; |
| |
| // btree_multimap::end() |
| // |
| // Returns an iterator to the end of the `btree_multimap`. |
| using Base::end; |
| |
| // btree_multimap::cend() |
| // |
| // Returns a const iterator to the end of the `btree_multimap`. |
| using Base::cend; |
| |
| // btree_multimap::empty() |
| // |
| // Returns whether or not the `btree_multimap` is empty. |
| using Base::empty; |
| |
| // btree_multimap::max_size() |
| // |
| // Returns the largest theoretical possible number of elements within a |
| // `btree_multimap` under current memory constraints. This value can be |
| // thought of as the largest value of `std::distance(begin(), end())` for a |
| // `btree_multimap<Key, T>`. |
| using Base::max_size; |
| |
| // btree_multimap::size() |
| // |
| // Returns the number of elements currently within the `btree_multimap`. |
| using Base::size; |
| |
| // btree_multimap::clear() |
| // |
| // Removes all elements from the `btree_multimap`. Invalidates any references, |
| // pointers, or iterators referring to contained elements. |
| using Base::clear; |
| |
| // btree_multimap::erase() |
| // |
| // Erases elements within the `btree_multimap`. If an erase occurs, any |
| // references, pointers, or iterators are invalidated. |
| // Overloads are listed below. |
| // |
| // iterator erase(iterator position): |
| // iterator erase(const_iterator position): |
| // |
| // Erases the element at `position` of the `btree_multimap`, returning |
| // the iterator pointing to the element after the one that was erased |
| // (or end() if none exists). |
| // |
| // iterator erase(const_iterator first, const_iterator last): |
| // |
| // Erases the elements in the open interval [`first`, `last`), returning |
| // the iterator pointing to the element after the interval that was erased |
| // (or end() if none exists). |
| // |
| // template <typename K> size_type erase(const K& key): |
| // |
| // Erases the elements matching the key, if any exist, returning the |
| // number of elements erased. |
| using Base::erase; |
| |
| // btree_multimap::insert() |
| // |
| // Inserts an element of the specified value into the `btree_multimap`, |
| // returning an iterator pointing to the newly inserted element. |
| // Any references, pointers, or iterators are invalidated. Overloads are |
| // listed below. |
| // |
| // iterator insert(const value_type& value): |
| // |
| // Inserts a value into the `btree_multimap`, returning an iterator to the |
| // inserted element. |
| // |
| // iterator insert(value_type&& value): |
| // |
| // Inserts a moveable value into the `btree_multimap`, returning an iterator |
| // to the inserted element. |
| // |
| // iterator insert(const_iterator hint, const value_type& value): |
| // iterator insert(const_iterator hint, value_type&& value): |
| // |
| // Inserts a value, using the position of `hint` as a non-binding suggestion |
| // for where to begin the insertion search. Returns an iterator to the |
| // inserted element. |
| // |
| // void insert(InputIterator first, InputIterator last): |
| // |
| // Inserts a range of values [`first`, `last`). |
| // |
| // void insert(std::initializer_list<init_type> ilist): |
| // |
| // Inserts the elements within the initializer list `ilist`. |
| using Base::insert; |
| |
| // btree_multimap::emplace() |
| // |
| // Inserts an element of the specified value by constructing it in-place |
| // within the `btree_multimap`. Any references, pointers, or iterators are |
| // invalidated. |
| using Base::emplace; |
| |
| // btree_multimap::emplace_hint() |
| // |
| // Inserts an element of the specified value by constructing it in-place |
| // within the `btree_multimap`, using the position of `hint` as a non-binding |
| // suggestion for where to begin the insertion search. |
| // |
| // Any references, pointers, or iterators are invalidated. |
| using Base::emplace_hint; |
| |
| // btree_multimap::extract() |
| // |
| // Extracts the indicated element, erasing it in the process, and returns it |
| // as a C++17-compatible node handle. Overloads are listed below. |
| // |
| // node_type extract(const_iterator position): |
| // |
| // Extracts the element at the indicated position and returns a node handle |
| // owning that extracted data. |
| // |
| // template <typename K> node_type extract(const K& k): |
| // |
| // Extracts the element with the key matching the passed key value and |
| // returns a node handle owning that extracted data. If the `btree_multimap` |
| // does not contain an element with a matching key, this function returns an |
| // empty node handle. |
| // |
| // NOTE: when compiled in an earlier version of C++ than C++17, |
| // `node_type::key()` returns a const reference to the key instead of a |
| // mutable reference. We cannot safely return a mutable reference without |
| // std::launder (which is not available before C++17). |
| // |
| // NOTE: In this context, `node_type` refers to the C++17 concept of a |
| // move-only type that owns and provides access to the elements in associative |
| // containers (https://en.cppreference.com/w/cpp/container/node_handle). |
| // It does NOT refer to the data layout of the underlying btree. |
| using Base::extract; |
| |
| // btree_multimap::extract_and_get_next() |
| // |
| // Extracts the indicated element, erasing it in the process, and returns it |
| // as a C++17-compatible node handle along with an iterator to the next |
| // element. |
| // |
| // extract_and_get_next_return_type extract_and_get_next( |
| // const_iterator position): |
| // |
| // Extracts the element at the indicated position, returns a struct |
| // containing a member named `node`: a node handle owning that extracted |
| // data and a member named `next`: an iterator pointing to the next element |
| // in the btree. |
| using Base::extract_and_get_next; |
| |
| // btree_multimap::merge() |
| // |
| // Extracts all elements from a given `source` btree_multimap into this |
| // `btree_multimap`. |
| using Base::merge; |
| |
| // btree_multimap::swap(btree_multimap& other) |
| // |
| // Exchanges the contents of this `btree_multimap` with those of the `other` |
| // btree_multimap, avoiding invocation of any move, copy, or swap operations |
| // on individual elements. |
| // |
| // All iterators and references on the `btree_multimap` remain valid, |
| // excepting for the past-the-end iterator, which is invalidated. |
| using Base::swap; |
| |
| // btree_multimap::contains() |
| // |
| // template <typename K> bool contains(const K& key) const: |
| // |
| // Determines whether an element comparing equal to the given `key` exists |
| // within the `btree_multimap`, returning `true` if so or `false` otherwise. |
| // |
| // Supports heterogeneous lookup, provided that the map has a compatible |
| // heterogeneous comparator. |
| using Base::contains; |
| |
| // btree_multimap::count() |
| // |
| // template <typename K> size_type count(const K& key) const: |
| // |
| // Returns the number of elements comparing equal to the given `key` within |
| // the `btree_multimap`. |
| // |
| // Supports heterogeneous lookup, provided that the map has a compatible |
| // heterogeneous comparator. |
| using Base::count; |
| |
| // btree_multimap::equal_range() |
| // |
| // Returns a half-open range [first, last), defined by a `std::pair` of two |
| // iterators, containing all elements with the passed key in the |
| // `btree_multimap`. |
| using Base::equal_range; |
| |
| // btree_multimap::find() |
| // |
| // template <typename K> iterator find(const K& key): |
| // template <typename K> const_iterator find(const K& key) const: |
| // |
| // Finds an element with the passed `key` within the `btree_multimap`. |
| // |
| // Supports heterogeneous lookup, provided that the map has a compatible |
| // heterogeneous comparator. |
| using Base::find; |
| |
| // btree_multimap::lower_bound() |
| // |
| // template <typename K> iterator lower_bound(const K& key): |
| // template <typename K> const_iterator lower_bound(const K& key) const: |
| // |
| // Finds the first element with a key that is not less than `key` within the |
| // `btree_multimap`. |
| // |
| // Supports heterogeneous lookup, provided that the map has a compatible |
| // heterogeneous comparator. |
| using Base::lower_bound; |
| |
| // btree_multimap::upper_bound() |
| // |
| // template <typename K> iterator upper_bound(const K& key): |
| // template <typename K> const_iterator upper_bound(const K& key) const: |
| // |
| // Finds the first element with a key that is greater than `key` within the |
| // `btree_multimap`. |
| // |
| // Supports heterogeneous lookup, provided that the map has a compatible |
| // heterogeneous comparator. |
| using Base::upper_bound; |
| |
| // btree_multimap::get_allocator() |
| // |
| // Returns the allocator function associated with this `btree_multimap`. |
| using Base::get_allocator; |
| |
| // btree_multimap::key_comp(); |
| // |
| // Returns the key comparator associated with this `btree_multimap`. |
| using Base::key_comp; |
| |
| // btree_multimap::value_comp(); |
| // |
| // Returns the value comparator associated with this `btree_multimap`. |
| using Base::value_comp; |
| }; |
| |
| // absl::swap(absl::btree_multimap<>, absl::btree_multimap<>) |
| // |
| // Swaps the contents of two `absl::btree_multimap` containers. |
| template <typename K, typename V, typename C, typename A> |
| void swap(btree_multimap<K, V, C, A> &x, btree_multimap<K, V, C, A> &y) { |
| return x.swap(y); |
| } |
| |
| // absl::erase_if(absl::btree_multimap<>, Pred) |
| // |
| // Erases all elements that satisfy the predicate pred from the container. |
| // Returns the number of erased elements. |
| template <typename K, typename V, typename C, typename A, typename Pred> |
| typename btree_multimap<K, V, C, A>::size_type erase_if( |
| btree_multimap<K, V, C, A> &map, Pred pred) { |
| return container_internal::btree_access::erase_if(map, std::move(pred)); |
| } |
| |
| namespace container_internal { |
| |
| // A parameters structure for holding the type parameters for a btree_map. |
| // Compare and Alloc should be nothrow copy-constructible. |
| template <typename Key, typename Data, typename Compare, typename Alloc, |
| int TargetNodeSize, bool IsMulti> |
| struct map_params : common_params<Key, Compare, Alloc, TargetNodeSize, IsMulti, |
| /*IsMap=*/true, map_slot_policy<Key, Data>> { |
| using super_type = typename map_params::common_params; |
| using mapped_type = Data; |
| // This type allows us to move keys when it is safe to do so. It is safe |
| // for maps in which value_type and mutable_value_type are layout compatible. |
| using slot_policy = typename super_type::slot_policy; |
| using slot_type = typename super_type::slot_type; |
| using value_type = typename super_type::value_type; |
| using init_type = typename super_type::init_type; |
| |
| template <typename V> |
| static auto key(const V &value ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| -> decltype((value.first)) { |
| return value.first; |
| } |
| static const Key &key(const slot_type *s) { return slot_policy::key(s); } |
| static const Key &key(slot_type *s) { return slot_policy::key(s); } |
| // For use in node handle. |
| static auto mutable_key(slot_type *s) |
| -> decltype(slot_policy::mutable_key(s)) { |
| return slot_policy::mutable_key(s); |
| } |
| static mapped_type &value(value_type *value) { return value->second; } |
| }; |
| |
| } // namespace container_internal |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CONTAINER_BTREE_MAP_H_ |
| *B |
| `soong/.intermediates/external/abseil-cpp/absl_base_hdrs/gen/my_include_dir/absl/base/call_once.h´A// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: call_once.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file provides an Abseil version of `std::call_once` for invoking |
| // a given function at most once, across all threads. This Abseil version is |
| // faster than the C++11 version and incorporates the C++17 argument-passing |
| // fix, so that (for example) non-const references may be passed to the invoked |
| // function. |
| |
| #ifndef ABSL_BASE_CALL_ONCE_H_ |
| #define ABSL_BASE_CALL_ONCE_H_ |
| |
| #include <algorithm> |
| #include <atomic> |
| #include <cstdint> |
| #include <functional> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/low_level_scheduling.h" |
| #include "absl/base/internal/raw_logging.h" |
| #include "absl/base/internal/scheduling_mode.h" |
| #include "absl/base/internal/spinlock_wait.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/optimization.h" |
| #include "absl/base/port.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| class once_flag; |
| |
| namespace base_internal { |
| std::atomic<uint32_t>* absl_nonnull ControlWord( |
| absl::once_flag* absl_nonnull flag); |
| } // namespace base_internal |
| |
| // call_once() |
| // |
| // For all invocations using a given `once_flag`, invokes a given `fn` exactly |
| // once across all threads. The first call to `call_once()` with a particular |
| // `once_flag` argument (that does not throw an exception) will run the |
| // specified function with the provided `args`; other calls with the same |
| // `once_flag` argument will not run the function, but will wait |
| // for the provided function to finish running (if it is still running). |
| // |
| // This mechanism provides a safe, simple, and fast mechanism for one-time |
| // initialization in a multi-threaded process. |
| // |
| // Example: |
| // |
| // class MyInitClass { |
| // public: |
| // ... |
| // mutable absl::once_flag once_; |
| // |
| // MyInitClass* init() const { |
| // absl::call_once(once_, &MyInitClass::Init, this); |
| // return ptr_; |
| // } |
| // |
| template <typename Callable, typename... Args> |
| void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args); |
| |
| // once_flag |
| // |
| // Objects of this type are used to distinguish calls to `call_once()` and |
| // ensure the provided function is only invoked once across all threads. This |
| // type is not copyable or movable. However, it has a `constexpr` |
| // constructor, and is safe to use as a namespace-scoped global variable. |
| class once_flag { |
| public: |
| constexpr once_flag() : control_(0) {} |
| once_flag(const once_flag&) = delete; |
| once_flag& operator=(const once_flag&) = delete; |
| |
| private: |
| friend std::atomic<uint32_t>* absl_nonnull base_internal::ControlWord( |
| once_flag* absl_nonnull flag); |
| std::atomic<uint32_t> control_; |
| }; |
| |
| //------------------------------------------------------------------------------ |
| // End of public interfaces. |
| // Implementation details follow. |
| //------------------------------------------------------------------------------ |
| |
| namespace base_internal { |
| |
| // Like call_once, but uses KERNEL_ONLY scheduling. Intended to be used to |
| // initialize entities used by the scheduler implementation. |
| template <typename Callable, typename... Args> |
| void LowLevelCallOnce(absl::once_flag* absl_nonnull flag, Callable&& fn, |
| Args&&... args); |
| |
| // Disables scheduling while on stack when scheduling mode is non-cooperative. |
| // No effect for cooperative scheduling modes. |
| class SchedulingHelper { |
| public: |
| explicit SchedulingHelper(base_internal::SchedulingMode mode) : mode_(mode) { |
| if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) { |
| guard_result_ = base_internal::SchedulingGuard::DisableRescheduling(); |
| } |
| } |
| |
| ~SchedulingHelper() { |
| if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) { |
| base_internal::SchedulingGuard::EnableRescheduling(guard_result_); |
| } |
| } |
| |
| private: |
| base_internal::SchedulingMode mode_; |
| bool guard_result_ = false; |
| }; |
| |
| // Bit patterns for call_once state machine values. Internal implementation |
| // detail, not for use by clients. |
| // |
| // The bit patterns are arbitrarily chosen from unlikely values, to aid in |
| // debugging. However, kOnceInit must be 0, so that a zero-initialized |
| // once_flag will be valid for immediate use. |
| enum { |
| kOnceInit = 0, |
| kOnceRunning = 0x65C2937B, |
| kOnceWaiter = 0x05A308D2, |
| // A very small constant is chosen for kOnceDone so that it fit in a single |
| // compare with immediate instruction for most common ISAs. This is verified |
| // for x86, POWER and ARM. |
| kOnceDone = 221, // Random Number |
| }; |
| |
| template <typename Callable, typename... Args> |
| void |
| CallOnceImpl(std::atomic<uint32_t>* absl_nonnull control, |
| base_internal::SchedulingMode scheduling_mode, Callable&& fn, |
| Args&&... args) { |
| #ifndef NDEBUG |
| { |
| uint32_t old_control = control->load(std::memory_order_relaxed); |
| if (old_control != kOnceInit && |
| old_control != kOnceRunning && |
| old_control != kOnceWaiter && |
| old_control != kOnceDone) { |
| ABSL_RAW_LOG(FATAL, "Unexpected value for control word: 0x%lx", |
| static_cast<unsigned long>(old_control)); // NOLINT |
| } |
| } |
| #endif // NDEBUG |
| static const base_internal::SpinLockWaitTransition trans[] = { |
| {kOnceInit, kOnceRunning, true}, |
| {kOnceRunning, kOnceWaiter, false}, |
| {kOnceDone, kOnceDone, true}}; |
| |
| // Must do this before potentially modifying control word's state. |
| base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode); |
| // Short circuit the simplest case to avoid procedure call overhead. |
| // The base_internal::SpinLockWait() call returns either kOnceInit or |
| // kOnceDone. If it returns kOnceDone, it must have loaded the control word |
| // with std::memory_order_acquire and seen a value of kOnceDone. |
| uint32_t old_control = kOnceInit; |
| if (control->compare_exchange_strong(old_control, kOnceRunning, |
| std::memory_order_relaxed) || |
| base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans, |
| scheduling_mode) == kOnceInit) { |
| std::invoke(std::forward<Callable>(fn), std::forward<Args>(args)...); |
| old_control = |
| control->exchange(base_internal::kOnceDone, std::memory_order_release); |
| if (old_control == base_internal::kOnceWaiter) { |
| base_internal::SpinLockWake(control, true); |
| } |
| } // else *control is already kOnceDone |
| } |
| |
| inline std::atomic<uint32_t>* absl_nonnull ControlWord( |
| once_flag* absl_nonnull flag) { |
| return &flag->control_; |
| } |
| |
| template <typename Callable, typename... Args> |
| void LowLevelCallOnce(absl::once_flag* absl_nonnull flag, Callable&& fn, |
| Args&&... args) { |
| std::atomic<uint32_t>* once = base_internal::ControlWord(flag); |
| uint32_t s = once->load(std::memory_order_acquire); |
| if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) { |
| base_internal::CallOnceImpl(once, base_internal::SCHEDULE_KERNEL_ONLY, |
| std::forward<Callable>(fn), |
| std::forward<Args>(args)...); |
| } |
| } |
| |
| } // namespace base_internal |
| |
| template <typename Callable, typename... Args> |
| void |
| call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) { |
| std::atomic<uint32_t>* once = base_internal::ControlWord(&flag); |
| uint32_t s = once->load(std::memory_order_acquire); |
| if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) { |
| base_internal::CallOnceImpl( |
| once, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL, |
| std::forward<Callable>(fn), std::forward<Args>(args)...); |
| } |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_CALL_ONCE_H_ |
| *Ó# |
| soong/.intermediates/external/abseil-cpp/absl_strings_internal_hdrs/gen/my_include_dir/absl/strings/internal/resize_uninitialized.hÊ"// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #ifndef ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ |
| #define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ |
| |
| #include <algorithm> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/port.h" |
| #include "absl/meta/type_traits.h" // for void_t |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace strings_internal { |
| |
| // In this type trait, we look for a __resize_default_init member function, and |
| // we use it if available, otherwise, we use resize. We provide HasMember to |
| // indicate whether __resize_default_init is present. |
| template <typename string_type, typename = void> |
| struct ResizeUninitializedTraits { |
| using HasMember = std::false_type; |
| static void Resize(string_type* s, size_t new_size) { s->resize(new_size); } |
| }; |
| |
| // __resize_default_init is provided by libc++ >= 8.0 |
| template <typename string_type> |
| struct ResizeUninitializedTraits< |
| string_type, absl::void_t<decltype(std::declval<string_type&>() |
| .__resize_default_init(237))> > { |
| using HasMember = std::true_type; |
| static void Resize(string_type* s, size_t new_size) { |
| s->__resize_default_init(new_size); |
| } |
| }; |
| |
| // Returns true if the std::string implementation supports a resize where |
| // the new characters added to the std::string are left untouched. |
| // |
| // (A better name might be "STLStringSupportsUninitializedResize", alluding to |
| // the previous function.) |
| template <typename string_type> |
| inline constexpr bool STLStringSupportsNontrashingResize(string_type*) { |
| return ResizeUninitializedTraits<string_type>::HasMember::value; |
| } |
| |
| // Like str->resize(new_size), except any new characters added to "*str" as a |
| // result of resizing may be left uninitialized, rather than being filled with |
| // '0' bytes. Typically used when code is then going to overwrite the backing |
| // store of the std::string with known data. |
| template <typename string_type, typename = void> |
| inline void STLStringResizeUninitialized(string_type* s, size_t new_size) { |
| ResizeUninitializedTraits<string_type>::Resize(s, new_size); |
| } |
| |
| // Used to ensure exponential growth so that the amortized complexity of |
| // increasing the string size by a small amount is O(1), in contrast to |
| // O(str->size()) in the case of precise growth. |
| template <typename string_type> |
| void STLStringReserveAmortized(string_type* s, size_t new_size) { |
| const size_t cap = s->capacity(); |
| if (new_size > cap) { |
| // Make sure to always grow by at least a factor of 2x. |
| s->reserve((std::max)(new_size, 2 * cap)); |
| } |
| } |
| |
| // In this type trait, we look for an __append_default_init member function, and |
| // we use it if available, otherwise, we use append. |
| template <typename string_type, typename = void> |
| struct AppendUninitializedTraits { |
| static void Append(string_type* s, size_t n) { |
| s->append(n, typename string_type::value_type()); |
| } |
| }; |
| |
| template <typename string_type> |
| struct AppendUninitializedTraits< |
| string_type, absl::void_t<decltype(std::declval<string_type&>() |
| .__append_default_init(237))> > { |
| static void Append(string_type* s, size_t n) { |
| s->__append_default_init(n); |
| } |
| }; |
| |
| // Like STLStringResizeUninitialized(str, new_size), except guaranteed to use |
| // exponential growth so that the amortized complexity of increasing the string |
| // size by a small amount is O(1), in contrast to O(str->size()) in the case of |
| // precise growth. |
| template <typename string_type> |
| void STLStringResizeUninitializedAmortized(string_type* s, size_t new_size) { |
| const size_t size = s->size(); |
| if (new_size > size) { |
| AppendUninitializedTraits<string_type>::Append(s, new_size - size); |
| } else { |
| s->erase(new_size); |
| } |
| } |
| |
| } // namespace strings_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ |
| *9 |
| hsoong/.intermediates/external/abseil-cpp/absl_base_prefetch_hdrs/gen/my_include_dir/absl/base/prefetch.hª8// Copyright 2023 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: prefetch.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines prefetch functions to prefetch memory contents |
| // into the first level cache (L1) for the current CPU. The prefetch logic |
| // offered in this header is limited to prefetching first level cachelines |
| // only, and is aimed at relatively 'simple' prefetching logic. |
| // |
| #ifndef ABSL_BASE_PREFETCH_H_ |
| #define ABSL_BASE_PREFETCH_H_ |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| |
| #if defined(ABSL_INTERNAL_HAVE_SSE) |
| #include <xmmintrin.h> |
| #endif |
| |
| #if defined(_MSC_VER) |
| #include <intrin.h> |
| #if defined(ABSL_INTERNAL_HAVE_SSE) |
| #pragma intrinsic(_mm_prefetch) |
| #endif |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // Moves data into the L1 cache before it is read, or "prefetches" it. |
| // |
| // The value of `addr` is the address of the memory to prefetch. If |
| // the target and compiler support it, data prefetch instructions are |
| // generated. If the prefetch is done some time before the memory is |
| // read, it may be in the cache by the time the read occurs. |
| // |
| // This method prefetches data with the highest degree of temporal locality; |
| // data is prefetched where possible into all levels of the cache. |
| // |
| // Incorrect or gratuitous use of this function can degrade performance. |
| // Use this function only when representative benchmarks show an improvement. |
| // |
| // Example: |
| // |
| // // Computes incremental checksum for `data`. |
| // int ComputeChecksum(int sum, absl::string_view data); |
| // |
| // // Computes cumulative checksum for all values in `data` |
| // int ComputeChecksum(absl::Span<const std::string> data) { |
| // int sum = 0; |
| // auto it = data.begin(); |
| // auto pit = data.begin(); |
| // auto end = data.end(); |
| // for (int dist = 8; dist > 0 && pit != data.end(); --dist, ++pit) { |
| // absl::PrefetchToLocalCache(pit->data()); |
| // } |
| // for (; pit != end; ++pit, ++it) { |
| // sum = ComputeChecksum(sum, *it); |
| // absl::PrefetchToLocalCache(pit->data()); |
| // } |
| // for (; it != end; ++it) { |
| // sum = ComputeChecksum(sum, *it); |
| // } |
| // return sum; |
| // } |
| // |
| void PrefetchToLocalCache(const void* addr); |
| |
| // Moves data into the L1 cache before it is read, or "prefetches" it. |
| // |
| // This function is identical to `PrefetchToLocalCache()` except that it has |
| // non-temporal locality: the fetched data should not be left in any of the |
| // cache tiers. This is useful for cases where the data is used only once / |
| // short term, for example, invoking a destructor on an object. |
| // |
| // Incorrect or gratuitous use of this function can degrade performance. |
| // Use this function only when representative benchmarks show an improvement. |
| // |
| // Example: |
| // |
| // template <typename Iterator> |
| // void DestroyPointers(Iterator begin, Iterator end) { |
| // size_t distance = std::min(8U, bars.size()); |
| // |
| // int dist = 8; |
| // auto prefetch_it = begin; |
| // while (prefetch_it != end && --dist;) { |
| // absl::PrefetchToLocalCacheNta(*prefetch_it++); |
| // } |
| // while (prefetch_it != end) { |
| // delete *begin++; |
| // absl::PrefetchToLocalCacheNta(*prefetch_it++); |
| // } |
| // while (begin != end) { |
| // delete *begin++; |
| // } |
| // } |
| // |
| void PrefetchToLocalCacheNta(const void* addr); |
| |
| // Moves data into the L1 cache with the intent to modify it. |
| // |
| // This function is similar to `PrefetchToLocalCache()` except that it |
| // prefetches cachelines with an 'intent to modify' This typically includes |
| // invalidating cache entries for this address in all other cache tiers, and an |
| // exclusive access intent. |
| // |
| // Incorrect or gratuitous use of this function can degrade performance. As this |
| // function can invalidate cached cachelines on other caches and computer cores, |
| // incorrect usage of this function can have an even greater negative impact |
| // than incorrect regular prefetches. |
| // Use this function only when representative benchmarks show an improvement. |
| // |
| // Example: |
| // |
| // void* Arena::Allocate(size_t size) { |
| // void* ptr = AllocateBlock(size); |
| // absl::PrefetchToLocalCacheForWrite(ptr); |
| // return ptr; |
| // } |
| // |
| void PrefetchToLocalCacheForWrite(const void* addr); |
| |
| #if ABSL_HAVE_BUILTIN(__builtin_prefetch) || defined(__GNUC__) |
| |
| #define ABSL_HAVE_PREFETCH 1 |
| |
| // See __builtin_prefetch: |
| // https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html. |
| // |
| ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache( |
| const void* addr) { |
| __builtin_prefetch(addr, 0, 3); |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta( |
| const void* addr) { |
| __builtin_prefetch(addr, 0, 0); |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite( |
| const void* addr) { |
| // [x86] gcc/clang don't generate PREFETCHW for __builtin_prefetch(.., 1) |
| // unless -march=broadwell or newer; this is not generally the default, so we |
| // manually emit prefetchw. PREFETCHW is recognized as a no-op on older Intel |
| // processors and has been present on AMD processors since the K6-2. |
| #if defined(__x86_64__) && !defined(__PRFCHW__) |
| asm("prefetchw %0" : : "m"(*reinterpret_cast<const char*>(addr))); |
| #else |
| __builtin_prefetch(addr, 1, 3); |
| #endif |
| } |
| |
| #elif defined(ABSL_INTERNAL_HAVE_SSE) |
| |
| #define ABSL_HAVE_PREFETCH 1 |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache( |
| const void* addr) { |
| _mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T0); |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta( |
| const void* addr) { |
| _mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_NTA); |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite( |
| const void* addr) { |
| #if defined(_MM_HINT_ET0) |
| _mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_ET0); |
| #elif !defined(_MSC_VER) && defined(__x86_64__) |
| // _MM_HINT_ET0 is not universally supported. As we commented further |
| // up, PREFETCHW is recognized as a no-op on older Intel processors |
| // and has been present on AMD processors since the K6-2. We have this |
| // disabled for MSVC compilers as this miscompiles on older MSVC compilers. |
| asm("prefetchw %0" : : "m"(*reinterpret_cast<const char*>(addr))); |
| #endif |
| } |
| |
| #else |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache( |
| const void* addr) {} |
| ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta( |
| const void* addr) {} |
| ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite( |
| const void* addr) {} |
| |
| #endif |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_PREFETCH_H_ |
| * |
| usoong/.intermediates/external/abseil-cpp/absl_strings_hdrs/gen/my_include_dir/absl/strings/internal/string_constant.h// Copyright 2020 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ |
| #define ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ |
| |
| #include "absl/meta/type_traits.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace strings_internal { |
| |
| // StringConstant<T> represents a compile time string constant. |
| // It can be accessed via its `absl::string_view value` static member. |
| // It is guaranteed that the `string_view` returned has constant `.data()`, |
| // constant `.size()` and constant `value[i]` for all `0 <= i < .size()` |
| // |
| // The `T` is an opaque type. It is guaranteed that different string constants |
| // will have different values of `T`. This allows users to associate the string |
| // constant with other static state at compile time. |
| // |
| // Instances should be made using the `MakeStringConstant()` factory function |
| // below. |
| template <typename T> |
| struct StringConstant { |
| private: |
| static constexpr bool TryConstexprEval(absl::string_view view) { |
| return view.empty() || 2 * view[0] != 1; |
| } |
| |
| public: |
| static constexpr absl::string_view value = T{}(); |
| constexpr absl::string_view operator()() const { return value; } |
| |
| // Check to be sure `view` points to constant data. |
| // Otherwise, it can't be constant evaluated. |
| static_assert(TryConstexprEval(value), |
| "The input string_view must point to constant data."); |
| }; |
| |
| // Factory function for `StringConstant` instances. |
| // It supports callables that have a constexpr default constructor and a |
| // constexpr operator(). |
| // It must return an `absl::string_view` or `const char*` pointing to constant |
| // data. This is validated at compile time. |
| template <typename T> |
| constexpr StringConstant<T> MakeStringConstant(T) { |
| return {}; |
| } |
| |
| } // namespace strings_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ |
| *«' |
| soong/.intermediates/external/abseil-cpp/absl_synchronization_hdrs/gen/my_include_dir/absl/synchronization/internal/per_thread_sem.h¡&// 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. |
| // |
| |
| // PerThreadSem is a low-level synchronization primitive controlling the |
| // runnability of a single thread, used internally by Mutex and CondVar. |
| // |
| // This is NOT a general-purpose synchronization mechanism, and should not be |
| // used directly by applications. Applications should use Mutex and CondVar. |
| // |
| // The semantics of PerThreadSem are the same as that of a counting semaphore. |
| // Each thread maintains an abstract "count" value associated with its identity. |
| |
| #ifndef ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_ |
| #define ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_ |
| |
| #include <atomic> |
| |
| #include "absl/base/internal/thread_identity.h" |
| #include "absl/synchronization/internal/create_thread_identity.h" |
| #include "absl/synchronization/internal/kernel_timeout.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| class Mutex; |
| |
| namespace synchronization_internal { |
| |
| class PerThreadSem { |
| public: |
| PerThreadSem() = delete; |
| PerThreadSem(const PerThreadSem&) = delete; |
| PerThreadSem& operator=(const PerThreadSem&) = delete; |
| |
| // Routine invoked periodically (once a second) by a background thread. |
| // Has no effect on user-visible state. |
| static void Tick(base_internal::ThreadIdentity* identity); |
| |
| // --------------------------------------------------------------------------- |
| // Routines used by autosizing threadpools to detect when threads are |
| // blocked. Each thread has a counter pointer, initially zero. If non-zero, |
| // the implementation atomically increments the counter when it blocks on a |
| // semaphore, a decrements it again when it wakes. This allows a threadpool |
| // to keep track of how many of its threads are blocked. |
| // SetThreadBlockedCounter() should be used only by threadpool |
| // implementations. GetThreadBlockedCounter() should be used by modules that |
| // block threads; if the pointer returned is non-zero, the location should be |
| // incremented before the thread blocks, and decremented after it wakes. |
| static void SetThreadBlockedCounter(std::atomic<int> *counter); |
| static std::atomic<int> *GetThreadBlockedCounter(); |
| |
| private: |
| // Create the PerThreadSem associated with "identity". Initializes count=0. |
| // REQUIRES: May only be called by ThreadIdentity. |
| static inline void Init(base_internal::ThreadIdentity* identity); |
| |
| // Increments "identity"'s count. |
| static inline void Post(base_internal::ThreadIdentity* identity); |
| |
| // Waits until either our count > 0 or t has expired. |
| // If count > 0, decrements count and returns true. Otherwise returns false. |
| // !t.has_timeout() => Wait(t) will return true. |
| static inline bool Wait(KernelTimeout t); |
| |
| // Permitted callers. |
| friend class PerThreadSemTest; |
| friend class absl::Mutex; |
| friend void OneTimeInitThreadIdentity(absl::base_internal::ThreadIdentity*); |
| }; |
| |
| } // namespace synchronization_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| // In some build configurations we pass --detect-odr-violations to the |
| // gold linker. This causes it to flag weak symbol overrides as ODR |
| // violations. Because ODR only applies to C++ and not C, |
| // --detect-odr-violations ignores symbols not mangled with C++ names. |
| // By changing our extension points to be extern "C", we dodge this |
| // check. |
| extern "C" { |
| void ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemInit)( |
| absl::base_internal::ThreadIdentity* identity); |
| void ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)( |
| absl::base_internal::ThreadIdentity* identity); |
| bool ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)( |
| absl::synchronization_internal::KernelTimeout t); |
| void ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPoke)( |
| absl::base_internal::ThreadIdentity* identity); |
| } // extern "C" |
| |
| void absl::synchronization_internal::PerThreadSem::Init( |
| absl::base_internal::ThreadIdentity* identity) { |
| ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemInit)(identity); |
| } |
| |
| void absl::synchronization_internal::PerThreadSem::Post( |
| absl::base_internal::ThreadIdentity* identity) { |
| ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)(identity); |
| } |
| |
| bool absl::synchronization_internal::PerThreadSem::Wait( |
| absl::synchronization_internal::KernelTimeout t) { |
| return ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)(t); |
| } |
| |
| #endif // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_ |
| *Ñ |
| nsoong/.intermediates/external/abseil-cpp/absl_base_hdrs/gen/my_include_dir/absl/base/internal/per_thread_tls.hÞ
// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_ |
| #define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_ |
| |
| // This header defines two macros: |
| // |
| // If the platform supports thread-local storage: |
| // |
| // * ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a |
| // thread-local variable |
| // * ABSL_PER_THREAD_TLS is 1 |
| // |
| // Otherwise: |
| // |
| // * ABSL_PER_THREAD_TLS_KEYWORD is empty |
| // * ABSL_PER_THREAD_TLS is 0 |
| // |
| // Microsoft C supports thread-local storage. |
| // GCC supports it if the appropriate version of glibc is available, |
| // which the programmer can indicate by defining ABSL_HAVE_TLS |
| |
| #include "absl/base/port.h" // For ABSL_HAVE_TLS |
| |
| #if defined(ABSL_PER_THREAD_TLS) |
| #error ABSL_PER_THREAD_TLS cannot be directly set |
| #elif defined(ABSL_PER_THREAD_TLS_KEYWORD) |
| #error ABSL_PER_THREAD_TLS_KEYWORD cannot be directly set |
| #elif defined(ABSL_HAVE_TLS) |
| #define ABSL_PER_THREAD_TLS_KEYWORD __thread |
| #define ABSL_PER_THREAD_TLS 1 |
| #elif defined(_MSC_VER) |
| #define ABSL_PER_THREAD_TLS_KEYWORD __declspec(thread) |
| #define ABSL_PER_THREAD_TLS 1 |
| #else |
| #define ABSL_PER_THREAD_TLS_KEYWORD |
| #define ABSL_PER_THREAD_TLS 0 |
| #endif |
| |
| #endif // ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_ |
| *ò% |
| soong/.intermediates/external/abseil-cpp/absl_base_malloc_internal_hdrs/gen/my_include_dir/absl/base/internal/low_level_alloc.hî$// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_ |
| #define ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_ |
| |
| // A simple thread-safe memory allocator that does not depend on |
| // mutexes or thread-specific data. It is intended to be used |
| // sparingly, and only when malloc() would introduce an unwanted |
| // dependency, such as inside the heap-checker, or the Mutex |
| // implementation. |
| |
| // IWYU pragma: private, include "base/low_level_alloc.h" |
| |
| #include <sys/types.h> |
| |
| #include <cstdint> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| |
| // LowLevelAlloc requires that the platform support low-level |
| // allocation of virtual memory. Platforms lacking this cannot use |
| // LowLevelAlloc. |
| #ifdef ABSL_LOW_LEVEL_ALLOC_MISSING |
| #error ABSL_LOW_LEVEL_ALLOC_MISSING cannot be directly set |
| #elif !defined(ABSL_HAVE_MMAP) && !defined(_WIN32) |
| #define ABSL_LOW_LEVEL_ALLOC_MISSING 1 |
| #endif |
| |
| // Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows or |
| // asm.js / WebAssembly. |
| // See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html |
| // for more information. |
| #ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING |
| #error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set |
| #elif defined(_WIN32) || defined(__asmjs__) || defined(__wasm__) || \ |
| defined(__hexagon__) |
| #define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1 |
| #endif |
| |
| #include <cstddef> |
| |
| #include "absl/base/port.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace base_internal { |
| |
| class LowLevelAlloc { |
| public: |
| struct Arena; // an arena from which memory may be allocated |
| |
| // Returns a pointer to a block of at least "request" bytes |
| // that have been newly allocated from the specific arena. |
| // for Alloc() call the DefaultArena() is used. |
| // Returns 0 if passed request==0. |
| // Does not return 0 under other circumstances; it crashes if memory |
| // is not available. |
| static void *Alloc(size_t request) ABSL_ATTRIBUTE_SECTION(malloc_hook); |
| static void *AllocWithArena(size_t request, Arena *arena) |
| ABSL_ATTRIBUTE_SECTION(malloc_hook); |
| |
| // Deallocates a region of memory that was previously allocated with |
| // Alloc(). Does nothing if passed 0. "s" must be either 0, |
| // or must have been returned from a call to Alloc() and not yet passed to |
| // Free() since that call to Alloc(). The space is returned to the arena |
| // from which it was allocated. |
| static void Free(void *s) ABSL_ATTRIBUTE_SECTION(malloc_hook); |
| |
| // ABSL_ATTRIBUTE_SECTION(malloc_hook) for Alloc* and Free |
| // are to put all callers of MallocHook::Invoke* in this module |
| // into special section, |
| // so that MallocHook::GetCallerStackTrace can function accurately. |
| |
| // Create a new arena. |
| // The root metadata for the new arena is allocated in the |
| // meta_data_arena; the DefaultArena() can be passed for meta_data_arena. |
| // These values may be ored into flags: |
| enum { |
| // Report calls to Alloc() and Free() via the MallocHook interface. |
| // Set in the DefaultArena. |
| kCallMallocHook = 0x0001, |
| |
| #ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING |
| // Make calls to Alloc(), Free() be async-signal-safe. Not set in |
| // DefaultArena(). Not supported on all platforms. |
| kAsyncSignalSafe = 0x0002, |
| #endif |
| }; |
| // Construct a new arena. The allocation of the underlying metadata honors |
| // the provided flags. For example, the call NewArena(kAsyncSignalSafe) |
| // is itself async-signal-safe, as well as generatating an arena that provides |
| // async-signal-safe Alloc/Free. |
| static Arena *NewArena(uint32_t flags); |
| |
| // Destroys an arena allocated by NewArena and returns true, |
| // provided no allocated blocks remain in the arena. |
| // If allocated blocks remain in the arena, does nothing and |
| // returns false. |
| // It is illegal to attempt to destroy the DefaultArena(). |
| static bool DeleteArena(Arena *arena); |
| |
| // The default arena that always exists. |
| static Arena *DefaultArena(); |
| |
| private: |
| LowLevelAlloc(); // no instances |
| }; |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_ |
| *Î |
| rsoong/.intermediates/external/abseil-cpp/absl_synchronization_hdrs/gen/my_include_dir/absl/synchronization/mutex.hÖ// 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. |
| // |
| // ----------------------------------------------------------------------------- |
| // mutex.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines a `Mutex` -- a mutually exclusive lock -- and the |
| // most common type of synchronization primitive for facilitating locks on |
| // shared resources. A mutex is used to prevent multiple threads from accessing |
| // and/or writing to a shared resource concurrently. |
| // |
| // Unlike a `std::mutex`, the Abseil `Mutex` provides the following additional |
| // features: |
| // * Conditional predicates intrinsic to the `Mutex` object |
| // * Shared/reader locks, in addition to standard exclusive/writer locks |
| // * Deadlock detection and debug support. |
| // |
| // The following helper classes are also defined within this file: |
| // |
| // MutexLock - An RAII wrapper to acquire and release a `Mutex` for exclusive/ |
| // write access within the current scope. |
| // |
| // ReaderMutexLock |
| // - An RAII wrapper to acquire and release a `Mutex` for shared/read |
| // access within the current scope. |
| // |
| // WriterMutexLock |
| // - Effectively an alias for `MutexLock` above, designed for use in |
| // distinguishing reader and writer locks within code. |
| // |
| // In addition to simple mutex locks, this file also defines ways to perform |
| // locking under certain conditions. |
| // |
| // Condition - (Preferred) Used to wait for a particular predicate that |
| // depends on state protected by the `Mutex` to become true. |
| // CondVar - A lower-level variant of `Condition` that relies on |
| // application code to explicitly signal the `CondVar` when |
| // a condition has been met. |
| // |
| // See below for more information on using `Condition` or `CondVar`. |
| // |
| // Mutexes and mutex behavior can be quite complicated. The information within |
| // this header file is limited, as a result. Please consult the Mutex guide for |
| // more complete information and examples. |
| |
| #ifndef ABSL_SYNCHRONIZATION_MUTEX_H_ |
| #define ABSL_SYNCHRONIZATION_MUTEX_H_ |
| |
| #include <atomic> |
| #include <cstdint> |
| #include <cstring> |
| #include <iterator> |
| #include <string> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/const_init.h" |
| #include "absl/base/internal/identity.h" |
| #include "absl/base/internal/low_level_alloc.h" |
| #include "absl/base/internal/thread_identity.h" |
| #include "absl/base/internal/tsan_mutex_interface.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/port.h" |
| #include "absl/base/thread_annotations.h" |
| #include "absl/synchronization/internal/kernel_timeout.h" |
| #include "absl/synchronization/internal/per_thread_sem.h" |
| #include "absl/time/time.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| class Condition; |
| struct SynchWaitParams; |
| |
| // ----------------------------------------------------------------------------- |
| // Mutex |
| // ----------------------------------------------------------------------------- |
| // |
| // A `Mutex` is a non-reentrant (aka non-recursive) Mutually Exclusive lock |
| // on some resource, typically a variable or data structure with associated |
| // invariants. Proper usage of mutexes prevents concurrent access by different |
| // threads to the same resource. |
| // |
| // A `Mutex` has two basic operations: `Mutex::Lock()` and `Mutex::Unlock()`. |
| // The `Lock()` operation *acquires* a `Mutex` (in a state known as an |
| // *exclusive* -- or *write* -- lock), and the `Unlock()` operation *releases* a |
| // Mutex. During the span of time between the Lock() and Unlock() operations, |
| // a mutex is said to be *held*. By design, all mutexes support exclusive/write |
| // locks, as this is the most common way to use a mutex. |
| // |
| // Mutex operations are only allowed under certain conditions; otherwise an |
| // operation is "invalid", and disallowed by the API. The conditions concern |
| // both the current state of the mutex and the identity of the threads that |
| // are performing the operations. |
| // |
| // The `Mutex` state machine for basic lock/unlock operations is quite simple: |
| // |
| // | | Lock() | Unlock() | |
| // |----------------+------------------------+----------| |
| // | Free | Exclusive | invalid | |
| // | Exclusive | blocks, then exclusive | Free | |
| // |
| // The full conditions are as follows. |
| // |
| // * Calls to `Unlock()` require that the mutex be held, and must be made in the |
| // same thread that performed the corresponding `Lock()` operation which |
| // acquired the mutex; otherwise the call is invalid. |
| // |
| // * The mutex being non-reentrant (or non-recursive) means that a call to |
| // `Lock()` or `TryLock()` must not be made in a thread that already holds the |
| // mutex; such a call is invalid. |
| // |
| // * In other words, the state of being "held" has both a temporal component |
| // (from `Lock()` until `Unlock()`) as well as a thread identity component: |
| // the mutex is held *by a particular thread*. |
| // |
| // An "invalid" operation has undefined behavior. The `Mutex` implementation |
| // is allowed to do anything on an invalid call, including, but not limited to, |
| // crashing with a useful error message, silently succeeding, or corrupting |
| // data structures. In debug mode, the implementation may crash with a useful |
| // error message. |
| // |
| // `Mutex` is not guaranteed to be "fair" in prioritizing waiting threads; it |
| // is, however, approximately fair over long periods, and starvation-free for |
| // threads at the same priority. |
| // |
| // The lock/unlock primitives are now annotated with lock annotations |
| // defined in (base/thread_annotations.h). When writing multi-threaded code, |
| // you should use lock annotations whenever possible to document your lock |
| // synchronization policy. Besides acting as documentation, these annotations |
| // also help compilers or static analysis tools to identify and warn about |
| // issues that could potentially result in race conditions and deadlocks. |
| // |
| // For more information about the lock annotations, please see |
| // [Thread Safety |
| // Analysis](http://clang.llvm.org/docs/ThreadSafetyAnalysis.html) in the Clang |
| // documentation. |
| // |
| // See also `MutexLock`, below, for scoped `Mutex` acquisition. |
| |
| class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED Mutex { |
| public: |
| // Creates a `Mutex` that is not held by anyone. This constructor is |
| // typically used for Mutexes allocated on the heap or the stack. |
| // |
| // To create `Mutex` instances with static storage duration |
| // (e.g. a namespace-scoped or global variable), see |
| // `Mutex::Mutex(absl::kConstInit)` below instead. |
| Mutex(); |
| |
| // Creates a mutex with static storage duration. A global variable |
| // constructed this way avoids the lifetime issues that can occur on program |
| // startup and shutdown. (See absl/base/const_init.h.) |
| // |
| // For Mutexes allocated on the heap and stack, instead use the default |
| // constructor, which can interact more fully with the thread sanitizer. |
| // |
| // Example usage: |
| // namespace foo { |
| // ABSL_CONST_INIT absl::Mutex mu(absl::kConstInit); |
| // } |
| explicit constexpr Mutex(absl::ConstInitType); |
| |
| ~Mutex(); |
| |
| // Mutex::Lock() |
| // |
| // Blocks the calling thread, if necessary, until this `Mutex` is free, and |
| // then acquires it exclusively. (This lock is also known as a "write lock.") |
| void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(); |
| |
| // Mutex::Unlock() |
| // |
| // Releases this `Mutex` and returns it from the exclusive/write state to the |
| // free state. Calling thread must hold the `Mutex` exclusively. |
| void Unlock() ABSL_UNLOCK_FUNCTION(); |
| |
| // Mutex::TryLock() |
| // |
| // If the mutex can be acquired without blocking, does so exclusively and |
| // returns `true`. Otherwise, returns `false`. Returns `true` with high |
| // probability if the `Mutex` was free. |
| [[nodiscard]] bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true); |
| |
| // Mutex::AssertHeld() |
| // |
| // Require that the mutex be held exclusively (write mode) by this thread. |
| // |
| // If the mutex is not currently held by this thread, this function may report |
| // an error (typically by crashing with a diagnostic) or it may do nothing. |
| // This function is intended only as a tool to assist debugging; it doesn't |
| // guarantee correctness. |
| void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK(); |
| |
| // --------------------------------------------------------------------------- |
| // Reader-Writer Locking |
| // --------------------------------------------------------------------------- |
| |
| // A Mutex can also be used as a starvation-free reader-writer lock. |
| // Neither read-locks nor write-locks are reentrant/recursive to avoid |
| // potential client programming errors. |
| // |
| // The Mutex API provides `Writer*()` aliases for the existing `Lock()`, |
| // `Unlock()` and `TryLock()` methods for use within applications mixing |
| // reader/writer locks. Using `Reader*()` and `Writer*()` operations in this |
| // manner can make locking behavior clearer when mixing read and write modes. |
| // |
| // Introducing reader locks necessarily complicates the `Mutex` state |
| // machine somewhat. The table below illustrates the allowed state transitions |
| // of a mutex in such cases. Note that ReaderLock() may block even if the lock |
| // is held in shared mode; this occurs when another thread is blocked on a |
| // call to WriterLock(). |
| // |
| // --------------------------------------------------------------------------- |
| // Operation: WriterLock() Unlock() ReaderLock() ReaderUnlock() |
| // --------------------------------------------------------------------------- |
| // State |
| // --------------------------------------------------------------------------- |
| // Free Exclusive invalid Shared(1) invalid |
| // Shared(1) blocks invalid Shared(2) or blocks Free |
| // Shared(n) n>1 blocks invalid Shared(n+1) or blocks Shared(n-1) |
| // Exclusive blocks Free blocks invalid |
| // --------------------------------------------------------------------------- |
| // |
| // In comments below, "shared" refers to a state of Shared(n) for any n > 0. |
| |
| // Mutex::ReaderLock() |
| // |
| // Blocks the calling thread, if necessary, until this `Mutex` is either free, |
| // or in shared mode, and then acquires a share of it. Note that |
| // `ReaderLock()` will block if some other thread has an exclusive/writer lock |
| // on the mutex. |
| |
| void ReaderLock() ABSL_SHARED_LOCK_FUNCTION(); |
| |
| // Mutex::ReaderUnlock() |
| // |
| // Releases a read share of this `Mutex`. `ReaderUnlock` may return a mutex to |
| // the free state if this thread holds the last reader lock on the mutex. Note |
| // that you cannot call `ReaderUnlock()` on a mutex held in write mode. |
| void ReaderUnlock() ABSL_UNLOCK_FUNCTION(); |
| |
| // Mutex::ReaderTryLock() |
| // |
| // If the mutex can be acquired without blocking, acquires this mutex for |
| // shared access and returns `true`. Otherwise, returns `false`. Returns |
| // `true` with high probability if the `Mutex` was free or shared. |
| [[nodiscard]] bool ReaderTryLock() ABSL_SHARED_TRYLOCK_FUNCTION(true); |
| |
| // Mutex::AssertReaderHeld() |
| // |
| // Require that the mutex be held at least in shared mode (read mode) by this |
| // thread. |
| // |
| // If the mutex is not currently held by this thread, this function may report |
| // an error (typically by crashing with a diagnostic) or it may do nothing. |
| // This function is intended only as a tool to assist debugging; it doesn't |
| // guarantee correctness. |
| void AssertReaderHeld() const ABSL_ASSERT_SHARED_LOCK(); |
| |
| // Mutex::WriterLock() |
| // Mutex::WriterUnlock() |
| // Mutex::WriterTryLock() |
| // |
| // Aliases for `Mutex::Lock()`, `Mutex::Unlock()`, and `Mutex::TryLock()`. |
| // |
| // These methods may be used (along with the complementary `Reader*()` |
| // methods) to distinguish simple exclusive `Mutex` usage (`Lock()`, |
| // etc.) from reader/writer lock usage. |
| void WriterLock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { this->Lock(); } |
| |
| void WriterUnlock() ABSL_UNLOCK_FUNCTION() { this->Unlock(); } |
| |
| [[nodiscard]] bool WriterTryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) { |
| return this->TryLock(); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Conditional Critical Regions |
| // --------------------------------------------------------------------------- |
| |
| // Conditional usage of a `Mutex` can occur using two distinct paradigms: |
| // |
| // * Use of `Mutex` member functions with `Condition` objects. |
| // * Use of the separate `CondVar` abstraction. |
| // |
| // In general, prefer use of `Condition` and the `Mutex` member functions |
| // listed below over `CondVar`. When there are multiple threads waiting on |
| // distinctly different conditions, however, a battery of `CondVar`s may be |
| // more efficient. This section discusses use of `Condition` objects. |
| // |
| // `Mutex` contains member functions for performing lock operations only under |
| // certain conditions, of class `Condition`. For correctness, the `Condition` |
| // must return a boolean that is a pure function, only of state protected by |
| // the `Mutex`. The condition must be invariant w.r.t. environmental state |
| // such as thread, cpu id, or time, and must be `noexcept`. The condition will |
| // always be invoked with the mutex held in at least read mode, so you should |
| // not block it for long periods or sleep it on a timer. |
| // |
| // Since a condition must not depend directly on the current time, use |
| // `*WithTimeout()` member function variants to make your condition |
| // effectively true after a given duration, or `*WithDeadline()` variants to |
| // make your condition effectively true after a given time. |
| // |
| // The condition function should have no side-effects aside from debug |
| // logging; as a special exception, the function may acquire other mutexes |
| // provided it releases all those that it acquires. (This exception was |
| // required to allow logging.) |
| |
| // Mutex::Await() |
| // |
| // Unlocks this `Mutex` and blocks until simultaneously both `cond` is `true` |
| // and this `Mutex` can be reacquired, then reacquires this `Mutex` in the |
| // same mode in which it was previously held. If the condition is initially |
| // `true`, `Await()` *may* skip the release/re-acquire step. |
| // |
| // `Await()` requires that this thread holds this `Mutex` in some mode. |
| void Await(const Condition& cond) { |
| AwaitCommon(cond, synchronization_internal::KernelTimeout::Never()); |
| } |
| |
| // Mutex::LockWhen() |
| // Mutex::ReaderLockWhen() |
| // Mutex::WriterLockWhen() |
| // |
| // Blocks until simultaneously both `cond` is `true` and this `Mutex` can |
| // be acquired, then atomically acquires this `Mutex`. `LockWhen()` is |
| // logically equivalent to `*Lock(); Await();` though they may have different |
| // performance characteristics. |
| void LockWhen(const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION() { |
| LockWhenCommon(cond, synchronization_internal::KernelTimeout::Never(), |
| true); |
| } |
| |
| void ReaderLockWhen(const Condition& cond) ABSL_SHARED_LOCK_FUNCTION() { |
| LockWhenCommon(cond, synchronization_internal::KernelTimeout::Never(), |
| false); |
| } |
| |
| void WriterLockWhen(const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION() { |
| this->LockWhen(cond); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Mutex Variants with Timeouts/Deadlines |
| // --------------------------------------------------------------------------- |
| |
| // Mutex::AwaitWithTimeout() |
| // Mutex::AwaitWithDeadline() |
| // |
| // Unlocks this `Mutex` and blocks until simultaneously: |
| // - either `cond` is true or the {timeout has expired, deadline has passed} |
| // and |
| // - this `Mutex` can be reacquired, |
| // then reacquire this `Mutex` in the same mode in which it was previously |
| // held, returning `true` iff `cond` is `true` on return. |
| // |
| // If the condition is initially `true`, the implementation *may* skip the |
| // release/re-acquire step and return immediately. |
| // |
| // Deadlines in the past are equivalent to an immediate deadline. |
| // Negative timeouts are equivalent to a zero timeout. |
| // |
| // This method requires that this thread holds this `Mutex` in some mode. |
| bool AwaitWithTimeout(const Condition& cond, absl::Duration timeout) { |
| return AwaitCommon(cond, synchronization_internal::KernelTimeout{timeout}); |
| } |
| |
| bool AwaitWithDeadline(const Condition& cond, absl::Time deadline) { |
| return AwaitCommon(cond, synchronization_internal::KernelTimeout{deadline}); |
| } |
| |
| // Mutex::LockWhenWithTimeout() |
| // Mutex::ReaderLockWhenWithTimeout() |
| // Mutex::WriterLockWhenWithTimeout() |
| // |
| // Blocks until simultaneously both: |
| // - either `cond` is `true` or the timeout has expired, and |
| // - this `Mutex` can be acquired, |
| // then atomically acquires this `Mutex`, returning `true` iff `cond` is |
| // `true` on return. |
| // |
| // Negative timeouts are equivalent to a zero timeout. |
| bool LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION() { |
| return LockWhenCommon( |
| cond, synchronization_internal::KernelTimeout{timeout}, true); |
| } |
| bool ReaderLockWhenWithTimeout(const Condition& cond, absl::Duration timeout) |
| ABSL_SHARED_LOCK_FUNCTION() { |
| return LockWhenCommon( |
| cond, synchronization_internal::KernelTimeout{timeout}, false); |
| } |
| bool WriterLockWhenWithTimeout(const Condition& cond, absl::Duration timeout) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION() { |
| return this->LockWhenWithTimeout(cond, timeout); |
| } |
| |
| // Mutex::LockWhenWithDeadline() |
| // Mutex::ReaderLockWhenWithDeadline() |
| // Mutex::WriterLockWhenWithDeadline() |
| // |
| // Blocks until simultaneously both: |
| // - either `cond` is `true` or the deadline has been passed, and |
| // - this `Mutex` can be acquired, |
| // then atomically acquires this Mutex, returning `true` iff `cond` is `true` |
| // on return. |
| // |
| // Deadlines in the past are equivalent to an immediate deadline. |
| bool LockWhenWithDeadline(const Condition& cond, absl::Time deadline) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION() { |
| return LockWhenCommon( |
| cond, synchronization_internal::KernelTimeout{deadline}, true); |
| } |
| bool ReaderLockWhenWithDeadline(const Condition& cond, absl::Time deadline) |
| ABSL_SHARED_LOCK_FUNCTION() { |
| return LockWhenCommon( |
| cond, synchronization_internal::KernelTimeout{deadline}, false); |
| } |
| bool WriterLockWhenWithDeadline(const Condition& cond, absl::Time deadline) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION() { |
| return this->LockWhenWithDeadline(cond, deadline); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Debug Support: Invariant Checking, Deadlock Detection, Logging. |
| // --------------------------------------------------------------------------- |
| |
| // Mutex::EnableInvariantDebugging() |
| // |
| // If `invariant`!=null and if invariant debugging has been enabled globally, |
| // cause `(*invariant)(arg)` to be called at moments when the invariant for |
| // this `Mutex` should hold (for example: just after acquire, just before |
| // release). |
| // |
| // The routine `invariant` should have no side-effects since it is not |
| // guaranteed how many times it will be called; it should check the invariant |
| // and crash if it does not hold. Enabling global invariant debugging may |
| // substantially reduce `Mutex` performance; it should be set only for |
| // non-production runs. Optimization options may also disable invariant |
| // checks. |
| void EnableInvariantDebugging( |
| void (*absl_nullable invariant)(void* absl_nullability_unknown), |
| void* absl_nullability_unknown arg); |
| |
| // Mutex::EnableDebugLog() |
| // |
| // Cause all subsequent uses of this `Mutex` to be logged via |
| // `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if no previous |
| // call to `EnableInvariantDebugging()` or `EnableDebugLog()` has been made. |
| // |
| // Note: This method substantially reduces `Mutex` performance. |
| void EnableDebugLog(const char* absl_nullable name); |
| |
| // Deadlock detection |
| |
| // Mutex::ForgetDeadlockInfo() |
| // |
| // Forget any deadlock-detection information previously gathered |
| // about this `Mutex`. Call this method in debug mode when the lock ordering |
| // of a `Mutex` changes. |
| void ForgetDeadlockInfo(); |
| |
| // Mutex::AssertNotHeld() |
| // |
| // Return immediately if this thread does not hold this `Mutex` in any |
| // mode; otherwise, may report an error (typically by crashing with a |
| // diagnostic), or may return immediately. |
| // |
| // Currently this check is performed only if all of: |
| // - in debug mode |
| // - SetMutexDeadlockDetectionMode() has been set to kReport or kAbort |
| // - number of locks concurrently held by this thread is not large. |
| // are true. |
| void AssertNotHeld() const; |
| |
| // Special cases. |
| |
| // A `MuHow` is a constant that indicates how a lock should be acquired. |
| // Internal implementation detail. Clients should ignore. |
| typedef const struct MuHowS* MuHow; |
| |
| // Mutex::InternalAttemptToUseMutexInFatalSignalHandler() |
| // |
| // Causes the `Mutex` implementation to prepare itself for re-entry caused by |
| // future use of `Mutex` within a fatal signal handler. This method is |
| // intended for use only for last-ditch attempts to log crash information. |
| // It does not guarantee that attempts to use Mutexes within the handler will |
| // not deadlock; it merely makes other faults less likely. |
| // |
| // WARNING: This routine must be invoked from a signal handler, and the |
| // signal handler must either loop forever or terminate the process. |
| // Attempts to return from (or `longjmp` out of) the signal handler once this |
| // call has been made may cause arbitrary program behaviour including |
| // crashes and deadlocks. |
| static void InternalAttemptToUseMutexInFatalSignalHandler(); |
| |
| private: |
| std::atomic<intptr_t> mu_; // The Mutex state. |
| |
| // Post()/Wait() versus associated PerThreadSem; in class for required |
| // friendship with PerThreadSem. |
| static void IncrementSynchSem(Mutex* absl_nonnull mu, |
| base_internal::PerThreadSynch* absl_nonnull w); |
| static bool DecrementSynchSem(Mutex* absl_nonnull mu, |
| base_internal::PerThreadSynch* absl_nonnull w, |
| synchronization_internal::KernelTimeout t); |
| |
| // slow path acquire |
| void LockSlowLoop(SynchWaitParams* absl_nonnull waitp, int flags); |
| // wrappers around LockSlowLoop() |
| bool LockSlowWithDeadline(MuHow absl_nonnull how, |
| const Condition* absl_nullable cond, |
| synchronization_internal::KernelTimeout t, |
| int flags); |
| void LockSlow(MuHow absl_nonnull how, const Condition* absl_nullable cond, |
| int flags) ABSL_ATTRIBUTE_COLD; |
| // slow path release |
| void UnlockSlow(SynchWaitParams* absl_nullable waitp) ABSL_ATTRIBUTE_COLD; |
| // TryLock slow path. |
| bool TryLockSlow(); |
| // ReaderTryLock slow path. |
| bool ReaderTryLockSlow(); |
| // Common code between Await() and AwaitWithTimeout/Deadline() |
| bool AwaitCommon(const Condition& cond, |
| synchronization_internal::KernelTimeout t); |
| bool LockWhenCommon(const Condition& cond, |
| synchronization_internal::KernelTimeout t, bool write); |
| // Attempt to remove thread s from queue. |
| void TryRemove(base_internal::PerThreadSynch* absl_nonnull s); |
| // Block a thread on mutex. |
| void Block(base_internal::PerThreadSynch* absl_nonnull s); |
| // Wake a thread; return successor. |
| base_internal::PerThreadSynch* absl_nullable Wakeup( |
| base_internal::PerThreadSynch* absl_nonnull w); |
| void Dtor(); |
| |
| friend class CondVar; // for access to Trans()/Fer(). |
| void Trans(MuHow absl_nonnull how); // used for CondVar->Mutex transfer |
| void Fer(base_internal::PerThreadSynch* absl_nonnull |
| w); // used for CondVar->Mutex transfer |
| |
| // Catch the error of writing Mutex when intending MutexLock. |
| explicit Mutex(const volatile Mutex* absl_nullable /*ignored*/) {} |
| |
| Mutex(const Mutex&) = delete; |
| Mutex& operator=(const Mutex&) = delete; |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // Mutex RAII Wrappers |
| // ----------------------------------------------------------------------------- |
| |
| // MutexLock |
| // |
| // `MutexLock` is a helper class, which acquires and releases a `Mutex` via |
| // RAII. |
| // |
| // Example: |
| // |
| // Class Foo { |
| // public: |
| // Foo::Bar* Baz() { |
| // MutexLock lock(&mu_); |
| // ... |
| // return bar; |
| // } |
| // |
| // private: |
| // Mutex mu_; |
| // }; |
| class ABSL_SCOPED_LOCKABLE MutexLock { |
| public: |
| // Constructors |
| |
| // Calls `mu->Lock()` and returns when that call returns. That is, `*mu` is |
| // guaranteed to be locked when this object is constructed. Requires that |
| // `mu` be dereferenceable. |
| explicit MutexLock(Mutex* absl_nonnull mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) |
| : mu_(mu) { |
| this->mu_->Lock(); |
| } |
| |
| // Like above, but calls `mu->LockWhen(cond)` instead. That is, in addition to |
| // the above, the condition given by `cond` is also guaranteed to hold when |
| // this object is constructed. |
| explicit MutexLock(Mutex* absl_nonnull mu, const Condition& cond) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) |
| : mu_(mu) { |
| this->mu_->LockWhen(cond); |
| } |
| |
| MutexLock(const MutexLock&) = delete; // NOLINT(runtime/mutex) |
| MutexLock(MutexLock&&) = delete; // NOLINT(runtime/mutex) |
| MutexLock& operator=(const MutexLock&) = delete; |
| MutexLock& operator=(MutexLock&&) = delete; |
| |
| ~MutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->Unlock(); } |
| |
| private: |
| Mutex* absl_nonnull const mu_; |
| }; |
| |
| // ReaderMutexLock |
| // |
| // The `ReaderMutexLock` is a helper class, like `MutexLock`, which acquires and |
| // releases a shared lock on a `Mutex` via RAII. |
| class ABSL_SCOPED_LOCKABLE ReaderMutexLock { |
| public: |
| explicit ReaderMutexLock(Mutex* absl_nonnull mu) ABSL_SHARED_LOCK_FUNCTION(mu) |
| : mu_(mu) { |
| mu->ReaderLock(); |
| } |
| |
| explicit ReaderMutexLock(Mutex* absl_nonnull mu, const Condition& cond) |
| ABSL_SHARED_LOCK_FUNCTION(mu) |
| : mu_(mu) { |
| mu->ReaderLockWhen(cond); |
| } |
| |
| ReaderMutexLock(const ReaderMutexLock&) = delete; |
| ReaderMutexLock(ReaderMutexLock&&) = delete; |
| ReaderMutexLock& operator=(const ReaderMutexLock&) = delete; |
| ReaderMutexLock& operator=(ReaderMutexLock&&) = delete; |
| |
| ~ReaderMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->ReaderUnlock(); } |
| |
| private: |
| Mutex* absl_nonnull const mu_; |
| }; |
| |
| // WriterMutexLock |
| // |
| // The `WriterMutexLock` is a helper class, like `MutexLock`, which acquires and |
| // releases a write (exclusive) lock on a `Mutex` via RAII. |
| class ABSL_SCOPED_LOCKABLE WriterMutexLock { |
| public: |
| explicit WriterMutexLock(Mutex* absl_nonnull mu) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) |
| : mu_(mu) { |
| mu->WriterLock(); |
| } |
| |
| explicit WriterMutexLock(Mutex* absl_nonnull mu, const Condition& cond) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) |
| : mu_(mu) { |
| mu->WriterLockWhen(cond); |
| } |
| |
| WriterMutexLock(const WriterMutexLock&) = delete; |
| WriterMutexLock(WriterMutexLock&&) = delete; |
| WriterMutexLock& operator=(const WriterMutexLock&) = delete; |
| WriterMutexLock& operator=(WriterMutexLock&&) = delete; |
| |
| ~WriterMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->WriterUnlock(); } |
| |
| private: |
| Mutex* absl_nonnull const mu_; |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // Condition |
| // ----------------------------------------------------------------------------- |
| // |
| // `Mutex` contains a number of member functions which take a `Condition` as an |
| // argument; clients can wait for conditions to become `true` before attempting |
| // to acquire the mutex. These sections are known as "condition critical" |
| // sections. To use a `Condition`, you simply need to construct it, and use |
| // within an appropriate `Mutex` member function; everything else in the |
| // `Condition` class is an implementation detail. |
| // |
| // A `Condition` is specified as a function pointer which returns a boolean. |
| // `Condition` functions should be pure functions -- their results should depend |
| // only on passed arguments, should not consult any external state (such as |
| // clocks), and should have no side-effects, aside from debug logging. Any |
| // objects that the function may access should be limited to those which are |
| // constant while the mutex is blocked on the condition (e.g. a stack variable), |
| // or objects of state protected explicitly by the mutex. |
| // |
| // No matter which construction is used for `Condition`, the underlying |
| // function pointer / functor / callable must not throw any |
| // exceptions. Correctness of `Mutex` / `Condition` is not guaranteed in |
| // the face of a throwing `Condition`. (When Abseil is allowed to depend |
| // on C++17, these function pointers will be explicitly marked |
| // `noexcept`; until then this requirement cannot be enforced in the |
| // type system.) |
| // |
| // Note: to use a `Condition`, you need only construct it and pass it to a |
| // suitable `Mutex' member function, such as `Mutex::Await()`, or to the |
| // constructor of one of the scope guard classes. |
| // |
| // Example using LockWhen/Unlock: |
| // |
| // // assume count_ is not internal reference count |
| // int count_ ABSL_GUARDED_BY(mu_); |
| // Condition count_is_zero(+[](int *count) { return *count == 0; }, &count_); |
| // |
| // mu_.LockWhen(count_is_zero); |
| // // ... |
| // mu_.Unlock(); |
| // |
| // Example using a scope guard: |
| // |
| // { |
| // MutexLock lock(&mu_, count_is_zero); |
| // // ... |
| // } |
| // |
| // When multiple threads are waiting on exactly the same condition, make sure |
| // that they are constructed with the same parameters (same pointer to function |
| // + arg, or same pointer to object + method), so that the mutex implementation |
| // can avoid redundantly evaluating the same condition for each thread. |
| class Condition { |
| public: |
| // A Condition that returns the result of "(*func)(arg)" |
| Condition(bool (*absl_nonnull func)(void* absl_nullability_unknown), |
| void* absl_nullability_unknown arg); |
| |
| // Templated version for people who are averse to casts. |
| // |
| // To use a lambda, prepend it with unary plus, which converts the lambda |
| // into a function pointer: |
| // Condition(+[](T* t) { return ...; }, arg). |
| // |
| // Note: lambdas in this case must contain no bound variables. |
| // |
| // See class comment for performance advice. |
| template <typename T> |
| Condition(bool (*absl_nonnull func)(T* absl_nullability_unknown), |
| T* absl_nullability_unknown arg); |
| |
| // Same as above, but allows for cases where `arg` comes from a pointer that |
| // is convertible to the function parameter type `T*` but not an exact match. |
| // |
| // For example, the argument might be `X*` but the function takes `const X*`, |
| // or the argument might be `Derived*` while the function takes `Base*`, and |
| // so on for cases where the argument pointer can be implicitly converted. |
| // |
| // Implementation notes: This constructor overload is required in addition to |
| // the one above to allow deduction of `T` from `arg` for cases such as where |
| // a function template is passed as `func`. Also, the dummy `typename = void` |
| // template parameter exists just to work around a MSVC mangling bug. |
| template <typename T, typename = void> |
| Condition( |
| bool (*absl_nonnull func)(T* absl_nullability_unknown), |
| typename absl::internal::type_identity<T>::type* absl_nullability_unknown |
| arg); |
| |
| // Templated version for invoking a method that returns a `bool`. |
| // |
| // `Condition(object, &Class::Method)` constructs a `Condition` that evaluates |
| // `object->Method()`. |
| // |
| // Implementation Note: `absl::internal::type_identity` is used to allow |
| // methods to come from base classes. A simpler signature like |
| // `Condition(T*, bool (T::*)())` does not suffice. |
| template <typename T> |
| Condition( |
| T* absl_nonnull object, |
| bool (absl::internal::type_identity<T>::type::* absl_nonnull method)()); |
| |
| // Same as above, for const members |
| template <typename T> |
| Condition( |
| const T* absl_nonnull object, |
| bool (absl::internal::type_identity<T>::type::* absl_nonnull method)() |
| const); |
| |
| // A Condition that returns the value of `*cond` |
| explicit Condition(const bool* absl_nonnull cond); |
| |
| // Templated version for invoking a functor that returns a `bool`. |
| // This approach accepts pointers to non-mutable lambdas, `std::function`, |
| // the result of` std::bind` and user-defined functors that define |
| // `bool F::operator()() const`. |
| // |
| // Example: |
| // |
| // auto reached = [this, current]() { |
| // mu_.AssertReaderHeld(); // For annotalysis. |
| // return processed_ >= current; |
| // }; |
| // mu_.Await(Condition(&reached)); |
| // |
| // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReaderHeld()" in |
| // the lambda as it may be called when the mutex is being unlocked from a |
| // scope holding only a reader lock, which will make the assertion not |
| // fulfilled and crash the binary. |
| |
| // See class comment for performance advice. In particular, if there |
| // might be more than one waiter for the same condition, make sure |
| // that all waiters construct the condition with the same pointers. |
| |
| // Implementation note: The second template parameter ensures that this |
| // constructor doesn't participate in overload resolution if T doesn't have |
| // `bool operator() const`. |
| template <typename T, typename E = decltype(static_cast<bool (T::*)() const>( |
| &T::operator()))> |
| explicit Condition(const T* absl_nonnull obj) |
| : Condition(obj, static_cast<bool (T::*)() const>(&T::operator())) {} |
| |
| // A Condition that always returns `true`. |
| // kTrue is only useful in a narrow set of circumstances, mostly when |
| // it's passed conditionally. For example: |
| // |
| // mu.LockWhen(some_flag ? kTrue : SomeOtherCondition); |
| // |
| // Note: {LockWhen,Await}With{Deadline,Timeout} methods with kTrue condition |
| // don't return immediately when the timeout happens, they still block until |
| // the Mutex becomes available. The return value of these methods does |
| // not indicate if the timeout was reached; rather it indicates whether or |
| // not the condition is true. |
| ABSL_CONST_INIT static const Condition kTrue; |
| |
| // Evaluates the condition. |
| bool Eval() const; |
| |
| // Returns `true` if the two conditions are guaranteed to return the same |
| // value if evaluated at the same time, `false` if the evaluation *may* return |
| // different results. |
| // |
| // Two `Condition` values are guaranteed equal if both their `func` and `arg` |
| // components are the same. A null pointer is equivalent to a `true` |
| // condition. |
| static bool GuaranteedEqual(const Condition* absl_nullable a, |
| const Condition* absl_nullable b); |
| |
| private: |
| // Sizing an allocation for a method pointer can be subtle. In the Itanium |
| // specifications, a method pointer has a predictable, uniform size. On the |
| // other hand, MSVC ABI, method pointer sizes vary based on the |
| // inheritance of the class. Specifically, method pointers from classes with |
| // multiple inheritance are bigger than those of classes with single |
| // inheritance. Other variations also exist. |
| |
| #ifndef _MSC_VER |
| // Allocation for a function pointer or method pointer. |
| // The {0} initializer ensures that all unused bytes of this buffer are |
| // always zeroed out. This is necessary, because GuaranteedEqual() compares |
| // all of the bytes, unaware of which bytes are relevant to a given `eval_`. |
| using MethodPtr = bool (Condition::*)(); |
| char callback_[sizeof(MethodPtr)] = {0}; |
| #else |
| // It is well known that the larget MSVC pointer-to-member is 24 bytes. This |
| // may be the largest known pointer-to-member of any platform. For this |
| // reason we will allocate 24 bytes for MSVC platform toolchains. |
| char callback_[24] = {0}; |
| #endif |
| |
| // Function with which to evaluate callbacks and/or arguments. |
| bool (*absl_nullable eval_)(const Condition* absl_nonnull) = nullptr; |
| |
| // Either an argument for a function call or an object for a method call. |
| void* absl_nullable arg_ = nullptr; |
| |
| // Various functions eval_ can point to: |
| static bool CallVoidPtrFunction(const Condition* absl_nonnull c); |
| template <typename T> |
| static bool CastAndCallFunction(const Condition* absl_nonnull c); |
| template <typename T, typename ConditionMethodPtr> |
| static bool CastAndCallMethod(const Condition* absl_nonnull c); |
| |
| // Helper methods for storing, validating, and reading callback arguments. |
| template <typename T> |
| inline void StoreCallback(T callback) { |
| static_assert( |
| sizeof(callback) <= sizeof(callback_), |
| "An overlarge pointer was passed as a callback to Condition."); |
| std::memcpy(callback_, &callback, sizeof(callback)); |
| } |
| |
| template <typename T> |
| inline void ReadCallback(T* absl_nonnull callback) const { |
| std::memcpy(callback, callback_, sizeof(*callback)); |
| } |
| |
| static bool AlwaysTrue(const Condition* absl_nullable) { return true; } |
| |
| // Used only to create kTrue. |
| constexpr Condition() : eval_(AlwaysTrue), arg_(nullptr) {} |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // CondVar |
| // ----------------------------------------------------------------------------- |
| // |
| // A condition variable, reflecting state evaluated separately outside of the |
| // `Mutex` object, which can be signaled to wake callers. |
| // This class is not normally needed; use `Mutex` member functions such as |
| // `Mutex::Await()` and intrinsic `Condition` abstractions. In rare cases |
| // with many threads and many conditions, `CondVar` may be faster. |
| // |
| // The implementation may deliver signals to any condition variable at |
| // any time, even when no call to `Signal()` or `SignalAll()` is made; as a |
| // result, upon being awoken, you must check the logical condition you have |
| // been waiting upon. |
| // |
| // Examples: |
| // |
| // Usage for a thread waiting for some condition C protected by mutex mu: |
| // mu.Lock(); |
| // while (!C) { cv->Wait(&mu); } // releases and reacquires mu |
| // // C holds; process data |
| // mu.Unlock(); |
| // |
| // Usage to wake T is: |
| // mu.Lock(); |
| // // process data, possibly establishing C |
| // if (C) { cv->Signal(); } |
| // mu.Unlock(); |
| // |
| // If C may be useful to more than one waiter, use `SignalAll()` instead of |
| // `Signal()`. |
| // |
| // With this implementation it is efficient to use `Signal()/SignalAll()` inside |
| // the locked region; this usage can make reasoning about your program easier. |
| // |
| class CondVar { |
| public: |
| // A `CondVar` allocated on the heap or on the stack can use the this |
| // constructor. |
| CondVar(); |
| |
| // CondVar::Wait() |
| // |
| // Atomically releases a `Mutex` and blocks on this condition variable. |
| // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a |
| // spurious wakeup), then reacquires the `Mutex` and returns. |
| // |
| // Requires and ensures that the current thread holds the `Mutex`. |
| void Wait(Mutex* absl_nonnull mu) { |
| WaitCommon(mu, synchronization_internal::KernelTimeout::Never()); |
| } |
| |
| // CondVar::WaitWithTimeout() |
| // |
| // Atomically releases a `Mutex` and blocks on this condition variable. |
| // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a |
| // spurious wakeup), or until the timeout has expired, then reacquires |
| // the `Mutex` and returns. |
| // |
| // Returns true if the timeout has expired without this `CondVar` |
| // being signalled in any manner. If both the timeout has expired |
| // and this `CondVar` has been signalled, the implementation is free |
| // to return `true` or `false`. |
| // |
| // Requires and ensures that the current thread holds the `Mutex`. |
| bool WaitWithTimeout(Mutex* absl_nonnull mu, absl::Duration timeout) { |
| return WaitCommon(mu, synchronization_internal::KernelTimeout(timeout)); |
| } |
| |
| // CondVar::WaitWithDeadline() |
| // |
| // Atomically releases a `Mutex` and blocks on this condition variable. |
| // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a |
| // spurious wakeup), or until the deadline has passed, then reacquires |
| // the `Mutex` and returns. |
| // |
| // Deadlines in the past are equivalent to an immediate deadline. |
| // |
| // Returns true if the deadline has passed without this `CondVar` |
| // being signalled in any manner. If both the deadline has passed |
| // and this `CondVar` has been signalled, the implementation is free |
| // to return `true` or `false`. |
| // |
| // Requires and ensures that the current thread holds the `Mutex`. |
| bool WaitWithDeadline(Mutex* absl_nonnull mu, absl::Time deadline) { |
| return WaitCommon(mu, synchronization_internal::KernelTimeout(deadline)); |
| } |
| |
| // CondVar::Signal() |
| // |
| // Signal this `CondVar`; wake at least one waiter if one exists. |
| void Signal(); |
| |
| // CondVar::SignalAll() |
| // |
| // Signal this `CondVar`; wake all waiters. |
| void SignalAll(); |
| |
| // CondVar::EnableDebugLog() |
| // |
| // Causes all subsequent uses of this `CondVar` to be logged via |
| // `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if `name != 0`. |
| // Note: this method substantially reduces `CondVar` performance. |
| void EnableDebugLog(const char* absl_nullable name); |
| |
| private: |
| bool WaitCommon(Mutex* absl_nonnull mutex, |
| synchronization_internal::KernelTimeout t); |
| void Remove(base_internal::PerThreadSynch* absl_nonnull s); |
| std::atomic<intptr_t> cv_; // Condition variable state. |
| CondVar(const CondVar&) = delete; |
| CondVar& operator=(const CondVar&) = delete; |
| }; |
| |
| // Variants of MutexLock. |
| // |
| // If you find yourself using one of these, consider instead using |
| // Mutex::Unlock() and/or if-statements for clarity. |
| |
| // MutexLockMaybe |
| // |
| // MutexLockMaybe is like MutexLock, but is a no-op when mu is null. |
| class ABSL_SCOPED_LOCKABLE MutexLockMaybe { |
| public: |
| explicit MutexLockMaybe(Mutex* absl_nullable mu) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) |
| : mu_(mu) { |
| if (this->mu_ != nullptr) { |
| this->mu_->Lock(); |
| } |
| } |
| |
| explicit MutexLockMaybe(Mutex* absl_nullable mu, const Condition& cond) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) |
| : mu_(mu) { |
| if (this->mu_ != nullptr) { |
| this->mu_->LockWhen(cond); |
| } |
| } |
| |
| ~MutexLockMaybe() ABSL_UNLOCK_FUNCTION() { |
| if (this->mu_ != nullptr) { |
| this->mu_->Unlock(); |
| } |
| } |
| |
| private: |
| Mutex* absl_nullable const mu_; |
| MutexLockMaybe(const MutexLockMaybe&) = delete; |
| MutexLockMaybe(MutexLockMaybe&&) = delete; |
| MutexLockMaybe& operator=(const MutexLockMaybe&) = delete; |
| MutexLockMaybe& operator=(MutexLockMaybe&&) = delete; |
| }; |
| |
| // ReleasableMutexLock |
| // |
| // ReleasableMutexLock is like MutexLock, but permits `Release()` of its |
| // mutex before destruction. `Release()` may be called at most once. |
| class ABSL_SCOPED_LOCKABLE ReleasableMutexLock { |
| public: |
| explicit ReleasableMutexLock(Mutex* absl_nonnull mu) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) |
| : mu_(mu) { |
| this->mu_->Lock(); |
| } |
| |
| explicit ReleasableMutexLock(Mutex* absl_nonnull mu, const Condition& cond) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) |
| : mu_(mu) { |
| this->mu_->LockWhen(cond); |
| } |
| |
| ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() { |
| if (this->mu_ != nullptr) { |
| this->mu_->Unlock(); |
| } |
| } |
| |
| void Release() ABSL_UNLOCK_FUNCTION(); |
| |
| private: |
| Mutex* absl_nonnull mu_; |
| ReleasableMutexLock(const ReleasableMutexLock&) = delete; |
| ReleasableMutexLock(ReleasableMutexLock&&) = delete; |
| ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete; |
| ReleasableMutexLock& operator=(ReleasableMutexLock&&) = delete; |
| }; |
| |
| inline Mutex::Mutex() : mu_(0) { |
| ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); |
| } |
| |
| inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {} |
| |
| #if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL) |
| ABSL_ATTRIBUTE_ALWAYS_INLINE |
| inline Mutex::~Mutex() { Dtor(); } |
| #endif |
| |
| #if defined(NDEBUG) && !defined(ABSL_HAVE_THREAD_SANITIZER) |
| // Use default (empty) destructor in release build for performance reasons. |
| // We need to mark both Dtor and ~Mutex as always inline for inconsistent |
| // builds that use both NDEBUG and !NDEBUG with dynamic libraries. In these |
| // cases we want the empty functions to dissolve entirely rather than being |
| // exported from dynamic libraries and potentially override the non-empty ones. |
| ABSL_ATTRIBUTE_ALWAYS_INLINE |
| inline void Mutex::Dtor() {} |
| #endif |
| |
| inline CondVar::CondVar() : cv_(0) {} |
| |
| // static |
| template <typename T, typename ConditionMethodPtr> |
| bool Condition::CastAndCallMethod(const Condition* absl_nonnull c) { |
| T* object = static_cast<T*>(c->arg_); |
| ConditionMethodPtr condition_method_pointer; |
| c->ReadCallback(&condition_method_pointer); |
| return (object->*condition_method_pointer)(); |
| } |
| |
| // static |
| template <typename T> |
| bool Condition::CastAndCallFunction(const Condition* absl_nonnull c) { |
| bool (*function)(T*); |
| c->ReadCallback(&function); |
| T* argument = static_cast<T*>(c->arg_); |
| return (*function)(argument); |
| } |
| |
| template <typename T> |
| inline Condition::Condition( |
| bool (*absl_nonnull func)(T* absl_nullability_unknown), |
| T* absl_nullability_unknown arg) |
| : eval_(&CastAndCallFunction<T>), |
| arg_(const_cast<void*>(static_cast<const void*>(arg))) { |
| static_assert(sizeof(&func) <= sizeof(callback_), |
| "An overlarge function pointer was passed to Condition."); |
| StoreCallback(func); |
| } |
| |
| template <typename T, typename> |
| inline Condition::Condition( |
| bool (*absl_nonnull func)(T* absl_nullability_unknown), |
| typename absl::internal::type_identity<T>::type* absl_nullability_unknown |
| arg) |
| // Just delegate to the overload above. |
| : Condition(func, arg) {} |
| |
| template <typename T> |
| inline Condition::Condition( |
| T* absl_nonnull object, |
| bool (absl::internal::type_identity<T>::type::* absl_nonnull method)()) |
| : eval_(&CastAndCallMethod<T, decltype(method)>), arg_(object) { |
| static_assert(sizeof(&method) <= sizeof(callback_), |
| "An overlarge method pointer was passed to Condition."); |
| StoreCallback(method); |
| } |
| |
| template <typename T> |
| inline Condition::Condition( |
| const T* absl_nonnull object, |
| bool (absl::internal::type_identity<T>::type::* absl_nonnull method)() |
| const) |
| : eval_(&CastAndCallMethod<const T, decltype(method)>), |
| arg_(reinterpret_cast<void*>(const_cast<T*>(object))) { |
| StoreCallback(method); |
| } |
| |
| // Register hooks for profiling support. |
| // |
| // The function pointer registered here will be called whenever a mutex is |
| // contended. The callback is given the cycles for which waiting happened (as |
| // measured by //absl/base/internal/cycleclock.h, and which may not |
| // be real "cycle" counts.) |
| // |
| // There is no ordering guarantee between when the hook is registered and when |
| // callbacks will begin. Only a single profiler can be installed in a running |
| // binary; if this function is called a second time with a different function |
| // pointer, the value is ignored (and will cause an assertion failure in debug |
| // mode.) |
| void RegisterMutexProfiler(void (*absl_nonnull fn)(int64_t wait_cycles)); |
| |
| // Register a hook for Mutex tracing. |
| // |
| // The function pointer registered here will be called whenever a mutex is |
| // contended. The callback is given an opaque handle to the contended mutex, |
| // an event name, and the number of wait cycles (as measured by |
| // //absl/base/internal/cycleclock.h, and which may not be real |
| // "cycle" counts.) |
| // |
| // The only event name currently sent is "slow release". |
| // |
| // This has the same ordering and single-use limitations as |
| // RegisterMutexProfiler() above. |
| void RegisterMutexTracer(void (*absl_nonnull fn)(const char* absl_nonnull msg, |
| const void* absl_nonnull obj, |
| int64_t wait_cycles)); |
| |
| // Register a hook for CondVar tracing. |
| // |
| // The function pointer registered here will be called here on various CondVar |
| // events. The callback is given an opaque handle to the CondVar object and |
| // a string identifying the event. This is thread-safe, but only a single |
| // tracer can be registered. |
| // |
| // Events that can be sent are "Wait", "Unwait", "Signal wakeup", and |
| // "SignalAll wakeup". |
| // |
| // This has the same ordering and single-use limitations as |
| // RegisterMutexProfiler() above. |
| void RegisterCondVarTracer(void (*absl_nonnull fn)( |
| const char* absl_nonnull msg, const void* absl_nonnull cv)); |
| |
| // EnableMutexInvariantDebugging() |
| // |
| // Enable or disable global support for Mutex invariant debugging. If enabled, |
| // then invariant predicates can be registered per-Mutex for debug checking. |
| // See Mutex::EnableInvariantDebugging(). |
| void EnableMutexInvariantDebugging(bool enabled); |
| |
| // When in debug mode, and when the feature has been enabled globally, the |
| // implementation will keep track of lock ordering and complain (or optionally |
| // crash) if a cycle is detected in the acquired-before graph. |
| |
| // Possible modes of operation for the deadlock detector in debug mode. |
| enum class OnDeadlockCycle { |
| kIgnore, // Neither report on nor attempt to track cycles in lock ordering |
| kReport, // Report lock cycles to stderr when detected |
| kAbort, // Report lock cycles to stderr when detected, then abort |
| }; |
| |
| // SetMutexDeadlockDetectionMode() |
| // |
| // Enable or disable global support for detection of potential deadlocks |
| // due to Mutex lock ordering inversions. When set to 'kIgnore', tracking of |
| // lock ordering is disabled. Otherwise, in debug builds, a lock ordering graph |
| // will be maintained internally, and detected cycles will be reported in |
| // the manner chosen here. |
| void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode); |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| // In some build configurations we pass --detect-odr-violations to the |
| // gold linker. This causes it to flag weak symbol overrides as ODR |
| // violations. Because ODR only applies to C++ and not C, |
| // --detect-odr-violations ignores symbols not mangled with C++ names. |
| // By changing our extension points to be extern "C", we dodge this |
| // check. |
| extern "C" { |
| void ABSL_INTERNAL_C_SYMBOL(AbslInternalMutexYield)(); |
| } // extern "C" |
| |
| #endif // ABSL_SYNCHRONIZATION_MUTEX_H_ |
| *¦ |
| soong/.intermediates/external/abseil-cpp/absl_strings_cordz_update_tracker_hdrs/gen/my_include_dir/absl/strings/internal/cordz_update_tracker.h// 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_STRINGS_INTERNAL_CORDZ_UPDATE_TRACKER_H_ |
| #define ABSL_STRINGS_INTERNAL_CORDZ_UPDATE_TRACKER_H_ |
| |
| #include <atomic> |
| #include <cstdint> |
| |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // CordzUpdateTracker tracks counters for Cord update methods. |
| // |
| // The purpose of CordzUpdateTracker is to track the number of calls to methods |
| // updating Cord data for sampled cords. The class internally uses 'lossy' |
| // atomic operations: Cord is thread-compatible, so there is no need to |
| // synchronize updates. However, Cordz collection threads may call 'Value()' at |
| // any point, so the class needs to provide thread safe access. |
| // |
| // This class is thread-safe. But as per above comments, all non-const methods |
| // should be used single-threaded only: updates are thread-safe but lossy. |
| class CordzUpdateTracker { |
| public: |
| // Tracked update methods. |
| enum MethodIdentifier { |
| kUnknown, |
| kAppendCord, |
| kAppendCordBuffer, |
| kAppendExternalMemory, |
| kAppendString, |
| kAssignCord, |
| kAssignString, |
| kClear, |
| kConstructorCord, |
| kConstructorString, |
| kCordReader, |
| kFlatten, |
| kGetAppendBuffer, |
| kGetAppendRegion, |
| kMakeCordFromExternal, |
| kMoveAppendCord, |
| kMoveAssignCord, |
| kMovePrependCord, |
| kPrependCord, |
| kPrependCordBuffer, |
| kPrependString, |
| kRemovePrefix, |
| kRemoveSuffix, |
| kSetExpectedChecksum, |
| kSubCord, |
| |
| // kNumMethods defines the number of entries: must be the last entry. |
| kNumMethods, |
| }; |
| |
| // Constructs a new instance. All counters are zero-initialized. |
| constexpr CordzUpdateTracker() noexcept : values_{} {} |
| |
| // Copy constructs a new instance. |
| CordzUpdateTracker(const CordzUpdateTracker& rhs) noexcept { *this = rhs; } |
| |
| // Assigns the provided value to this instance. |
| CordzUpdateTracker& operator=(const CordzUpdateTracker& rhs) noexcept { |
| for (int i = 0; i < kNumMethods; ++i) { |
| values_[i].store(rhs.values_[i].load(std::memory_order_relaxed), |
| std::memory_order_relaxed); |
| } |
| return *this; |
| } |
| |
| // Returns the value for the specified method. |
| int64_t Value(MethodIdentifier method) const { |
| return values_[method].load(std::memory_order_relaxed); |
| } |
| |
| // Increases the value for the specified method by `n` |
| void LossyAdd(MethodIdentifier method, int64_t n = 1) { |
| auto& value = values_[method]; |
| value.store(value.load(std::memory_order_relaxed) + n, |
| std::memory_order_relaxed); |
| } |
| |
| // Adds all the values from `src` to this instance |
| void LossyAdd(const CordzUpdateTracker& src) { |
| for (int i = 0; i < kNumMethods; ++i) { |
| MethodIdentifier method = static_cast<MethodIdentifier>(i); |
| if (int64_t value = src.Value(method)) { |
| LossyAdd(method, value); |
| } |
| } |
| } |
| |
| private: |
| // Until C++20 std::atomic is not constexpr default-constructible, so we need |
| // a wrapper for this class to be constexpr constructible. |
| class Counter : public std::atomic<int64_t> { |
| public: |
| constexpr Counter() noexcept : std::atomic<int64_t>(0) {} |
| }; |
| |
| Counter values_[kNumMethods]; |
| }; |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORDZ_UPDATE_TRACKER_H_ |
| *Ô& |
| tsoong/.intermediates/external/abseil-cpp/absl_base_hdrs/gen/my_include_dir/absl/base/internal/low_level_scheduling.hÛ%// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // Core interfaces and definitions used by by low-level interfaces such as |
| // SpinLock. |
| |
| #ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ |
| #define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ |
| |
| #include "absl/base/internal/raw_logging.h" |
| #include "absl/base/internal/scheduling_mode.h" |
| #include "absl/base/macros.h" |
| |
| // The following two declarations exist so SchedulingGuard may friend them with |
| // the appropriate language linkage. These callbacks allow libc internals, such |
| // as function level statics, to schedule cooperatively when locking. |
| extern "C" bool __google_disable_rescheduling(void); |
| extern "C" void __google_enable_rescheduling(bool disable_result); |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| class CondVar; |
| class Mutex; |
| |
| namespace synchronization_internal { |
| int MutexDelay(int32_t c, int mode); |
| } // namespace synchronization_internal |
| |
| namespace base_internal { |
| |
| class SchedulingHelper; // To allow use of SchedulingGuard. |
| class SpinLock; // To allow use of SchedulingGuard. |
| |
| // SchedulingGuard |
| // Provides guard semantics that may be used to disable cooperative rescheduling |
| // of the calling thread within specific program blocks. This is used to |
| // protect resources (e.g. low-level SpinLocks or Domain code) that cooperative |
| // scheduling depends on. |
| // |
| // Domain implementations capable of rescheduling in reaction to involuntary |
| // kernel thread actions (e.g blocking due to a pagefault or syscall) must |
| // guarantee that an annotated thread is not allowed to (cooperatively) |
| // reschedule until the annotated region is complete. |
| // |
| // It is an error to attempt to use a cooperatively scheduled resource (e.g. |
| // Mutex) within a rescheduling-disabled region. |
| // |
| // All methods are async-signal safe. |
| class SchedulingGuard { |
| public: |
| // Returns true iff the calling thread may be cooperatively rescheduled. |
| static bool ReschedulingIsAllowed(); |
| SchedulingGuard(const SchedulingGuard&) = delete; |
| SchedulingGuard& operator=(const SchedulingGuard&) = delete; |
| |
| private: |
| // Disable cooperative rescheduling of the calling thread. It may still |
| // initiate scheduling operations (e.g. wake-ups), however, it may not itself |
| // reschedule. Nestable. The returned result is opaque, clients should not |
| // attempt to interpret it. |
| // REQUIRES: Result must be passed to a pairing EnableScheduling(). |
| static bool DisableRescheduling(); |
| |
| // Marks the end of a rescheduling disabled region, previously started by |
| // DisableRescheduling(). |
| // REQUIRES: Pairs with innermost call (and result) of DisableRescheduling(). |
| static void EnableRescheduling(bool disable_result); |
| |
| // A scoped helper for {Disable, Enable}Rescheduling(). |
| // REQUIRES: destructor must run in same thread as constructor. |
| struct ScopedDisable { |
| ScopedDisable() { disabled = SchedulingGuard::DisableRescheduling(); } |
| ~ScopedDisable() { SchedulingGuard::EnableRescheduling(disabled); } |
| |
| bool disabled; |
| }; |
| |
| // A scoped helper to enable rescheduling temporarily. |
| // REQUIRES: destructor must run in same thread as constructor. |
| class ScopedEnable { |
| public: |
| ScopedEnable(); |
| ~ScopedEnable(); |
| |
| private: |
| int scheduling_disabled_depth_; |
| }; |
| |
| // Access to SchedulingGuard is explicitly permitted. |
| friend class absl::CondVar; |
| friend class absl::Mutex; |
| friend class SchedulingHelper; |
| friend class SpinLock; |
| friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode); |
| }; |
| |
| //------------------------------------------------------------------------------ |
| // End of public interfaces. |
| //------------------------------------------------------------------------------ |
| |
| inline bool SchedulingGuard::ReschedulingIsAllowed() { |
| return false; |
| } |
| |
| inline bool SchedulingGuard::DisableRescheduling() { |
| return false; |
| } |
| |
| inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) { |
| return; |
| } |
| |
| inline SchedulingGuard::ScopedEnable::ScopedEnable() |
| : scheduling_disabled_depth_(0) {} |
| inline SchedulingGuard::ScopedEnable::~ScopedEnable() { |
| ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning"); |
| } |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ |
| *× |
| ~soong/.intermediates/external/abseil-cpp/absl_base_dynamic_annotations_hdrs/gen/my_include_dir/absl/base/dynamic_annotations.hÓ// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // This file defines dynamic annotations for use with dynamic analysis tool |
| // such as valgrind, PIN, etc. |
| // |
| // Dynamic annotation is a source code annotation that affects the generated |
| // code (that is, the annotation is not a comment). Each such annotation is |
| // attached to a particular instruction and/or to a particular object (address) |
| // in the program. |
| // |
| // The annotations that should be used by users are macros in all upper-case |
| // (e.g., ABSL_ANNOTATE_THREAD_NAME). |
| // |
| // Actual implementation of these macros may differ depending on the dynamic |
| // analysis tool being used. |
| // |
| // This file supports the following configurations: |
| // - Dynamic Annotations enabled (with static thread-safety warnings disabled). |
| // In this case, macros expand to functions implemented by Thread Sanitizer, |
| // when building with TSan. When not provided an external implementation, |
| // dynamic_annotations.cc provides no-op implementations. |
| // |
| // - Static Clang thread-safety warnings enabled. |
| // When building with a Clang compiler that supports thread-safety warnings, |
| // a subset of annotations can be statically-checked at compile-time. We |
| // expand these macros to static-inline functions that can be analyzed for |
| // thread-safety, but afterwards elided when building the final binary. |
| // |
| // - All annotations are disabled. |
| // If neither Dynamic Annotations nor Clang thread-safety warnings are |
| // enabled, then all annotation-macros expand to empty. |
| |
| #ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ |
| #define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #ifdef __cplusplus |
| #include "absl/base/macros.h" |
| #endif |
| |
| #ifdef ABSL_HAVE_HWADDRESS_SANITIZER |
| #include <sanitizer/hwasan_interface.h> |
| #endif |
| |
| // TODO(rogeeff): Remove after the backward compatibility period. |
| #include "absl/base/internal/dynamic_annotations.h" // IWYU pragma: export |
| |
| // ------------------------------------------------------------------------- |
| // Decide which features are enabled. |
| |
| #ifdef ABSL_HAVE_THREAD_SANITIZER |
| |
| #define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1 |
| #define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1 |
| #define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1 |
| #define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0 |
| #define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1 |
| |
| #else |
| |
| #define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0 |
| #define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0 |
| #define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0 |
| |
| // Clang provides limited support for static thread-safety analysis through a |
| // feature called Annotalysis. We configure macro-definitions according to |
| // whether Annotalysis support is available. When running in opt-mode, GCC |
| // will issue a warning, if these attributes are compiled. Only include them |
| // when compiling using Clang. |
| |
| #if defined(__clang__) |
| #define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 1 |
| #if !defined(SWIG) |
| #define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1 |
| #endif |
| #else |
| #define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0 |
| #endif |
| |
| // Read/write annotations are enabled in Annotalysis mode; disabled otherwise. |
| #define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \ |
| ABSL_INTERNAL_ANNOTALYSIS_ENABLED |
| |
| #endif // ABSL_HAVE_THREAD_SANITIZER |
| |
| #ifdef __cplusplus |
| #define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" { |
| #define ABSL_INTERNAL_END_EXTERN_C } // extern "C" |
| #define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F |
| #define ABSL_INTERNAL_STATIC_INLINE inline |
| #else |
| #define ABSL_INTERNAL_BEGIN_EXTERN_C // empty |
| #define ABSL_INTERNAL_END_EXTERN_C // empty |
| #define ABSL_INTERNAL_GLOBAL_SCOPED(F) F |
| #define ABSL_INTERNAL_STATIC_INLINE static inline |
| #endif |
| |
| // ------------------------------------------------------------------------- |
| // Define race annotations. |
| |
| #if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1 |
| // Some of the symbols used in this section (e.g. AnnotateBenignRaceSized) are |
| // defined by the compiler-based sanitizer 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) |
| |
| #define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty |
| #define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty |
| |
| #endif // ABSL_HAVE_MEMORY_SANITIZER |
| |
| // ------------------------------------------------------------------------- |
| // Define IGNORE_READS_BEGIN/_END attributes. |
| |
| #if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED) |
| |
| #define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \ |
| __attribute((exclusive_lock_function("*"))) |
| #define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \ |
| __attribute((unlock_function("*"))) |
| |
| #else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED) |
| |
| #define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty |
| #define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty |
| |
| #endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED) |
| |
| // ------------------------------------------------------------------------- |
| // Define IGNORE_READS_BEGIN/_END annotations. |
| |
| #if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1 |
| // Some of the symbols used in this section (e.g. AnnotateIgnoreReadsBegin) are |
| // defined by the compiler-based implementation, not by the Abseil |
| // library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL. |
| |
| // Request the analysis tool to ignore all reads in the current thread until |
| // ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey |
| // reads, while still checking other reads and all writes. |
| // See also ABSL_ANNOTATE_UNPROTECTED_READ. |
| #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ |
| ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin) \ |
| (__FILE__, __LINE__) |
| |
| // Stop ignoring reads. |
| #define ABSL_ANNOTATE_IGNORE_READS_END() \ |
| ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd) \ |
| (__FILE__, __LINE__) |
| |
| // Function prototypes of annotations provided by the compiler-based sanitizer |
| // implementation. |
| ABSL_INTERNAL_BEGIN_EXTERN_C |
| void AnnotateIgnoreReadsBegin(const char* file, int line) |
| ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE; |
| void AnnotateIgnoreReadsEnd(const char* file, |
| int line) ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE; |
| ABSL_INTERNAL_END_EXTERN_C |
| |
| #elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED) |
| |
| // When Annotalysis is enabled without Dynamic Annotations, the use of |
| // static-inline functions allows the annotations to be read at compile-time, |
| // while still letting the compiler elide the functions from the final build. |
| // |
| // TODO(delesley) -- The exclusive lock here ignores writes as well, but |
| // allows IGNORE_READS_AND_WRITES to work properly. |
| |
| #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ |
| ABSL_INTERNAL_GLOBAL_SCOPED( \ |
| ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsBegin)) \ |
| () |
| |
| #define ABSL_ANNOTATE_IGNORE_READS_END() \ |
| ABSL_INTERNAL_GLOBAL_SCOPED( \ |
| ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsEnd)) \ |
| () |
| |
| ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL( |
| AbslInternalAnnotateIgnoreReadsBegin)() |
| ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {} |
| |
| ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL( |
| AbslInternalAnnotateIgnoreReadsEnd)() |
| ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {} |
| |
| #else |
| |
| #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() // empty |
| #define ABSL_ANNOTATE_IGNORE_READS_END() // empty |
| |
| #endif |
| |
| // ------------------------------------------------------------------------- |
| // Define IGNORE_WRITES_BEGIN/_END annotations. |
| |
| #if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1 |
| |
| // Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. |
| #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \ |
| ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__) |
| |
| // Stop ignoring writes. |
| #define ABSL_ANNOTATE_IGNORE_WRITES_END() \ |
| ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__) |
| |
| // Function prototypes of annotations provided by the compiler-based sanitizer |
| // implementation. |
| ABSL_INTERNAL_BEGIN_EXTERN_C |
| void AnnotateIgnoreWritesBegin(const char* file, int line); |
| void AnnotateIgnoreWritesEnd(const char* file, int line); |
| ABSL_INTERNAL_END_EXTERN_C |
| |
| #else |
| |
| #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() // empty |
| #define ABSL_ANNOTATE_IGNORE_WRITES_END() // empty |
| |
| #endif |
| |
| // ------------------------------------------------------------------------- |
| // Define the ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more |
| // primitive annotations defined above. |
| // |
| // Instead of doing |
| // ABSL_ANNOTATE_IGNORE_READS_BEGIN(); |
| // ... = x; |
| // ABSL_ANNOTATE_IGNORE_READS_END(); |
| // one can use |
| // ... = ABSL_ANNOTATE_UNPROTECTED_READ(x); |
| |
| #if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED) |
| |
| // Start ignoring all memory accesses (both reads and writes). |
| #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ |
| do { \ |
| ABSL_ANNOTATE_IGNORE_READS_BEGIN(); \ |
| ABSL_ANNOTATE_IGNORE_WRITES_BEGIN(); \ |
| } while (0) |
| |
| // Stop ignoring both reads and writes. |
| #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \ |
| do { \ |
| ABSL_ANNOTATE_IGNORE_WRITES_END(); \ |
| ABSL_ANNOTATE_IGNORE_READS_END(); \ |
| } while (0) |
| |
| #ifdef __cplusplus |
| // ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. |
| #define ABSL_ANNOTATE_UNPROTECTED_READ(x) \ |
| absl::base_internal::AnnotateUnprotectedRead(x) |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace base_internal { |
| |
| template <typename T> |
| inline T AnnotateUnprotectedRead(const volatile T& x) { // NOLINT |
| ABSL_ANNOTATE_IGNORE_READS_BEGIN(); |
| T res = x; |
| ABSL_ANNOTATE_IGNORE_READS_END(); |
| return res; |
| } |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| #endif |
| |
| #else |
| |
| #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty |
| #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty |
| #define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x) |
| |
| #endif |
| |
| // ------------------------------------------------------------------------- |
| // Address sanitizer annotations |
| |
| #ifdef ABSL_HAVE_ADDRESS_SANITIZER |
| // Describe the current state of a contiguous container such as e.g. |
| // std::vector or std::string. For more details see |
| // sanitizer/common_interface_defs.h, which is provided by the compiler. |
| #include <sanitizer/common_interface_defs.h> |
| |
| #define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \ |
| __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid) |
| #define ABSL_ADDRESS_SANITIZER_REDZONE(name) \ |
| struct { \ |
| alignas(8) char x[8]; \ |
| } name |
| |
| #else |
| |
| #define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) // empty |
| #define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "") |
| |
| #endif // ABSL_HAVE_ADDRESS_SANITIZER |
| |
| // ------------------------------------------------------------------------- |
| // HWAddress sanitizer annotations |
| |
| #ifdef __cplusplus |
| namespace absl { |
| #ifdef ABSL_HAVE_HWADDRESS_SANITIZER |
| // Under HWASAN changes the tag of the pointer. |
| template <typename T> |
| T* HwasanTagPointer(T* ptr, uintptr_t tag) { |
| return reinterpret_cast<T*>(__hwasan_tag_pointer(ptr, tag)); |
| } |
| #else |
| template <typename T> |
| T* HwasanTagPointer(T* ptr, uintptr_t) { |
| return ptr; |
| } |
| #endif |
| } // namespace absl |
| #endif |
| |
| // ------------------------------------------------------------------------- |
| // 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_ |
| *¶P |
| hsoong/.intermediates/external/abseil-cpp/absl_base_hdrs/gen/my_include_dir/absl/base/internal/spinlock.hÉO// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| // Most users requiring mutual exclusion should use Mutex. |
| // SpinLock is provided for use in two situations: |
| // - for use by Abseil internal code that Mutex itself depends on |
| // - for async signal safety (see below) |
| |
| // SpinLock with a base_internal::SchedulingMode::SCHEDULE_KERNEL_ONLY is async |
| // signal safe. If a spinlock is used within a signal handler, all code that |
| // acquires the lock must ensure that the signal cannot arrive while they are |
| // holding the lock. Typically, this is done by blocking the signal. |
| // |
| // Threads waiting on a SpinLock may be woken in an arbitrary order. |
| |
| #ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_ |
| #define ABSL_BASE_INTERNAL_SPINLOCK_H_ |
| |
| #include <atomic> |
| #include <cstdint> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/const_init.h" |
| #include "absl/base/dynamic_annotations.h" |
| #include "absl/base/internal/low_level_scheduling.h" |
| #include "absl/base/internal/raw_logging.h" |
| #include "absl/base/internal/scheduling_mode.h" |
| #include "absl/base/internal/tsan_mutex_interface.h" |
| #include "absl/base/thread_annotations.h" |
| |
| namespace tcmalloc { |
| namespace tcmalloc_internal { |
| |
| class AllocationGuardSpinLockHolder; |
| |
| } // namespace tcmalloc_internal |
| } // namespace tcmalloc |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace base_internal { |
| |
| class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED SpinLock { |
| public: |
| SpinLock() : lockword_(kSpinLockCooperative) { |
| ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); |
| } |
| |
| // Constructors that allow non-cooperative spinlocks to be created for use |
| // inside thread schedulers. Normal clients should not use these. |
| explicit SpinLock(base_internal::SchedulingMode mode); |
| |
| // Constructor for global SpinLock instances. See absl/base/const_init.h. |
| constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode) |
| : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {} |
| |
| // For global SpinLock instances prefer trivial destructor when possible. |
| // Default but non-trivial destructor in some build configurations causes an |
| // extra static initializer. |
| #ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE |
| ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); } |
| #else |
| ~SpinLock() = default; |
| #endif |
| |
| // Acquire this SpinLock. |
| inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { |
| ABSL_TSAN_MUTEX_PRE_LOCK(this, 0); |
| if (!TryLockImpl()) { |
| SlowLock(); |
| } |
| ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0); |
| } |
| |
| // Try to acquire this SpinLock without blocking and return true if the |
| // acquisition was successful. If the lock was not acquired, false is |
| // returned. If this SpinLock is free at the time of the call, TryLock |
| // will return true with high probability. |
| [[nodiscard]] inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) { |
| ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock); |
| bool res = TryLockImpl(); |
| ABSL_TSAN_MUTEX_POST_LOCK( |
| this, __tsan_mutex_try_lock | (res ? 0 : __tsan_mutex_try_lock_failed), |
| 0); |
| return res; |
| } |
| |
| // Release this SpinLock, which must be held by the calling thread. |
| inline void Unlock() ABSL_UNLOCK_FUNCTION() { |
| ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0); |
| uint32_t lock_value = lockword_.load(std::memory_order_relaxed); |
| lock_value = lockword_.exchange(lock_value & kSpinLockCooperative, |
| std::memory_order_release); |
| |
| if ((lock_value & kSpinLockDisabledScheduling) != 0) { |
| base_internal::SchedulingGuard::EnableRescheduling(true); |
| } |
| if ((lock_value & kWaitTimeMask) != 0) { |
| // Collect contentionz profile info, and speed the wakeup of any waiter. |
| // The wait_cycles value indicates how long this thread spent waiting |
| // for the lock. |
| SlowUnlock(lock_value); |
| } |
| ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0); |
| } |
| |
| // Determine if the lock is held. When the lock is held by the invoking |
| // thread, true will always be returned. Intended to be used as |
| // CHECK(lock.IsHeld()). |
| [[nodiscard]] inline bool IsHeld() const { |
| return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0; |
| } |
| |
| // Return immediately if this thread holds the SpinLock exclusively. |
| // Otherwise, report an error by crashing with a diagnostic. |
| inline void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() { |
| if (!IsHeld()) { |
| ABSL_RAW_LOG(FATAL, "thread should hold the lock on SpinLock"); |
| } |
| } |
| |
| protected: |
| // These should not be exported except for testing. |
| |
| // Store number of cycles between wait_start_time and wait_end_time in a |
| // lock value. |
| static uint32_t EncodeWaitCycles(int64_t wait_start_time, |
| int64_t wait_end_time); |
| |
| // Extract number of wait cycles in a lock value. |
| static int64_t DecodeWaitCycles(uint32_t lock_value); |
| |
| // Provide access to protected method above. Use for testing only. |
| friend struct SpinLockTest; |
| friend class tcmalloc::tcmalloc_internal::AllocationGuardSpinLockHolder; |
| |
| private: |
| // lockword_ is used to store the following: |
| // |
| // bit[0] encodes whether a lock is being held. |
| // bit[1] encodes whether a lock uses cooperative scheduling. |
| // bit[2] encodes whether the current lock holder disabled scheduling when |
| // acquiring the lock. Only set when kSpinLockHeld is also set. |
| // bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int. |
| // This is set by the lock holder to indicate how long it waited on |
| // the lock before eventually acquiring it. The number of cycles is |
| // encoded as a 29-bit unsigned int, or in the case that the current |
| // holder did not wait but another waiter is queued, the LSB |
| // (kSpinLockSleeper) is set. The implementation does not explicitly |
| // track the number of queued waiters beyond this. It must always be |
| // assumed that waiters may exist if the current holder was required to |
| // queue. |
| // |
| // Invariant: if the lock is not held, the value is either 0 or |
| // kSpinLockCooperative. |
| static constexpr uint32_t kSpinLockHeld = 1; |
| static constexpr uint32_t kSpinLockCooperative = 2; |
| static constexpr uint32_t kSpinLockDisabledScheduling = 4; |
| static constexpr uint32_t kSpinLockSleeper = 8; |
| // Includes kSpinLockSleeper. |
| static constexpr uint32_t kWaitTimeMask = |
| ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling); |
| |
| // Returns true if the provided scheduling mode is cooperative. |
| static constexpr bool IsCooperative( |
| base_internal::SchedulingMode scheduling_mode) { |
| return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL; |
| } |
| |
| bool IsCooperative() const { |
| return lockword_.load(std::memory_order_relaxed) & kSpinLockCooperative; |
| } |
| |
| uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles); |
| void SlowLock() ABSL_ATTRIBUTE_COLD; |
| void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD; |
| uint32_t SpinLoop(); |
| |
| inline bool TryLockImpl() { |
| uint32_t lock_value = lockword_.load(std::memory_order_relaxed); |
| return (TryLockInternal(lock_value, 0) & kSpinLockHeld) == 0; |
| } |
| |
| std::atomic<uint32_t> lockword_; |
| |
| SpinLock(const SpinLock&) = delete; |
| SpinLock& operator=(const SpinLock&) = delete; |
| }; |
| |
| // Corresponding locker object that arranges to acquire a spinlock for |
| // the duration of a C++ scope. |
| class ABSL_SCOPED_LOCKABLE [[nodiscard]] SpinLockHolder { |
| public: |
| inline explicit SpinLockHolder(SpinLock* l) ABSL_EXCLUSIVE_LOCK_FUNCTION(l) |
| : lock_(l) { |
| l->Lock(); |
| } |
| inline ~SpinLockHolder() ABSL_UNLOCK_FUNCTION() { lock_->Unlock(); } |
| |
| SpinLockHolder(const SpinLockHolder&) = delete; |
| SpinLockHolder& operator=(const SpinLockHolder&) = delete; |
| |
| private: |
| SpinLock* lock_; |
| }; |
| |
| // Register a hook for profiling support. |
| // |
| // The function pointer registered here will be called whenever a spinlock is |
| // contended. The callback is given an opaque handle to the contended spinlock |
| // and the number of wait cycles. This is thread-safe, but only a single |
| // profiler can be registered. It is an error to call this function multiple |
| // times with different arguments. |
| void RegisterSpinLockProfiler(void (*fn)(const void* lock, |
| int64_t wait_cycles)); |
| |
| //------------------------------------------------------------------------------ |
| // Public interface ends here. |
| //------------------------------------------------------------------------------ |
| |
| // If (result & kSpinLockHeld) == 0, then *this was successfully locked. |
| // Otherwise, returns last observed value for lockword_. |
| inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value, |
| uint32_t wait_cycles) { |
| if ((lock_value & kSpinLockHeld) != 0) { |
| return lock_value; |
| } |
| |
| uint32_t sched_disabled_bit = 0; |
| if ((lock_value & kSpinLockCooperative) == 0) { |
| // For non-cooperative locks we must make sure we mark ourselves as |
| // non-reschedulable before we attempt to CompareAndSwap. |
| if (base_internal::SchedulingGuard::DisableRescheduling()) { |
| sched_disabled_bit = kSpinLockDisabledScheduling; |
| } |
| } |
| |
| if (!lockword_.compare_exchange_strong( |
| lock_value, |
| kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit, |
| std::memory_order_acquire, std::memory_order_relaxed)) { |
| base_internal::SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0); |
| } |
| |
| return lock_value; |
| } |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_SPINLOCK_H_ |
| *»D |
| soong/.intermediates/external/abseil-cpp/absl_strings_cord_internal_hdrs/gen/my_include_dir/absl/strings/internal/cord_rep_btree_reader.h¬C// 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_STRINGS_INTERNAL_CORD_REP_BTREE_READER_H_ |
| #define ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_READER_H_ |
| |
| #include <cassert> |
| |
| #include "absl/base/config.h" |
| #include "absl/strings/internal/cord_data_edge.h" |
| #include "absl/strings/internal/cord_internal.h" |
| #include "absl/strings/internal/cord_rep_btree.h" |
| #include "absl/strings/internal/cord_rep_btree_navigator.h" |
| #include "absl/strings/internal/cord_rep_flat.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // CordRepBtreeReader implements logic to iterate over cord btrees. |
| // References to the underlying data are returned as absl::string_view values. |
| // The most typical use case is a forward only iteration over tree data. |
| // The class also provides `Skip()`, `Seek()` and `Read()` methods similar to |
| // CordRepBtreeNavigator that allow more advanced navigation. |
| // |
| // Example: iterate over all data inside a cord btree: |
| // |
| // CordRepBtreeReader reader; |
| // for (string_view sv = reader.Init(tree); !sv.Empty(); sv = sv.Next()) { |
| // DoSomethingWithDataIn(sv); |
| // } |
| // |
| // All navigation methods always return the next 'chunk' of data. The class |
| // assumes that all data is directly 'consumed' by the caller. For example: |
| // invoking `Skip()` will skip the desired number of bytes, and directly |
| // read and return the next chunk of data directly after the skipped bytes. |
| // |
| // Example: iterate over all data inside a btree skipping the first 100 bytes: |
| // |
| // CordRepBtreeReader reader; |
| // absl::string_view sv = reader.Init(tree); |
| // if (sv.length() > 100) { |
| // sv.RemovePrefix(100); |
| // } else { |
| // sv = reader.Skip(100 - sv.length()); |
| // } |
| // while (!sv.empty()) { |
| // DoSomethingWithDataIn(sv); |
| // absl::string_view sv = reader.Next(); |
| // } |
| // |
| // It is important to notice that `remaining` is based on the end position of |
| // the last data edge returned to the caller, not the cumulative data returned |
| // to the caller which can be less in cases of skipping or seeking over data. |
| // |
| // For example, consider a cord btree with five data edges: "abc", "def", "ghi", |
| // "jkl" and "mno": |
| // |
| // absl::string_view sv; |
| // CordRepBtreeReader reader; |
| // |
| // sv = reader.Init(tree); // sv = "abc", remaining = 12 |
| // sv = reader.Skip(4); // sv = "hi", remaining = 6 |
| // sv = reader.Skip(2); // sv = "l", remaining = 3 |
| // sv = reader.Next(); // sv = "mno", remaining = 0 |
| // sv = reader.Seek(1); // sv = "bc", remaining = 12 |
| // |
| class CordRepBtreeReader { |
| public: |
| using ReadResult = CordRepBtreeNavigator::ReadResult; |
| using Position = CordRepBtreeNavigator::Position; |
| |
| // Returns true if this instance is not empty. |
| explicit operator bool() const { return navigator_.btree() != nullptr; } |
| |
| // Returns the tree referenced by this instance or nullptr if empty. |
| CordRepBtree* btree() const { return navigator_.btree(); } |
| |
| // Returns the current data edge inside the referenced btree. |
| // Requires that the current instance is not empty. |
| CordRep* node() const { return navigator_.Current(); } |
| |
| // Returns the length of the referenced tree. |
| // Requires that the current instance is not empty. |
| size_t length() const; |
| |
| // Returns the number of remaining bytes available for iteration, which is the |
| // number of bytes directly following the end of the last chunk returned. |
| // This value will be zero if we iterated over the last edge in the bound |
| // tree, in which case any call to Next() or Skip() will return an empty |
| // string_view reflecting the EOF state. |
| // Note that a call to `Seek()` resets `remaining` to a value based on the |
| // end position of the chunk returned by that call. |
| size_t remaining() const { return remaining_; } |
| |
| // Resets this instance to an empty value. |
| void Reset() { navigator_.Reset(); } |
| |
| // Initializes this instance with `tree`. `tree` must not be null. |
| // Returns a reference to the first data edge of the provided tree. |
| absl::string_view Init(CordRepBtree* tree); |
| |
| // Navigates to and returns the next data edge of the referenced tree. |
| // Returns an empty string_view if an attempt is made to read beyond the end |
| // of the tree, i.e.: if `remaining()` is zero indicating an EOF condition. |
| // Requires that the current instance is not empty. |
| absl::string_view Next(); |
| |
| // Skips the provided amount of bytes and returns a reference to the data |
| // directly following the skipped bytes. |
| absl::string_view Skip(size_t skip); |
| |
| // Reads `n` bytes into `tree`. |
| // If `chunk_size` is zero, starts reading at the next data edge. If |
| // `chunk_size` is non zero, the read starts at the last `chunk_size` bytes of |
| // the last returned data edge. Effectively, this means that the read starts |
| // at offset `consumed() - chunk_size`. |
| // Requires that `chunk_size` is less than or equal to the length of the |
| // last returned data edge. The purpose of `chunk_size` is to simplify code |
| // partially consuming a returned chunk and wanting to include the remaining |
| // bytes in the Read call. For example, the below code will read 1000 bytes of |
| // data into a cord tree if the first chunk starts with "big:": |
| // |
| // CordRepBtreeReader reader; |
| // absl::string_view sv = reader.Init(tree); |
| // if (absl::StartsWith(sv, "big:")) { |
| // CordRepBtree tree; |
| // sv = reader.Read(1000, sv.size() - 4 /* "big:" */, &tree); |
| // } |
| // |
| // This method will return an empty string view if all remaining data was |
| // read. If `n` exceeded the amount of remaining data this function will |
| // return an empty string view and `tree` will be set to nullptr. |
| // In both cases, `consumed` will be set to `length`. |
| absl::string_view Read(size_t n, size_t chunk_size, CordRep*& tree); |
| |
| // Navigates to the chunk at offset `offset`. |
| // Returns a reference into the navigated to chunk, adjusted for the relative |
| // position of `offset` into that chunk. For example, calling `Seek(13)` on a |
| // cord tree containing 2 chunks of 10 and 20 bytes respectively will return |
| // a string view into the second chunk starting at offset 3 with a size of 17. |
| // Returns an empty string view if `offset` is equal to or greater than the |
| // length of the referenced tree. |
| absl::string_view Seek(size_t offset); |
| |
| private: |
| size_t remaining_ = 0; |
| CordRepBtreeNavigator navigator_; |
| }; |
| |
| inline size_t CordRepBtreeReader::length() const { |
| assert(btree() != nullptr); |
| return btree()->length; |
| } |
| |
| inline absl::string_view CordRepBtreeReader::Init(CordRepBtree* tree) { |
| assert(tree != nullptr); |
| const CordRep* edge = navigator_.InitFirst(tree); |
| remaining_ = tree->length - edge->length; |
| return EdgeData(edge); |
| } |
| |
| inline absl::string_view CordRepBtreeReader::Next() { |
| if (remaining_ == 0) return {}; |
| const CordRep* edge = navigator_.Next(); |
| assert(edge != nullptr); |
| remaining_ -= edge->length; |
| return EdgeData(edge); |
| } |
| |
| inline absl::string_view CordRepBtreeReader::Skip(size_t skip) { |
| // As we are always positioned on the last 'consumed' edge, we |
| // need to skip the current edge as well as `skip`. |
| const size_t edge_length = navigator_.Current()->length; |
| CordRepBtreeNavigator::Position pos = navigator_.Skip(skip + edge_length); |
| if (ABSL_PREDICT_FALSE(pos.edge == nullptr)) { |
| remaining_ = 0; |
| return {}; |
| } |
| // The combined length of all edges skipped before `pos.edge` is `skip - |
| // pos.offset`, all of which are 'consumed', as well as the current edge. |
| remaining_ -= skip - pos.offset + pos.edge->length; |
| return EdgeData(pos.edge).substr(pos.offset); |
| } |
| |
| inline absl::string_view CordRepBtreeReader::Seek(size_t offset) { |
| const CordRepBtreeNavigator::Position pos = navigator_.Seek(offset); |
| if (ABSL_PREDICT_FALSE(pos.edge == nullptr)) { |
| remaining_ = 0; |
| return {}; |
| } |
| absl::string_view chunk = EdgeData(pos.edge).substr(pos.offset); |
| remaining_ = length() - offset - chunk.length(); |
| return chunk; |
| } |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_READER_H_ |
| *Ó; |
| wsoong/.intermediates/external/abseil-cpp/absl_base_atomic_hook_hdrs/gen/my_include_dir/absl/base/internal/atomic_hook.h×:// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_ |
| #define ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_ |
| |
| #include <atomic> |
| #include <cassert> |
| #include <cstdint> |
| #include <utility> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| |
| #if defined(_MSC_VER) && !defined(__clang__) |
| #define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 0 |
| #else |
| #define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 1 |
| #endif |
| |
| #if defined(_MSC_VER) |
| #define ABSL_HAVE_WORKING_ATOMIC_POINTER 0 |
| #else |
| #define ABSL_HAVE_WORKING_ATOMIC_POINTER 1 |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace base_internal { |
| |
| template <typename T> |
| class AtomicHook; |
| |
| // To workaround AtomicHook not being constant-initializable on some platforms, |
| // prefer to annotate instances with `ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES` |
| // instead of `ABSL_CONST_INIT`. |
| #if ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT |
| #define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_CONST_INIT |
| #else |
| #define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES |
| #endif |
| |
| // `AtomicHook` is a helper class, templatized on a raw function pointer type, |
| // for implementing Abseil customization hooks. It is a callable object that |
| // dispatches to the registered hook. Objects of type `AtomicHook` must have |
| // static or thread storage duration. |
| // |
| // A default constructed object performs a no-op (and returns a default |
| // constructed object) if no hook has been registered. |
| // |
| // Hooks can be pre-registered via constant initialization, for example: |
| // |
| // ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static AtomicHook<void(*)()> |
| // my_hook(DefaultAction); |
| // |
| // and then changed at runtime via a call to `Store()`. |
| // |
| // Reads and writes guarantee memory_order_acquire/memory_order_release |
| // semantics. |
| template <typename ReturnType, typename... Args> |
| class AtomicHook<ReturnType (*)(Args...)> { |
| public: |
| using FnPtr = ReturnType (*)(Args...); |
| |
| // Constructs an object that by default performs a no-op (and |
| // returns a default constructed object) when no hook as been registered. |
| constexpr AtomicHook() : AtomicHook(DummyFunction) {} |
| |
| // Constructs an object that by default dispatches to/returns the |
| // pre-registered default_fn when no hook has been registered at runtime. |
| #if ABSL_HAVE_WORKING_ATOMIC_POINTER && ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT |
| explicit constexpr AtomicHook(FnPtr default_fn) |
| : hook_(default_fn), default_fn_(default_fn) {} |
| #elif ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT |
| explicit constexpr AtomicHook(FnPtr default_fn) |
| : hook_(kUninitialized), default_fn_(default_fn) {} |
| #else |
| // As of January 2020, on all known versions of MSVC this constructor runs in |
| // the global constructor sequence. If `Store()` is called by a dynamic |
| // initializer, we want to preserve the value, even if this constructor runs |
| // after the call to `Store()`. If not, `hook_` will be |
| // zero-initialized by the linker and we have no need to set it. |
| // https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html |
| explicit constexpr AtomicHook(FnPtr default_fn) |
| : /* hook_(deliberately omitted), */ default_fn_(default_fn) { |
| static_assert(kUninitialized == 0, "here we rely on zero-initialization"); |
| } |
| #endif |
| |
| // Stores the provided function pointer as the value for this hook. |
| // |
| // This is intended to be called once. Multiple calls are legal only if the |
| // same function pointer is provided for each call. The store is implemented |
| // as a memory_order_release operation, and read accesses are implemented as |
| // memory_order_acquire. |
| void Store(FnPtr fn) { |
| bool success = DoStore(fn); |
| static_cast<void>(success); |
| assert(success); |
| } |
| |
| // Invokes the registered callback. If no callback has yet been registered, a |
| // default-constructed object of the appropriate type is returned instead. |
| template <typename... CallArgs> |
| ReturnType operator()(CallArgs&&... args) const { |
| return DoLoad()(std::forward<CallArgs>(args)...); |
| } |
| |
| // Returns the registered callback, or nullptr if none has been registered. |
| // Useful if client code needs to conditionalize behavior based on whether a |
| // callback was registered. |
| // |
| // Note that atomic_hook.Load()() and atomic_hook() have different semantics: |
| // operator()() will perform a no-op if no callback was registered, while |
| // Load()() will dereference a null function pointer. Prefer operator()() to |
| // Load()() unless you must conditionalize behavior on whether a hook was |
| // registered. |
| FnPtr Load() const { |
| FnPtr ptr = DoLoad(); |
| return (ptr == DummyFunction) ? nullptr : ptr; |
| } |
| |
| private: |
| static ReturnType DummyFunction(Args...) { |
| return ReturnType(); |
| } |
| |
| // Current versions of MSVC (as of September 2017) have a broken |
| // implementation of std::atomic<T*>: Its constructor attempts to do the |
| // equivalent of a reinterpret_cast in a constexpr context, which is not |
| // allowed. |
| // |
| // This causes an issue when building with LLVM under Windows. To avoid this, |
| // we use a less-efficient, intptr_t-based implementation on Windows. |
| #if ABSL_HAVE_WORKING_ATOMIC_POINTER |
| // Return the stored value, or DummyFunction if no value has been stored. |
| FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); } |
| |
| // Store the given value. Returns false if a different value was already |
| // stored to this object. |
| bool DoStore(FnPtr fn) { |
| assert(fn); |
| FnPtr expected = default_fn_; |
| const bool store_succeeded = hook_.compare_exchange_strong( |
| expected, fn, std::memory_order_acq_rel, std::memory_order_acquire); |
| const bool same_value_already_stored = (expected == fn); |
| return store_succeeded || same_value_already_stored; |
| } |
| |
| std::atomic<FnPtr> hook_; |
| #else // !ABSL_HAVE_WORKING_ATOMIC_POINTER |
| // Use a sentinel value unlikely to be the address of an actual function. |
| static constexpr intptr_t kUninitialized = 0; |
| |
| static_assert(sizeof(intptr_t) >= sizeof(FnPtr), |
| "intptr_t can't contain a function pointer"); |
| |
| FnPtr DoLoad() const { |
| const intptr_t value = hook_.load(std::memory_order_acquire); |
| if (value == kUninitialized) { |
| return default_fn_; |
| } |
| return reinterpret_cast<FnPtr>(value); |
| } |
| |
| bool DoStore(FnPtr fn) { |
| assert(fn); |
| const auto value = reinterpret_cast<intptr_t>(fn); |
| intptr_t expected = kUninitialized; |
| const bool store_succeeded = hook_.compare_exchange_strong( |
| expected, value, std::memory_order_acq_rel, std::memory_order_acquire); |
| const bool same_value_already_stored = (expected == value); |
| return store_succeeded || same_value_already_stored; |
| } |
| |
| std::atomic<intptr_t> hook_; |
| #endif |
| |
| const FnPtr default_fn_; |
| }; |
| |
| #undef ABSL_HAVE_WORKING_ATOMIC_POINTER |
| #undef ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_ |
| *Q |
| soong/.intermediates/external/abseil-cpp/absl_base_raw_logging_internal_hdrs/gen/my_include_dir/absl/base/internal/raw_logging.hP// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // Thread-safe logging routines that do not allocate any memory or |
| // acquire any locks, and can therefore be used by low-level memory |
| // allocation, synchronization, and signal-handling code. |
| |
| #ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_ |
| #define ABSL_BASE_INTERNAL_RAW_LOGGING_H_ |
| |
| #include <string> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/atomic_hook.h" |
| #include "absl/base/log_severity.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/optimization.h" |
| #include "absl/base/port.h" |
| |
| // This is similar to LOG(severity) << format..., but |
| // * it is to be used ONLY by low-level modules that can't use normal LOG() |
| // * it is designed to be a low-level logger that does not allocate any |
| // memory and does not need any locks, hence: |
| // * it logs straight and ONLY to STDERR w/o buffering |
| // * it uses an explicit printf-format and arguments list |
| // * it will silently chop off really long message strings |
| // Usage example: |
| // ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error); |
| // This will print an almost standard log line like this to stderr only: |
| // E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file |
| |
| #define ABSL_RAW_LOG(severity, ...) \ |
| do { \ |
| constexpr const char* absl_raw_log_internal_basename = \ |
| ::absl::raw_log_internal::Basename(__FILE__, sizeof(__FILE__) - 1); \ |
| ::absl::raw_log_internal::RawLog(ABSL_RAW_LOG_INTERNAL_##severity, \ |
| absl_raw_log_internal_basename, __LINE__, \ |
| __VA_ARGS__); \ |
| ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_##severity; \ |
| } while (0) |
| |
| // Similar to CHECK(condition) << message, but for low-level modules: |
| // we use only ABSL_RAW_LOG that does not allocate memory. |
| // We do not want to provide args list here to encourage this usage: |
| // if (!cond) ABSL_RAW_LOG(FATAL, "foo ...", hard_to_compute_args); |
| // so that the args are not computed when not needed. |
| #define ABSL_RAW_CHECK(condition, message) \ |
| do { \ |
| if (ABSL_PREDICT_FALSE(!(condition))) { \ |
| ABSL_RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \ |
| } \ |
| } while (0) |
| |
| // ABSL_INTERNAL_LOG and ABSL_INTERNAL_CHECK work like the RAW variants above, |
| // except that if the richer log library is linked into the binary, we dispatch |
| // to that instead. This is potentially useful for internal logging and |
| // assertions, where we are using RAW_LOG neither for its async-signal-safety |
| // nor for its non-allocating nature, but rather because raw logging has very |
| // few other dependencies. |
| // |
| // The API is a subset of the above: each macro only takes two arguments. Use |
| // StrCat if you need to build a richer message. |
| #define ABSL_INTERNAL_LOG(severity, message) \ |
| do { \ |
| constexpr const char* absl_raw_log_internal_filename = __FILE__; \ |
| ::absl::raw_log_internal::internal_log_function( \ |
| ABSL_RAW_LOG_INTERNAL_##severity, absl_raw_log_internal_filename, \ |
| __LINE__, message); \ |
| ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_##severity; \ |
| } while (0) |
| |
| #define ABSL_INTERNAL_CHECK(condition, message) \ |
| do { \ |
| if (ABSL_PREDICT_FALSE(!(condition))) { \ |
| std::string death_message = "Check " #condition " failed: "; \ |
| death_message += std::string(message); \ |
| ABSL_INTERNAL_LOG(FATAL, death_message); \ |
| } \ |
| } while (0) |
| |
| #ifndef NDEBUG |
| |
| #define ABSL_RAW_DLOG(severity, ...) ABSL_RAW_LOG(severity, __VA_ARGS__) |
| #define ABSL_RAW_DCHECK(condition, message) ABSL_RAW_CHECK(condition, message) |
| |
| #else // NDEBUG |
| |
| #define ABSL_RAW_DLOG(severity, ...) \ |
| while (false) ABSL_RAW_LOG(severity, __VA_ARGS__) |
| #define ABSL_RAW_DCHECK(condition, message) \ |
| while (false) ABSL_RAW_CHECK(condition, message) |
| |
| #endif // NDEBUG |
| |
| #define ABSL_RAW_LOG_INTERNAL_INFO ::absl::LogSeverity::kInfo |
| #define ABSL_RAW_LOG_INTERNAL_WARNING ::absl::LogSeverity::kWarning |
| #define ABSL_RAW_LOG_INTERNAL_ERROR ::absl::LogSeverity::kError |
| #define ABSL_RAW_LOG_INTERNAL_FATAL ::absl::LogSeverity::kFatal |
| #define ABSL_RAW_LOG_INTERNAL_DFATAL ::absl::kLogDebugFatal |
| #define ABSL_RAW_LOG_INTERNAL_LEVEL(severity) \ |
| ::absl::NormalizeLogSeverity(severity) |
| |
| #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_INFO |
| #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_WARNING |
| #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_ERROR |
| #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_FATAL ABSL_UNREACHABLE() |
| #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_DFATAL |
| #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_LEVEL(severity) |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace raw_log_internal { |
| |
| // Helper function to implement ABSL_RAW_LOG |
| // Logs format... at "severity" level, reporting it |
| // as called from file:line. |
| // This does not allocate memory or acquire locks. |
| void RawLog(absl::LogSeverity severity, const char* file, int line, |
| const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5); |
| |
| // Writes the provided buffer directly to stderr, in a signal-safe, low-level |
| // manner. Preserves errno. |
| void AsyncSignalSafeWriteError(const char* s, size_t len); |
| |
| // compile-time function to get the "base" filename, that is, the part of |
| // a filename after the last "/" or "\" path separator. The search starts at |
| // the end of the string; the second parameter is the length of the string. |
| constexpr const char* Basename(const char* fname, int offset) { |
| return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\' |
| ? fname + offset |
| : Basename(fname, offset - 1); |
| } |
| |
| // For testing only. |
| // Returns true if raw logging is fully supported. When it is not |
| // fully supported, no messages will be emitted, but a log at FATAL |
| // severity will cause an abort. |
| // |
| // TODO(gfalcon): Come up with a better name for this method. |
| bool RawLoggingFullySupported(); |
| |
| // Function type for a raw_log customization hook for suppressing messages |
| // by severity, and for writing custom prefixes on non-suppressed messages. |
| // |
| // The installed hook is called for every raw log invocation. The message will |
| // be logged to stderr only if the hook returns true. FATAL errors will cause |
| // the process to abort, even if writing to stderr is suppressed. The hook is |
| // also provided with an output buffer, where it can write a custom log message |
| // prefix. |
| // |
| // The raw_log system does not allocate memory or grab locks. User-provided |
| // hooks must avoid these operations, and must not throw exceptions. |
| // |
| // 'severity' is the severity level of the message being written. |
| // 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro |
| // was located. |
| // 'buf' and 'buf_size' are pointers to the buffer and buffer size. If the |
| // hook writes a prefix, it must increment *buf and decrement *buf_size |
| // accordingly. |
| using LogFilterAndPrefixHook = bool (*)(absl::LogSeverity severity, |
| const char* file, int line, char** buf, |
| int* buf_size); |
| |
| // Function type for a raw_log customization hook called to abort a process |
| // when a FATAL message is logged. If the provided AbortHook() returns, the |
| // logging system will call abort(). |
| // |
| // 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro |
| // was located. |
| // The NUL-terminated logged message lives in the buffer between 'buf_start' |
| // and 'buf_end'. 'prefix_end' points to the first non-prefix character of the |
| // buffer (as written by the LogFilterAndPrefixHook.) |
| // |
| // The lifetime of the filename and message buffers will not end while the |
| // process remains alive. |
| using AbortHook = void (*)(const char* file, int line, const char* buf_start, |
| const char* prefix_end, const char* buf_end); |
| |
| // Internal logging function for ABSL_INTERNAL_LOG to dispatch to. |
| // |
| // TODO(gfalcon): When string_view no longer depends on base, change this |
| // interface to take its message as a string_view instead. |
| using InternalLogFunction = void (*)(absl::LogSeverity severity, |
| const char* file, int line, |
| const std::string& message); |
| |
| ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook< |
| InternalLogFunction> |
| internal_log_function; |
| |
| // Registers hooks of the above types. Only a single hook of each type may be |
| // registered. It is an error to call these functions multiple times with |
| // different input arguments. |
| // |
| // These functions are safe to call at any point during initialization; they do |
| // not block or malloc, and are async-signal safe. |
| void RegisterLogFilterAndPrefixHook(LogFilterAndPrefixHook func); |
| void RegisterAbortHook(AbortHook func); |
| void RegisterInternalLogFunction(InternalLogFunction func); |
| |
| } // namespace raw_log_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_ |
| *ê |
| soong/.intermediates/external/abseil-cpp/absl_strings_cord_internal_hdrs/gen/my_include_dir/absl/strings/internal/cord_data_edge.hâ// Copyright 2022 The Abseil Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_CORD_DATA_EDGE_H_ |
| #define ABSL_STRINGS_INTERNAL_CORD_DATA_EDGE_H_ |
| |
| #include <cassert> |
| #include <cstddef> |
| |
| #include "absl/base/config.h" |
| #include "absl/strings/internal/cord_internal.h" |
| #include "absl/strings/internal/cord_rep_flat.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // Returns true if the provided rep is a FLAT, EXTERNAL or a SUBSTRING node |
| // holding a FLAT or EXTERNAL child rep. Requires `rep != nullptr`. |
| inline bool IsDataEdge(const CordRep* edge) { |
| assert(edge != nullptr); |
| |
| // The fast path is that `edge` is an EXTERNAL or FLAT node, making the below |
| // if a single, well predicted branch. We then repeat the FLAT or EXTERNAL |
| // check in the slow path of the SUBSTRING check to optimize for the hot path. |
| if (edge->tag == EXTERNAL || edge->tag >= FLAT) return true; |
| if (edge->tag == SUBSTRING) edge = edge->substring()->child; |
| return edge->tag == EXTERNAL || edge->tag >= FLAT; |
| } |
| |
| // Returns the `absl::string_view` data reference for the provided data edge. |
| // Requires 'IsDataEdge(edge) == true`. |
| inline absl::string_view EdgeData(const CordRep* edge) { |
| assert(IsDataEdge(edge)); |
| |
| size_t offset = 0; |
| const size_t length = edge->length; |
| if (edge->IsSubstring()) { |
| offset = edge->substring()->start; |
| edge = edge->substring()->child; |
| } |
| return edge->tag >= FLAT |
| ? absl::string_view{edge->flat()->Data() + offset, length} |
| : absl::string_view{edge->external()->base + offset, length}; |
| } |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORD_DATA_EDGE_H_ |
| *? |
| soong/.intermediates/external/abseil-cpp/absl_strings_cord_internal_hdrs/gen/my_include_dir/absl/strings/internal/cord_rep_flat.h>// Copyright 2020 The Abseil Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_ |
| #define ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_ |
| |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <memory> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/macros.h" |
| #include "absl/strings/internal/cord_internal.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // Note: all constants below are never ODR used and internal to cord, we define |
| // these as static constexpr to avoid 'in struct' definition and usage clutter. |
| |
| // Largest and smallest flat node lengths we are willing to allocate |
| // Flat allocation size is stored in tag, which currently can encode sizes up |
| // to 4K, encoded as multiple of either 8 or 32 bytes. |
| // If we allow for larger sizes, we need to change this to 8/64, 16/128, etc. |
| // kMinFlatSize is bounded by tag needing to be at least FLAT * 8 bytes, and |
| // ideally a 'nice' size aligning with allocation and cacheline sizes like 32. |
| // kMaxFlatSize is bounded by the size resulting in a computed tag no greater |
| // than MAX_FLAT_TAG. MAX_FLAT_TAG provides for additional 'high' tag values. |
| static constexpr size_t kFlatOverhead = offsetof(CordRep, storage); |
| static constexpr size_t kMinFlatSize = 32; |
| static constexpr size_t kMaxFlatSize = 4096; |
| static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead; |
| static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead; |
| static constexpr size_t kMaxLargeFlatSize = 256 * 1024; |
| static constexpr size_t kMaxLargeFlatLength = kMaxLargeFlatSize - kFlatOverhead; |
| |
| // kTagBase should make the Size <--> Tag computation resilient |
| // against changes to the value of FLAT when we add a new tag.. |
| static constexpr uint8_t kTagBase = FLAT - 4; |
| |
| // Converts the provided rounded size to the corresponding tag |
| constexpr uint8_t AllocatedSizeToTagUnchecked(size_t size) { |
| return static_cast<uint8_t>(size <= 512 ? kTagBase + size / 8 |
| : size <= 8192 |
| ? kTagBase + 512 / 8 + size / 64 - 512 / 64 |
| : kTagBase + 512 / 8 + ((8192 - 512) / 64) + |
| size / 4096 - 8192 / 4096); |
| } |
| |
| // Converts the provided tag to the corresponding allocated size |
| constexpr size_t TagToAllocatedSize(uint8_t tag) { |
| return (tag <= kTagBase + 512 / 8) ? tag * 8 - kTagBase * 8 |
| : (tag <= kTagBase + (512 / 8) + ((8192 - 512) / 64)) |
| ? 512 + tag * 64 - kTagBase * 64 - 512 / 8 * 64 |
| : 8192 + tag * 4096 - kTagBase * 4096 - |
| ((512 / 8) + ((8192 - 512) / 64)) * 4096; |
| } |
| |
| static_assert(AllocatedSizeToTagUnchecked(kMinFlatSize) == FLAT, ""); |
| static_assert(AllocatedSizeToTagUnchecked(kMaxLargeFlatSize) == MAX_FLAT_TAG, |
| ""); |
| |
| // RoundUp logically performs `((n + m - 1) / m) * m` to round up to the nearest |
| // multiple of `m`, optimized for the invariant that `m` is a power of 2. |
| // Android local modification: disable unsigned integer overflow sanitizer here |
| // to support enabling it in the clients. |
| ABSL_ATTRIBUTE_NO_SANITIZE_UNSIGNED_OVERFLOW |
| constexpr size_t RoundUp(size_t n, size_t m) { |
| return (n + m - 1) & (0 - m); |
| } |
| |
| // Returns the size to the nearest equal or larger value that can be |
| // expressed exactly as a tag value. |
| inline size_t RoundUpForTag(size_t size) { |
| return RoundUp(size, (size <= 512) ? 8 : (size <= 8192 ? 64 : 4096)); |
| } |
| |
| // Converts the allocated size to a tag, rounding down if the size |
| // does not exactly match a 'tag expressible' size value. The result is |
| // undefined if the size exceeds the maximum size that can be encoded in |
| // a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>). |
| inline uint8_t AllocatedSizeToTag(size_t size) { |
| const uint8_t tag = AllocatedSizeToTagUnchecked(size); |
| assert(tag <= MAX_FLAT_TAG); |
| return tag; |
| } |
| |
| // Converts the provided tag to the corresponding available data length |
| constexpr size_t TagToLength(uint8_t tag) { |
| return TagToAllocatedSize(tag) - kFlatOverhead; |
| } |
| |
| // Enforce that kMaxFlatSize maps to a well-known exact tag value. |
| static_assert(TagToAllocatedSize(MAX_FLAT_TAG) == kMaxLargeFlatSize, |
| "Bad tag logic"); |
| |
| struct CordRepFlat : public CordRep { |
| // Tag for explicit 'large flat' allocation |
| struct Large {}; |
| |
| // Creates a new flat node. |
| template <size_t max_flat_size, typename... Args> |
| static CordRepFlat* NewImpl(size_t len, Args... args ABSL_ATTRIBUTE_UNUSED) { |
| if (len <= kMinFlatLength) { |
| len = kMinFlatLength; |
| } else if (len > max_flat_size - kFlatOverhead) { |
| len = max_flat_size - kFlatOverhead; |
| } |
| |
| // Round size up so it matches a size we can exactly express in a tag. |
| const size_t size = RoundUpForTag(len + kFlatOverhead); |
| void* const raw_rep = ::operator new(size); |
| // GCC 13 has a false-positive -Wstringop-overflow warning here. |
| #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(13, 0) |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic ignored "-Wstringop-overflow" |
| #endif |
| CordRepFlat* rep = new (raw_rep) CordRepFlat(); |
| rep->tag = AllocatedSizeToTag(size); |
| #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(13, 0) |
| #pragma GCC diagnostic pop |
| #endif |
| return rep; |
| } |
| |
| static CordRepFlat* New(size_t len) { return NewImpl<kMaxFlatSize>(len); } |
| |
| static CordRepFlat* New(Large, size_t len) { |
| return NewImpl<kMaxLargeFlatSize>(len); |
| } |
| |
| // Deletes a CordRepFlat instance created previously through a call to New(). |
| // Flat CordReps are allocated and constructed with raw ::operator new and |
| // placement new, and must be destructed and deallocated accordingly. |
| static void Delete(CordRep*rep) { |
| assert(rep->tag >= FLAT && rep->tag <= MAX_FLAT_TAG); |
| |
| #if defined(__cpp_sized_deallocation) |
| size_t size = TagToAllocatedSize(rep->tag); |
| rep->~CordRep(); |
| ::operator delete(rep, size); |
| #else |
| rep->~CordRep(); |
| ::operator delete(rep); |
| #endif |
| } |
| |
| // Create a CordRepFlat containing `data`, with an optional additional |
| // extra capacity of up to `extra` bytes. Requires that `data.size()` |
| // is less than kMaxFlatLength. |
| static CordRepFlat* Create(absl::string_view data, size_t extra = 0) { |
| assert(data.size() <= kMaxFlatLength); |
| CordRepFlat* flat = New(data.size() + (std::min)(extra, kMaxFlatLength)); |
| memcpy(flat->Data(), data.data(), data.size()); |
| flat->length = data.size(); |
| return flat; |
| } |
| |
| // Returns a pointer to the data inside this flat rep. |
| char* Data() { return reinterpret_cast<char*>(storage); } |
| const char* Data() const { return reinterpret_cast<const char*>(storage); } |
| |
| // Returns the maximum capacity (payload size) of this instance. |
| size_t Capacity() const { return TagToLength(tag); } |
| |
| // Returns the allocated size (payload + overhead) of this instance. |
| size_t AllocatedSize() const { return TagToAllocatedSize(tag); } |
| }; |
| |
| // Now that CordRepFlat is defined, we can define CordRep's helper casts: |
| inline CordRepFlat* CordRep::flat() { |
| assert(tag >= FLAT && tag <= MAX_FLAT_TAG); |
| return reinterpret_cast<CordRepFlat*>(this); |
| } |
| |
| inline const CordRepFlat* CordRep::flat() const { |
| assert(tag >= FLAT && tag <= MAX_FLAT_TAG); |
| return reinterpret_cast<const CordRepFlat*>(this); |
| } |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_ |
| *õ² |
| msoong/.intermediates/external/abseil-cpp/absl_strings_cord_hdrs/gen/my_include_dir/absl/strings/cord_buffer.h²// 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: cord_buffer.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This file defines an `absl::CordBuffer` data structure to hold data for |
| // eventual inclusion within an existing `Cord` data structure. Cord buffers are |
| // useful for building large Cords that may require custom allocation of its |
| // associated memory. |
| // |
| #ifndef ABSL_STRINGS_CORD_BUFFER_H_ |
| #define ABSL_STRINGS_CORD_BUFFER_H_ |
| |
| #include <algorithm> |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <memory> |
| #include <utility> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/macros.h" |
| #include "absl/numeric/bits.h" |
| #include "absl/strings/internal/cord_internal.h" |
| #include "absl/strings/internal/cord_rep_flat.h" |
| #include "absl/types/span.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| class Cord; |
| class CordBufferTestPeer; |
| |
| // CordBuffer |
| // |
| // CordBuffer manages memory buffers for purposes such as zero-copy APIs as well |
| // as applications building cords with large data requiring granular control |
| // over the allocation and size of cord data. For example, a function creating |
| // a cord of random data could use a CordBuffer as follows: |
| // |
| // absl::Cord CreateRandomCord(size_t length) { |
| // absl::Cord cord; |
| // while (length > 0) { |
| // CordBuffer buffer = CordBuffer::CreateWithDefaultLimit(length); |
| // absl::Span<char> data = buffer.available_up_to(length); |
| // FillRandomValues(data.data(), data.size()); |
| // buffer.IncreaseLengthBy(data.size()); |
| // cord.Append(std::move(buffer)); |
| // length -= data.size(); |
| // } |
| // return cord; |
| // } |
| // |
| // CordBuffer instances are by default limited to a capacity of `kDefaultLimit` |
| // bytes. `kDefaultLimit` is currently just under 4KiB, but this default may |
| // change in the future and/or for specific architectures. The default limit is |
| // aimed to provide a good trade-off between performance and memory overhead. |
| // Smaller buffers typically incur more compute cost while larger buffers are |
| // more CPU efficient but create significant memory overhead because of such |
| // allocations being less granular. Using larger buffers may also increase the |
| // risk of memory fragmentation. |
| // |
| // Applications create a buffer using one of the `CreateWithDefaultLimit()` or |
| // `CreateWithCustomLimit()` methods. The returned instance will have a non-zero |
| // capacity and a zero length. Applications use the `data()` method to set the |
| // contents of the managed memory, and once done filling the buffer, use the |
| // `IncreaseLengthBy()` or 'SetLength()' method to specify the length of the |
| // initialized data before adding the buffer to a Cord. |
| // |
| // The `CreateWithCustomLimit()` method is intended for applications needing |
| // larger buffers than the default memory limit, allowing the allocation of up |
| // to a capacity of `kCustomLimit` bytes minus some minimum internal overhead. |
| // The usage of `CreateWithCustomLimit()` should be limited to only those use |
| // cases where the distribution of the input is relatively well known, and/or |
| // where the trade-off between the efficiency gains outweigh the risk of memory |
| // fragmentation. See the documentation for `CreateWithCustomLimit()` for more |
| // information on using larger custom limits. |
| // |
| // The capacity of a `CordBuffer` returned by one of the `Create` methods may |
| // be larger than the requested capacity due to rounding, alignment and |
| // granularity of the memory allocator. Applications should use the `capacity` |
| // method to obtain the effective capacity of the returned instance as |
| // demonstrated in the provided example above. |
| // |
| // CordBuffer is a move-only class. All references into the managed memory are |
| // invalidated when an instance is moved into either another CordBuffer instance |
| // or a Cord. Writing to a location obtained by a previous call to `data()` |
| // after an instance was moved will lead to undefined behavior. |
| // |
| // A `moved from` CordBuffer instance will have a valid, but empty state. |
| // CordBuffer is thread compatible. |
| class CordBuffer { |
| public: |
| // kDefaultLimit |
| // |
| // Default capacity limits of allocated CordBuffers. |
| // See the class comments for more information on allocation limits. |
| static constexpr size_t kDefaultLimit = cord_internal::kMaxFlatLength; |
| |
| // kCustomLimit |
| // |
| // Maximum size for CreateWithCustomLimit() allocated buffers. |
| // Note that the effective capacity may be slightly less |
| // because of internal overhead of internal cord buffers. |
| static constexpr size_t kCustomLimit = 64U << 10; |
| |
| // Constructors, Destructors and Assignment Operators |
| |
| // Creates an empty CordBuffer. |
| CordBuffer() = default; |
| |
| // Destroys this CordBuffer instance and, if not empty, releases any memory |
| // managed by this instance, invalidating previously returned references. |
| ~CordBuffer(); |
| |
| // CordBuffer is move-only |
| CordBuffer(CordBuffer&& rhs) noexcept; |
| CordBuffer& operator=(CordBuffer&&) noexcept; |
| CordBuffer(const CordBuffer&) = delete; |
| CordBuffer& operator=(const CordBuffer&) = delete; |
| |
| // CordBuffer::MaximumPayload() |
| // |
| // Returns the guaranteed maximum payload for a CordBuffer returned by the |
| // `CreateWithDefaultLimit()` method. While small, each internal buffer inside |
| // a Cord incurs an overhead to manage the length, type and reference count |
| // for the buffer managed inside the cord tree. Applications can use this |
| // method to get approximate number of buffers required for a given byte |
| // size, etc. |
| // |
| // For example: |
| // const size_t payload = absl::CordBuffer::MaximumPayload(); |
| // const size_t buffer_count = (total_size + payload - 1) / payload; |
| // buffers.reserve(buffer_count); |
| static constexpr size_t MaximumPayload(); |
| |
| // Overload to the above `MaximumPayload()` except that it returns the |
| // maximum payload for a CordBuffer returned by the `CreateWithCustomLimit()` |
| // method given the provided `block_size`. |
| static constexpr size_t MaximumPayload(size_t block_size); |
| |
| // CordBuffer::CreateWithDefaultLimit() |
| // |
| // Creates a CordBuffer instance of the desired `capacity`, capped at the |
| // default limit `kDefaultLimit`. The returned buffer has a guaranteed |
| // capacity of at least `min(kDefaultLimit, capacity)`. See the class comments |
| // for more information on buffer capacities and intended usage. |
| static CordBuffer CreateWithDefaultLimit(size_t capacity); |
| |
| // CordBuffer::CreateWithCustomLimit() |
| // |
| // Creates a CordBuffer instance of the desired `capacity` rounded to an |
| // appropriate power of 2 size less than, or equal to `block_size`. |
| // Requires `block_size` to be a power of 2. |
| // |
| // If `capacity` is less than or equal to `kDefaultLimit`, then this method |
| // behaves identical to `CreateWithDefaultLimit`, which means that the caller |
| // is guaranteed to get a buffer of at least the requested capacity. |
| // |
| // If `capacity` is greater than or equal to `block_size`, then this method |
| // returns a buffer with an `allocated size` of `block_size` bytes. Otherwise, |
| // this methods returns a buffer with a suitable smaller power of 2 block size |
| // to satisfy the request. The actual size depends on a number of factors, and |
| // is typically (but not necessarily) the highest or second highest power of 2 |
| // value less than or equal to `capacity`. |
| // |
| // The 'allocated size' includes a small amount of overhead required for |
| // internal state, which is currently 13 bytes on 64-bit platforms. For |
| // example: a buffer created with `block_size` and `capacity' set to 8KiB |
| // will have an allocated size of 8KiB, and an effective internal `capacity` |
| // of 8KiB - 13 = 8179 bytes. |
| // |
| // To demonstrate this in practice, let's assume we want to read data from |
| // somewhat larger files using approximately 64KiB buffers: |
| // |
| // absl::Cord ReadFromFile(int fd, size_t n) { |
| // absl::Cord cord; |
| // while (n > 0) { |
| // CordBuffer buffer = CordBuffer::CreateWithCustomLimit(64 << 10, n); |
| // absl::Span<char> data = buffer.available_up_to(n); |
| // ReadFileDataOrDie(fd, data.data(), data.size()); |
| // buffer.IncreaseLengthBy(data.size()); |
| // cord.Append(std::move(buffer)); |
| // n -= data.size(); |
| // } |
| // return cord; |
| // } |
| // |
| // If we'd use this function to read a file of 659KiB, we may get the |
| // following pattern of allocated cord buffer sizes: |
| // |
| // CreateWithCustomLimit(64KiB, 674816) --> ~64KiB (65523) |
| // CreateWithCustomLimit(64KiB, 674816) --> ~64KiB (65523) |
| // ... |
| // CreateWithCustomLimit(64KiB, 19586) --> ~16KiB (16371) |
| // CreateWithCustomLimit(64KiB, 3215) --> 3215 (at least 3215) |
| // |
| // The reason the method returns a 16K buffer instead of a roughly 19K buffer |
| // is to reduce memory overhead and fragmentation risks. Using carefully |
| // chosen power of 2 values reduces the entropy of allocated memory sizes. |
| // |
| // Additionally, let's assume we'd use the above function on files that are |
| // generally smaller than 64K. If we'd use 'precise' sized buffers for such |
| // files, than we'd get a very wide distribution of allocated memory sizes |
| // rounded to 4K page sizes, and we'd end up with a lot of unused capacity. |
| // |
| // In general, application should only use custom sizes if the data they are |
| // consuming or storing is expected to be many times the chosen block size, |
| // and be based on objective data and performance metrics. For example, a |
| // compress function may work faster and consume less CPU when using larger |
| // buffers. Such an application should pick a size offering a reasonable |
| // trade-off between expected data size, compute savings with larger buffers, |
| // and the cost or fragmentation effect of larger buffers. |
| // Applications must pick a reasonable spot on that curve, and make sure their |
| // data meets their expectations in size distributions such as "mostly large". |
| static CordBuffer CreateWithCustomLimit(size_t block_size, size_t capacity); |
| |
| // CordBuffer::available() |
| // |
| // Returns the span delineating the available capacity in this buffer |
| // which is defined as `{ data() + length(), capacity() - length() }`. |
| absl::Span<char> available(); |
| |
| // CordBuffer::available_up_to() |
| // |
| // Returns the span delineating the available capacity in this buffer limited |
| // to `size` bytes. This is equivalent to `available().subspan(0, size)`. |
| absl::Span<char> available_up_to(size_t size); |
| |
| // CordBuffer::data() |
| // |
| // Returns a non-null reference to the data managed by this instance. |
| // Applications are allowed to write up to `capacity` bytes of instance data. |
| // CordBuffer data is uninitialized by default. Reading data from an instance |
| // that has not yet been initialized will lead to undefined behavior. |
| char* data(); |
| const char* data() const; |
| |
| // CordBuffer::length() |
| // |
| // Returns the length of this instance. The default length of a CordBuffer is |
| // 0, indicating an 'empty' CordBuffer. Applications must specify the length |
| // of the data in a CordBuffer before adding it to a Cord. |
| size_t length() const; |
| |
| // CordBuffer::capacity() |
| // |
| // Returns the capacity of this instance. All instances have a non-zero |
| // capacity: default and `moved from` instances have a small internal buffer. |
| size_t capacity() const; |
| |
| // CordBuffer::IncreaseLengthBy() |
| // |
| // Increases the length of this buffer by the specified 'n' bytes. |
| // Applications must make sure all data in this buffer up to the new length |
| // has been initialized before adding a CordBuffer to a Cord: failure to do so |
| // will lead to undefined behavior. Requires `length() + n <= capacity()`. |
| // Typically, applications will use 'available_up_to()` to get a span of the |
| // desired capacity, and use `span.size()` to increase the length as in: |
| // absl::Span<char> span = buffer.available_up_to(desired); |
| // buffer.IncreaseLengthBy(span.size()); |
| // memcpy(span.data(), src, span.size()); |
| // etc... |
| void IncreaseLengthBy(size_t n); |
| |
| // CordBuffer::SetLength() |
| // |
| // Sets the data length of this instance. Applications must make sure all data |
| // of the specified length has been initialized before adding a CordBuffer to |
| // a Cord: failure to do so will lead to undefined behavior. |
| // Setting the length to a small value or zero does not release any memory |
| // held by this CordBuffer instance. Requires `length <= capacity()`. |
| // Applications should preferably use the `IncreaseLengthBy()` method above |
| // in combination with the 'available()` or `available_up_to()` methods. |
| void SetLength(size_t length); |
| |
| private: |
| // Make sure we don't accidentally over promise. |
| static_assert(kCustomLimit <= cord_internal::kMaxLargeFlatSize, ""); |
| |
| // Assume the cost of an 'uprounded' allocation to CeilPow2(size) versus |
| // the cost of allocating at least 1 extra flat <= 4KB: |
| // - Flat overhead = 13 bytes |
| // - Btree amortized cost / node =~ 13 bytes |
| // - 64 byte granularity of tcmalloc at 4K =~ 32 byte average |
| // CPU cost and efficiency requires we should at least 'save' something by |
| // splitting, as a poor man's measure, we say the slop needs to be |
| // at least double the cost offset to make it worth splitting: ~128 bytes. |
| static constexpr size_t kMaxPageSlop = 128; |
| |
| // Overhead for allocation a flat. |
| static constexpr size_t kOverhead = cord_internal::kFlatOverhead; |
| |
| using CordRepFlat = cord_internal::CordRepFlat; |
| |
| // `Rep` is the internal data representation of a CordBuffer. The internal |
| // representation has an internal small size optimization similar to |
| // std::string (SSO). |
| struct Rep { |
| // Inline SSO size of a CordBuffer |
| static constexpr size_t kInlineCapacity = sizeof(intptr_t) * 2 - 1; |
| |
| // Creates a default instance with kInlineCapacity. |
| Rep() : short_rep{} {} |
| |
| // Creates an instance managing an allocated non zero CordRep. |
| explicit Rep(cord_internal::CordRepFlat* rep) : long_rep{rep} { |
| assert(rep != nullptr); |
| } |
| |
| // Returns true if this instance manages the SSO internal buffer. |
| bool is_short() const { |
| constexpr size_t offset = offsetof(Short, raw_size); |
| return (reinterpret_cast<const char*>(this)[offset] & 1) != 0; |
| } |
| |
| // Returns the available area of the internal SSO data |
| absl::Span<char> short_available() { |
| const size_t length = short_length(); |
| return absl::Span<char>(short_rep.data + length, |
| kInlineCapacity - length); |
| } |
| |
| // Returns the available area of the internal SSO data |
| absl::Span<char> long_available() const { |
| assert(!is_short()); |
| const size_t length = long_rep.rep->length; |
| return absl::Span<char>(long_rep.rep->Data() + length, |
| long_rep.rep->Capacity() - length); |
| } |
| |
| // Returns the length of the internal SSO data. |
| size_t short_length() const { |
| assert(is_short()); |
| return static_cast<size_t>(short_rep.raw_size >> 1); |
| } |
| |
| // Sets the length of the internal SSO data. |
| // Disregards any previously set CordRep instance. |
| void set_short_length(size_t length) { |
| short_rep.raw_size = static_cast<char>((length << 1) + 1); |
| } |
| |
| // Adds `n` to the current short length. |
| void add_short_length(size_t n) { |
| assert(is_short()); |
| short_rep.raw_size += static_cast<char>(n << 1); |
| } |
| |
| // Returns reference to the internal SSO data buffer. |
| char* data() { |
| assert(is_short()); |
| return short_rep.data; |
| } |
| const char* data() const { |
| assert(is_short()); |
| return short_rep.data; |
| } |
| |
| // Returns a pointer the external CordRep managed by this instance. |
| cord_internal::CordRepFlat* rep() const { |
| assert(!is_short()); |
| return long_rep.rep; |
| } |
| |
| // The internal representation takes advantage of the fact that allocated |
| // memory is always on an even address, and uses the least significant bit |
| // of the first or last byte (depending on endianness) as the inline size |
| // indicator overlapping with the least significant byte of the CordRep*. |
| #if defined(ABSL_IS_BIG_ENDIAN) |
| struct Long { |
| explicit Long(cord_internal::CordRepFlat* rep_arg) : rep(rep_arg) {} |
| void* padding; |
| cord_internal::CordRepFlat* rep; |
| }; |
| struct Short { |
| char data[sizeof(Long) - 1]; |
| char raw_size = 1; |
| }; |
| #else |
| struct Long { |
| explicit Long(cord_internal::CordRepFlat* rep_arg) : rep(rep_arg) {} |
| cord_internal::CordRepFlat* rep; |
| void* padding; |
| }; |
| struct Short { |
| char raw_size = 1; |
| char data[sizeof(Long) - 1]; |
| }; |
| #endif |
| |
| union { |
| Long long_rep; |
| Short short_rep; |
| }; |
| }; |
| |
| // Power2 functions |
| static bool IsPow2(size_t size) { return absl::has_single_bit(size); } |
| static size_t Log2Floor(size_t size) { |
| return static_cast<size_t>(absl::bit_width(size) - 1); |
| } |
| static size_t Log2Ceil(size_t size) { |
| return static_cast<size_t>(absl::bit_width(size - 1)); |
| } |
| |
| // Implementation of `CreateWithCustomLimit()`. |
| // This implementation allows for future memory allocation hints to |
| // be passed down into the CordRepFlat allocation function. |
| template <typename... AllocationHints> |
| static CordBuffer CreateWithCustomLimitImpl(size_t block_size, |
| size_t capacity, |
| AllocationHints... hints); |
| |
| // Consumes the value contained in this instance and resets the instance. |
| // This method returns a non-null Cordrep* if the current instances manages a |
| // CordRep*, and resets the instance to an empty SSO instance. If the current |
| // instance is an SSO instance, then this method returns nullptr and sets |
| // `short_value` to the inlined data value. In either case, the current |
| // instance length is reset to zero. |
| // This method is intended to be used by Cord internal functions only. |
| cord_internal::CordRep* ConsumeValue(absl::string_view& short_value) { |
| cord_internal::CordRep* rep = nullptr; |
| if (rep_.is_short()) { |
| short_value = absl::string_view(rep_.data(), rep_.short_length()); |
| } else { |
| rep = rep_.rep(); |
| } |
| rep_.set_short_length(0); |
| return rep; |
| } |
| |
| // Internal constructor. |
| explicit CordBuffer(cord_internal::CordRepFlat* rep) : rep_(rep) { |
| assert(rep != nullptr); |
| } |
| |
| Rep rep_; |
| |
| friend class Cord; |
| friend class CordBufferTestPeer; |
| }; |
| |
| inline constexpr size_t CordBuffer::MaximumPayload() { |
| return cord_internal::kMaxFlatLength; |
| } |
| |
| inline constexpr size_t CordBuffer::MaximumPayload(size_t block_size) { |
| return (std::min)(kCustomLimit, block_size) - cord_internal::kFlatOverhead; |
| } |
| |
| inline CordBuffer CordBuffer::CreateWithDefaultLimit(size_t capacity) { |
| if (capacity > Rep::kInlineCapacity) { |
| auto* rep = cord_internal::CordRepFlat::New(capacity); |
| rep->length = 0; |
| return CordBuffer(rep); |
| } |
| return CordBuffer(); |
| } |
| |
| template <typename... AllocationHints> |
| inline CordBuffer CordBuffer::CreateWithCustomLimitImpl( |
| size_t block_size, size_t capacity, AllocationHints... hints) { |
| assert(IsPow2(block_size)); |
| capacity = (std::min)(capacity, kCustomLimit); |
| block_size = (std::min)(block_size, kCustomLimit); |
| if (capacity + kOverhead >= block_size) { |
| capacity = block_size; |
| } else if (capacity <= kDefaultLimit) { |
| capacity = capacity + kOverhead; |
| } else if (!IsPow2(capacity)) { |
| // Check if rounded up to next power 2 is a good enough fit |
| // with limited waste making it an acceptable direct fit. |
| const size_t rounded_up = size_t{1} << Log2Ceil(capacity); |
| const size_t slop = rounded_up - capacity; |
| if (slop >= kOverhead && slop <= kMaxPageSlop + kOverhead) { |
| capacity = rounded_up; |
| } else { |
| // Round down to highest power of 2 <= capacity. |
| // Consider a more aggressive step down if that may reduce the |
| // risk of fragmentation where 'people are holding it wrong'. |
| const size_t rounded_down = size_t{1} << Log2Floor(capacity); |
| capacity = rounded_down; |
| } |
| } |
| const size_t length = capacity - kOverhead; |
| auto* rep = CordRepFlat::New(CordRepFlat::Large(), length, hints...); |
| rep->length = 0; |
| return CordBuffer(rep); |
| } |
| |
| inline CordBuffer CordBuffer::CreateWithCustomLimit(size_t block_size, |
| size_t capacity) { |
| return CreateWithCustomLimitImpl(block_size, capacity); |
| } |
| |
| inline CordBuffer::~CordBuffer() { |
| if (!rep_.is_short()) { |
| cord_internal::CordRepFlat::Delete(rep_.rep()); |
| } |
| } |
| |
| inline CordBuffer::CordBuffer(CordBuffer&& rhs) noexcept : rep_(rhs.rep_) { |
| rhs.rep_.set_short_length(0); |
| } |
| |
| inline CordBuffer& CordBuffer::operator=(CordBuffer&& rhs) noexcept { |
| if (!rep_.is_short()) cord_internal::CordRepFlat::Delete(rep_.rep()); |
| rep_ = rhs.rep_; |
| rhs.rep_.set_short_length(0); |
| return *this; |
| } |
| |
| inline absl::Span<char> CordBuffer::available() { |
| return rep_.is_short() ? rep_.short_available() : rep_.long_available(); |
| } |
| |
| inline absl::Span<char> CordBuffer::available_up_to(size_t size) { |
| return available().subspan(0, size); |
| } |
| |
| inline char* CordBuffer::data() { |
| return rep_.is_short() ? rep_.data() : rep_.rep()->Data(); |
| } |
| |
| inline const char* CordBuffer::data() const { |
| return rep_.is_short() ? rep_.data() : rep_.rep()->Data(); |
| } |
| |
| inline size_t CordBuffer::capacity() const { |
| return rep_.is_short() ? Rep::kInlineCapacity : rep_.rep()->Capacity(); |
| } |
| |
| inline size_t CordBuffer::length() const { |
| return rep_.is_short() ? rep_.short_length() : rep_.rep()->length; |
| } |
| |
| inline void CordBuffer::SetLength(size_t length) { |
| ABSL_HARDENING_ASSERT(length <= capacity()); |
| if (rep_.is_short()) { |
| rep_.set_short_length(length); |
| } else { |
| rep_.rep()->length = length; |
| } |
| } |
| |
| inline void CordBuffer::IncreaseLengthBy(size_t n) { |
| ABSL_HARDENING_ASSERT(n <= capacity() && length() + n <= capacity()); |
| if (rep_.is_short()) { |
| rep_.add_short_length(n); |
| } else { |
| rep_.rep()->length += n; |
| } |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_CORD_BUFFER_H_ |
| * |
| soong/.intermediates/external/abseil-cpp/absl_strings_cord_internal_hdrs/gen/my_include_dir/absl/strings/internal/cord_internal.h
// 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_STRINGS_INTERNAL_CORD_INTERNAL_H_ |
| #define ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_ |
| |
| #include <atomic> |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <string> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/endian.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/optimization.h" |
| #include "absl/container/internal/compressed_tuple.h" |
| #include "absl/container/internal/container_memory.h" |
| #include "absl/strings/string_view.h" |
| |
| // We can only add poisoning if we can detect consteval executions. |
| #if defined(ABSL_HAVE_CONSTANT_EVALUATED) && \ |
| (defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ |
| defined(ABSL_HAVE_MEMORY_SANITIZER)) |
| #define ABSL_INTERNAL_CORD_HAVE_SANITIZER 1 |
| #endif |
| |
| #define ABSL_CORD_INTERNAL_NO_SANITIZE \ |
| ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // The overhead of a vtable is too much for Cord, so we roll our own subclasses |
| // using only a single byte to differentiate classes from each other - the "tag" |
| // byte. Define the subclasses first so we can provide downcasting helper |
| // functions in the base class. |
| struct CordRep; |
| struct CordRepConcat; |
| struct CordRepExternal; |
| struct CordRepFlat; |
| struct CordRepSubstring; |
| struct CordRepCrc; |
| class CordRepBtree; |
| |
| class CordzInfo; |
| |
| // Default feature enable states for cord ring buffers |
| enum CordFeatureDefaults { kCordShallowSubcordsDefault = false }; |
| |
| extern std::atomic<bool> shallow_subcords_enabled; |
| |
| inline void enable_shallow_subcords(bool enable) { |
| shallow_subcords_enabled.store(enable, std::memory_order_relaxed); |
| } |
| |
| enum Constants { |
| // The inlined size to use with absl::InlinedVector. |
| // |
| // Note: The InlinedVectors in this file (and in cord.h) do not need to use |
| // the same value for their inlined size. The fact that they do is historical. |
| // It may be desirable for each to use a different inlined size optimized for |
| // that InlinedVector's usage. |
| // |
| // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for |
| // the inlined vector size (47 exists for backward compatibility). |
| kInlinedVectorSize = 47, |
| |
| // Prefer copying blocks of at most this size, otherwise reference count. |
| kMaxBytesToCopy = 511 |
| }; |
| |
| // Emits a fatal error "Unexpected node type: xyz" and aborts the program. |
| [[noreturn]] void LogFatalNodeType(CordRep* rep); |
| |
| // Fast implementation of memmove for up to 15 bytes. This implementation is |
| // safe for overlapping regions. If nullify_tail is true, the destination is |
| // padded with '\0' up to 15 bytes. |
| template <bool nullify_tail = false> |
| inline void SmallMemmove(char* dst, const char* src, size_t n) { |
| if (n >= 8) { |
| assert(n <= 15); |
| uint64_t buf1; |
| uint64_t buf2; |
| memcpy(&buf1, src, 8); |
| memcpy(&buf2, src + n - 8, 8); |
| if (nullify_tail) { |
| memset(dst + 7, 0, 8); |
| } |
| // GCC 12 has a false-positive -Wstringop-overflow warning here. |
| #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0) |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic ignored "-Wstringop-overflow" |
| #endif |
| memcpy(dst, &buf1, 8); |
| memcpy(dst + n - 8, &buf2, 8); |
| #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0) |
| #pragma GCC diagnostic pop |
| #endif |
| } else if (n >= 4) { |
| uint32_t buf1; |
| uint32_t buf2; |
| memcpy(&buf1, src, 4); |
| memcpy(&buf2, src + n - 4, 4); |
| if (nullify_tail) { |
| memset(dst + 4, 0, 4); |
| memset(dst + 7, 0, 8); |
| } |
| memcpy(dst, &buf1, 4); |
| memcpy(dst + n - 4, &buf2, 4); |
| } else { |
| if (n != 0) { |
| dst[0] = src[0]; |
| dst[n / 2] = src[n / 2]; |
| dst[n - 1] = src[n - 1]; |
| } |
| if (nullify_tail) { |
| memset(dst + 7, 0, 8); |
| memset(dst + n, 0, 8); |
| } |
| } |
| } |
| |
| // Compact class for tracking the reference count and state flags for CordRep |
| // instances. Data is stored in an atomic int32_t for compactness and speed. |
| class RefcountAndFlags { |
| public: |
| constexpr RefcountAndFlags() : count_{kRefIncrement} {} |
| struct Immortal {}; |
| explicit constexpr RefcountAndFlags(Immortal) : count_(kImmortalFlag) {} |
| |
| // Increments the reference count. Imposes no memory ordering. |
| inline void Increment() { |
| count_.fetch_add(kRefIncrement, std::memory_order_relaxed); |
| } |
| |
| // Asserts that the current refcount is greater than 0. If the refcount is |
| // greater than 1, decrements the reference count. |
| // |
| // Returns false if there are no references outstanding; true otherwise. |
| // Inserts barriers to ensure that state written before this method returns |
| // false will be visible to a thread that just observed this method returning |
| // false. Always returns false when the immortal bit is set. |
| inline bool Decrement() { |
| int32_t refcount = count_.load(std::memory_order_acquire); |
| assert(refcount > 0 || refcount & kImmortalFlag); |
| return refcount != kRefIncrement && |
| count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) != |
| kRefIncrement; |
| } |
| |
| // Same as Decrement but expect that refcount is greater than 1. |
| inline bool DecrementExpectHighRefcount() { |
| int32_t refcount = |
| count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel); |
| assert(refcount > 0 || refcount & kImmortalFlag); |
| return refcount != kRefIncrement; |
| } |
| |
| // Returns the current reference count using acquire semantics. |
| inline size_t Get() const { |
| return static_cast<size_t>(count_.load(std::memory_order_acquire) >> |
| kNumFlags); |
| } |
| |
| // Returns whether the atomic integer is 1. |
| // If the reference count is used in the conventional way, a |
| // reference count of 1 implies that the current thread owns the |
| // reference and no other thread shares it. |
| // This call performs the test for a reference count of one, and |
| // performs the memory barrier needed for the owning thread |
| // to act on the object, knowing that it has exclusive access to the |
| // object. Always returns false when the immortal bit is set. |
| inline bool IsOne() { |
| return count_.load(std::memory_order_acquire) == kRefIncrement; |
| } |
| |
| bool IsImmortal() const { |
| return (count_.load(std::memory_order_relaxed) & kImmortalFlag) != 0; |
| } |
| |
| private: |
| // We reserve the bottom bit for flag. |
| // kImmortalBit indicates that this entity should never be collected; it is |
| // used for the StringConstant constructor to avoid collecting immutable |
| // constant cords. |
| enum Flags { |
| kNumFlags = 1, |
| |
| kImmortalFlag = 0x1, |
| kRefIncrement = (1 << kNumFlags), |
| }; |
| |
| std::atomic<int32_t> count_; |
| }; |
| |
| // Various representations that we allow |
| enum CordRepKind { |
| UNUSED_0 = 0, |
| SUBSTRING = 1, |
| CRC = 2, |
| BTREE = 3, |
| UNUSED_4 = 4, |
| EXTERNAL = 5, |
| |
| // We have different tags for different sized flat arrays, |
| // starting with FLAT, and limited to MAX_FLAT_TAG. The below values map to an |
| // allocated range of 32 bytes to 256 KB. The current granularity is: |
| // - 8 byte granularity for flat sizes in [32 - 512] |
| // - 64 byte granularity for flat sizes in (512 - 8KiB] |
| // - 4KiB byte granularity for flat sizes in (8KiB, 256 KiB] |
| // If a new tag is needed in the future, then 'FLAT' and 'MAX_FLAT_TAG' should |
| // be adjusted as well as the Tag <---> Size mapping logic so that FLAT still |
| // represents the minimum flat allocation size. (32 bytes as of now). |
| FLAT = 6, |
| MAX_FLAT_TAG = 248 |
| }; |
| |
| // There are various locations where we want to check if some rep is a 'plain' |
| // data edge, i.e. an external or flat rep. By having FLAT == EXTERNAL + 1, we |
| // can perform this check in a single branch as 'tag >= EXTERNAL' |
| // Note that we can leave this optimization to the compiler. The compiler will |
| // DTRT when it sees a condition like `tag == EXTERNAL || tag >= FLAT`. |
| static_assert(FLAT == EXTERNAL + 1, "EXTERNAL and FLAT not consecutive"); |
| |
| struct CordRep { |
| // Result from an `extract edge` operation. Contains the (possibly changed) |
| // tree node as well as the extracted edge, or {tree, nullptr} if no edge |
| // could be extracted. |
| // On success, the returned `tree` value is null if `extracted` was the only |
| // data edge inside the tree, a data edge if there were only two data edges in |
| // the tree, or the (possibly new / smaller) remaining tree with the extracted |
| // data edge removed. |
| struct ExtractResult { |
| CordRep* tree; |
| CordRep* extracted; |
| }; |
| |
| CordRep() = default; |
| constexpr CordRep(RefcountAndFlags::Immortal immortal, size_t l) |
| : length(l), refcount(immortal), tag(EXTERNAL), storage{} {} |
| |
| // The following three fields have to be less than 32 bytes since |
| // that is the smallest supported flat node size. Some code optimizations rely |
| // on the specific layout of these fields. Notably: the non-trivial field |
| // `refcount` being preceded by `length`, and being tailed by POD data |
| // members only. |
| // LINT.IfChange |
| size_t length; |
| RefcountAndFlags refcount; |
| // If tag < FLAT, it represents CordRepKind and indicates the type of node. |
| // Otherwise, the node type is CordRepFlat and the tag is the encoded size. |
| uint8_t tag; |
| |
| // `storage` provides two main purposes: |
| // - the starting point for FlatCordRep.Data() [flexible-array-member] |
| // - 3 bytes of additional storage for use by derived classes. |
| // The latter is used by CordrepConcat and CordRepBtree. CordRepConcat stores |
| // a 'depth' value in storage[0], and the (future) CordRepBtree class stores |
| // `height`, `begin` and `end` in the 3 entries. Otherwise we would need to |
| // allocate room for these in the derived class, as not all compilers reuse |
| // padding space from the base class (clang and gcc do, MSVC does not, etc) |
| uint8_t storage[3]; |
| // LINT.ThenChange(cord_rep_btree.h:copy_raw) |
| |
| // Returns true if this instance's tag matches the requested type. |
| constexpr bool IsSubstring() const { return tag == SUBSTRING; } |
| constexpr bool IsCrc() const { return tag == CRC; } |
| constexpr bool IsExternal() const { return tag == EXTERNAL; } |
| constexpr bool IsFlat() const { return tag >= FLAT; } |
| constexpr bool IsBtree() const { return tag == BTREE; } |
| |
| inline CordRepSubstring* substring(); |
| inline const CordRepSubstring* substring() const; |
| inline CordRepCrc* crc(); |
| inline const CordRepCrc* crc() const; |
| inline CordRepExternal* external(); |
| inline const CordRepExternal* external() const; |
| inline CordRepFlat* flat(); |
| inline const CordRepFlat* flat() const; |
| inline CordRepBtree* btree(); |
| inline const CordRepBtree* btree() const; |
| |
| // -------------------------------------------------------------------- |
| // Memory management |
| |
| // Destroys the provided `rep`. |
| static void Destroy(CordRep* rep); |
| |
| // Increments the reference count of `rep`. |
| // Requires `rep` to be a non-null pointer value. |
| static inline CordRep* Ref(CordRep* rep); |
| |
| // Decrements the reference count of `rep`. Destroys rep if count reaches |
| // zero. Requires `rep` to be a non-null pointer value. |
| static inline void Unref(CordRep* rep); |
| }; |
| |
| struct CordRepSubstring : public CordRep { |
| size_t start; // Starting offset of substring in child |
| CordRep* child; |
| |
| // Creates a substring on `child`, adopting a reference on `child`. |
| // Requires `child` to be either a flat or external node, and `pos` and `n` to |
| // form a non-empty partial sub range of `'child`, i.e.: |
| // `n > 0 && n < length && n + pos <= length` |
| static inline CordRepSubstring* Create(CordRep* child, size_t pos, size_t n); |
| |
| // Creates a substring of `rep`. Does not adopt a reference on `rep`. |
| // Requires `IsDataEdge(rep) && n > 0 && pos + n <= rep->length`. |
| // If `n == rep->length` then this method returns `CordRep::Ref(rep)` |
| // If `rep` is a substring of a flat or external node, then this method will |
| // return a new substring of that flat or external node with `pos` adjusted |
| // with the original `start` position. |
| static inline CordRep* Substring(CordRep* rep, size_t pos, size_t n); |
| }; |
| |
| // Type for function pointer that will invoke the releaser function and also |
| // delete the `CordRepExternalImpl` corresponding to the passed in |
| // `CordRepExternal`. |
| using ExternalReleaserInvoker = void (*)(CordRepExternal*); |
| |
| // External CordReps are allocated together with a type erased releaser. The |
| // releaser is stored in the memory directly following the CordRepExternal. |
| struct CordRepExternal : public CordRep { |
| CordRepExternal() = default; |
| explicit constexpr CordRepExternal(absl::string_view str) |
| : CordRep(RefcountAndFlags::Immortal{}, str.size()), |
| base(str.data()), |
| releaser_invoker(nullptr) {} |
| |
| const char* base; |
| // Pointer to function that knows how to call and destroy the releaser. |
| ExternalReleaserInvoker releaser_invoker; |
| |
| // Deletes (releases) the external rep. |
| // Requires rep != nullptr and rep->IsExternal() |
| static void Delete(CordRep* rep); |
| }; |
| |
| // Use go/ranked-overloads for dispatching. |
| struct Rank0 {}; |
| struct Rank1 : Rank0 {}; |
| |
| template <typename Releaser, |
| typename = ::std::invoke_result_t<Releaser, absl::string_view>> |
| void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view data) { |
| ::std::invoke(std::forward<Releaser>(releaser), data); |
| } |
| |
| template <typename Releaser, typename = ::std::invoke_result_t<Releaser>> |
| void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view) { |
| ::std::invoke(std::forward<Releaser>(releaser)); |
| } |
| |
| // We use CompressedTuple so that we can benefit from EBCO. |
| template <typename Releaser> |
| struct CordRepExternalImpl |
| : public CordRepExternal, |
| public ::absl::container_internal::CompressedTuple<Releaser> { |
| // The extra int arg is so that we can avoid interfering with copy/move |
| // constructors while still benefitting from perfect forwarding. |
| template <typename T> |
| CordRepExternalImpl(T&& releaser, int) |
| : CordRepExternalImpl::CompressedTuple(std::forward<T>(releaser)) { |
| this->releaser_invoker = &Release; |
| } |
| |
| ~CordRepExternalImpl() { |
| InvokeReleaser(Rank1{}, std::move(this->template get<0>()), |
| absl::string_view(base, length)); |
| } |
| |
| static void Release(CordRepExternal* rep) { |
| delete static_cast<CordRepExternalImpl*>(rep); |
| } |
| }; |
| |
| inline CordRepSubstring* CordRepSubstring::Create(CordRep* child, size_t pos, |
| size_t n) { |
| assert(child != nullptr); |
| assert(n > 0); |
| assert(n < child->length); |
| assert(pos < child->length); |
| assert(n <= child->length - pos); |
| |
| // Move to strategical places inside the Cord logic and make this an assert. |
| if (ABSL_PREDICT_FALSE(!(child->IsExternal() || child->IsFlat()))) { |
| LogFatalNodeType(child); |
| } |
| |
| CordRepSubstring* rep = new CordRepSubstring(); |
| rep->length = n; |
| rep->tag = SUBSTRING; |
| rep->start = pos; |
| rep->child = child; |
| return rep; |
| } |
| |
| inline CordRep* CordRepSubstring::Substring(CordRep* rep, size_t pos, |
| size_t n) { |
| assert(rep != nullptr); |
| assert(n != 0); |
| assert(pos < rep->length); |
| assert(n <= rep->length - pos); |
| if (n == rep->length) return CordRep::Ref(rep); |
| if (rep->IsSubstring()) { |
| pos += rep->substring()->start; |
| rep = rep->substring()->child; |
| } |
| CordRepSubstring* substr = new CordRepSubstring(); |
| substr->length = n; |
| substr->tag = SUBSTRING; |
| substr->start = pos; |
| substr->child = CordRep::Ref(rep); |
| return substr; |
| } |
| |
| inline void CordRepExternal::Delete(CordRep* rep) { |
| assert(rep != nullptr && rep->IsExternal()); |
| auto* rep_external = static_cast<CordRepExternal*>(rep); |
| assert(rep_external->releaser_invoker != nullptr); |
| rep_external->releaser_invoker(rep_external); |
| } |
| |
| template <typename Str> |
| struct ConstInitExternalStorage { |
| ABSL_CONST_INIT static CordRepExternal value; |
| }; |
| |
| template <typename Str> |
| ABSL_CONST_INIT CordRepExternal |
| ConstInitExternalStorage<Str>::value(Str::value); |
| |
| enum { |
| kMaxInline = 15, |
| }; |
| |
| constexpr char GetOrNull(absl::string_view data, size_t pos) { |
| return pos < data.size() ? data[pos] : '\0'; |
| } |
| |
| // We store cordz_info as 64 bit pointer value in little endian format. This |
| // guarantees that the least significant byte of cordz_info matches the first |
| // byte of the inline data representation in `data`, which holds the inlined |
| // size or the 'is_tree' bit. |
| using cordz_info_t = int64_t; |
| |
| // Assert that the `cordz_info` pointer value perfectly overlaps the last half |
| // of `data` and can hold a pointer value. |
| static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, ""); |
| static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), ""); |
| |
| // LittleEndianByte() creates a little endian representation of 'value', i.e.: |
| // a little endian value where the first byte in the host's representation |
| // holds 'value`, with all other bytes being 0. |
| static constexpr cordz_info_t LittleEndianByte(unsigned char value) { |
| #if defined(ABSL_IS_BIG_ENDIAN) |
| return static_cast<cordz_info_t>(value) << ((sizeof(cordz_info_t) - 1) * 8); |
| #else |
| return value; |
| #endif |
| } |
| |
| class InlineData { |
| public: |
| // DefaultInitType forces the use of the default initialization constructor. |
| enum DefaultInitType { kDefaultInit }; |
| |
| // kNullCordzInfo holds the little endian representation of intptr_t(1) |
| // This is the 'null' / initial value of 'cordz_info'. The null value |
| // is specifically big endian 1 as with 64-bit pointers, the last |
| // byte of cordz_info overlaps with the last byte holding the tag. |
| static constexpr cordz_info_t kNullCordzInfo = LittleEndianByte(1); |
| |
| // kTagOffset contains the offset of the control byte / tag. This constant is |
| // intended mostly for debugging purposes: do not remove this constant as it |
| // is actively inspected and used by gdb pretty printing code. |
| static constexpr size_t kTagOffset = 0; |
| |
| // Implement `~InlineData()` conditionally: we only need this destructor to |
| // unpoison poisoned instances under *SAN, and it will only compile correctly |
| // if the current compiler supports `absl::is_constant_evaluated()`. |
| #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER |
| ~InlineData() noexcept { unpoison(); } |
| #endif |
| |
| constexpr InlineData() noexcept { poison_this(); } |
| |
| explicit InlineData(DefaultInitType) noexcept : rep_(kDefaultInit) { |
| poison_this(); |
| } |
| |
| explicit InlineData(CordRep* rep) noexcept : rep_(rep) { |
| ABSL_ASSERT(rep != nullptr); |
| } |
| |
| // Explicit constexpr constructor to create a constexpr InlineData |
| // value. Creates an inlined SSO value if `rep` is null, otherwise |
| // creates a tree instance value. |
| constexpr InlineData(absl::string_view sv, CordRep* rep) noexcept |
| : rep_(rep ? Rep(rep) : Rep(sv)) { |
| poison(); |
| } |
| |
| constexpr InlineData(const InlineData& rhs) noexcept; |
| InlineData& operator=(const InlineData& rhs) noexcept; |
| friend void swap(InlineData& lhs, InlineData& rhs) noexcept; |
| |
| friend bool operator==(const InlineData& lhs, const InlineData& rhs) { |
| #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER |
| const Rep l = lhs.rep_.SanitizerSafeCopy(); |
| const Rep r = rhs.rep_.SanitizerSafeCopy(); |
| return memcmp(&l, &r, sizeof(l)) == 0; |
| #else |
| return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; |
| #endif |
| } |
| friend bool operator!=(const InlineData& lhs, const InlineData& rhs) { |
| return !operator==(lhs, rhs); |
| } |
| |
| // Poisons the unused inlined SSO data if the current instance |
| // is inlined, else un-poisons the entire instance. |
| constexpr void poison(); |
| |
| // Un-poisons this instance. |
| constexpr void unpoison(); |
| |
| // Poisons the current instance. This is used on default initialization. |
| constexpr void poison_this(); |
| |
| // Returns true if the current instance is empty. |
| // The 'empty value' is an inlined data value of zero length. |
| bool is_empty() const { return rep_.tag() == 0; } |
| |
| // Returns true if the current instance holds a tree value. |
| bool is_tree() const { return (rep_.tag() & 1) != 0; } |
| |
| // Returns true if the current instance holds a cordz_info value. |
| // Requires the current instance to hold a tree value. |
| bool is_profiled() const { |
| assert(is_tree()); |
| return rep_.cordz_info() != kNullCordzInfo; |
| } |
| |
| // Returns true if either of the provided instances hold a cordz_info value. |
| // This method is more efficient than the equivalent `data1.is_profiled() || |
| // data2.is_profiled()`. Requires both arguments to hold a tree. |
| static bool is_either_profiled(const InlineData& data1, |
| const InlineData& data2) { |
| assert(data1.is_tree() && data2.is_tree()); |
| return (data1.rep_.cordz_info() | data2.rep_.cordz_info()) != |
| kNullCordzInfo; |
| } |
| |
| // Returns the cordz_info sampling instance for this instance, or nullptr |
| // if the current instance is not sampled and does not have CordzInfo data. |
| // Requires the current instance to hold a tree value. |
| CordzInfo* cordz_info() const { |
| assert(is_tree()); |
| intptr_t info = static_cast<intptr_t>(absl::little_endian::ToHost64( |
| static_cast<uint64_t>(rep_.cordz_info()))); |
| assert(info & 1); |
| return reinterpret_cast<CordzInfo*>(info - 1); |
| } |
| |
| // Sets the current cordz_info sampling instance for this instance, or nullptr |
| // if the current instance is not sampled and does not have CordzInfo data. |
| // Requires the current instance to hold a tree value. |
| void set_cordz_info(CordzInfo* cordz_info) { |
| assert(is_tree()); |
| uintptr_t info = reinterpret_cast<uintptr_t>(cordz_info) | 1; |
| rep_.set_cordz_info( |
| static_cast<cordz_info_t>(absl::little_endian::FromHost64(info))); |
| } |
| |
| // Resets the current cordz_info to null / empty. |
| void clear_cordz_info() { |
| assert(is_tree()); |
| rep_.set_cordz_info(kNullCordzInfo); |
| } |
| |
| // Returns a read only pointer to the character data inside this instance. |
| // Requires the current instance to hold inline data. |
| const char* as_chars() const { |
| assert(!is_tree()); |
| return rep_.as_chars(); |
| } |
| |
| // Returns a mutable pointer to the character data inside this instance. |
| // Should be used for 'write only' operations setting an inlined value. |
| // Applications can set the value of inlined data either before or after |
| // setting the inlined size, i.e., both of the below are valid: |
| // |
| // // Set inlined data and inline size |
| // memcpy(data_.as_chars(), data, size); |
| // data_.set_inline_size(size); |
| // |
| // // Set inlined size and inline data |
| // data_.set_inline_size(size); |
| // memcpy(data_.as_chars(), data, size); |
| // |
| // It's an error to read from the returned pointer without a preceding write |
| // if the current instance does not hold inline data, i.e.: is_tree() == true. |
| char* as_chars() { return rep_.as_chars(); } |
| |
| // Returns the tree value of this value. |
| // Requires the current instance to hold a tree value. |
| CordRep* as_tree() const { |
| assert(is_tree()); |
| return rep_.tree(); |
| } |
| |
| void set_inline_data(const char* data, size_t n) { |
| ABSL_ASSERT(n <= kMaxInline); |
| unpoison(); |
| rep_.set_tag(static_cast<int8_t>(n << 1)); |
| SmallMemmove<true>(rep_.as_chars(), data, n); |
| poison(); |
| } |
| |
| void CopyInlineToString(std::string* dst) const { |
| assert(!is_tree()); |
| // As Cord can store only 15 bytes it is smaller than std::string's |
| // small string optimization buffer size. Therefore we will always trigger |
| // the fast assign short path. |
| // |
| // Copying with a size equal to the maximum allows more efficient, wider |
| // stores to be used and no branching. |
| dst->assign(rep_.SanitizerSafeCopy().as_chars(), kMaxInline); |
| // After the copy we then change the size and put in a 0 byte. |
| dst->erase(inline_size()); |
| } |
| |
| void copy_max_inline_to(char* dst) const { |
| assert(!is_tree()); |
| memcpy(dst, rep_.SanitizerSafeCopy().as_chars(), kMaxInline); |
| } |
| |
| // Initialize this instance to holding the tree value `rep`, |
| // initializing the cordz_info to null, i.e.: 'not profiled'. |
| void make_tree(CordRep* rep) { |
| unpoison(); |
| rep_.make_tree(rep); |
| } |
| |
| // Set the tree value of this instance to 'rep`. |
| // Requires the current instance to already hold a tree value. |
| // Does not affect the value of cordz_info. |
| void set_tree(CordRep* rep) { |
| assert(is_tree()); |
| rep_.set_tree(rep); |
| } |
| |
| // Returns the size of the inlined character data inside this instance. |
| // Requires the current instance to hold inline data. |
| size_t inline_size() const { return rep_.inline_size(); } |
| |
| // Sets the size of the inlined character data inside this instance. |
| // Requires `size` to be <= kMaxInline. |
| // See the documentation on 'as_chars()' for more information and examples. |
| void set_inline_size(size_t size) { |
| unpoison(); |
| rep_.set_inline_size(size); |
| poison(); |
| } |
| |
| // Compares 'this' inlined data with rhs. The comparison is a straightforward |
| // lexicographic comparison. `Compare()` returns values as follows: |
| // |
| // -1 'this' InlineData instance is smaller |
| // 0 the InlineData instances are equal |
| // 1 'this' InlineData instance larger |
| int Compare(const InlineData& rhs) const { |
| return Compare(rep_.SanitizerSafeCopy(), rhs.rep_.SanitizerSafeCopy()); |
| } |
| |
| private: |
| struct Rep { |
| // See cordz_info_t for forced alignment and size of `cordz_info` details. |
| struct AsTree { |
| explicit constexpr AsTree(absl::cord_internal::CordRep* tree) |
| : rep(tree) {} |
| cordz_info_t cordz_info = kNullCordzInfo; |
| absl::cord_internal::CordRep* rep; |
| }; |
| |
| explicit Rep(DefaultInitType) {} |
| constexpr Rep() : data{0} {} |
| constexpr Rep(const Rep&) = default; |
| constexpr Rep& operator=(const Rep&) = default; |
| |
| explicit constexpr Rep(CordRep* rep) : as_tree(rep) {} |
| |
| explicit constexpr Rep(absl::string_view chars) |
| : data{static_cast<char>((chars.size() << 1)), |
| GetOrNull(chars, 0), |
| GetOrNull(chars, 1), |
| GetOrNull(chars, 2), |
| GetOrNull(chars, 3), |
| GetOrNull(chars, 4), |
| GetOrNull(chars, 5), |
| GetOrNull(chars, 6), |
| GetOrNull(chars, 7), |
| GetOrNull(chars, 8), |
| GetOrNull(chars, 9), |
| GetOrNull(chars, 10), |
| GetOrNull(chars, 11), |
| GetOrNull(chars, 12), |
| GetOrNull(chars, 13), |
| GetOrNull(chars, 14)} {} |
| |
| #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER |
| // Break compiler optimization for cases when value is allocated on the |
| // stack. Compiler assumes that the the variable is fully accessible |
| // regardless of our poisoning. |
| // Missing report: https://github.com/llvm/llvm-project/issues/100640 |
| const Rep* self() const { |
| const Rep* volatile ptr = this; |
| return ptr; |
| } |
| Rep* self() { |
| Rep* volatile ptr = this; |
| return ptr; |
| } |
| #else |
| constexpr const Rep* self() const { return this; } |
| constexpr Rep* self() { return this; } |
| #endif |
| |
| // Disable sanitizer as we must always be able to read `tag`. |
| ABSL_CORD_INTERNAL_NO_SANITIZE |
| int8_t tag() const { return reinterpret_cast<const int8_t*>(this)[0]; } |
| void set_tag(int8_t rhs) { reinterpret_cast<int8_t*>(self())[0] = rhs; } |
| |
| char* as_chars() { return self()->data + 1; } |
| const char* as_chars() const { return self()->data + 1; } |
| |
| bool is_tree() const { return (self()->tag() & 1) != 0; } |
| |
| size_t inline_size() const { |
| ABSL_ASSERT(!self()->is_tree()); |
| return static_cast<size_t>(self()->tag()) >> 1; |
| } |
| |
| void set_inline_size(size_t size) { |
| ABSL_ASSERT(size <= kMaxInline); |
| self()->set_tag(static_cast<int8_t>(size << 1)); |
| } |
| |
| CordRep* tree() const { return self()->as_tree.rep; } |
| void set_tree(CordRep* rhs) { self()->as_tree.rep = rhs; } |
| |
| cordz_info_t cordz_info() const { return self()->as_tree.cordz_info; } |
| void set_cordz_info(cordz_info_t rhs) { self()->as_tree.cordz_info = rhs; } |
| |
| void make_tree(CordRep* tree) { |
| self()->as_tree.rep = tree; |
| self()->as_tree.cordz_info = kNullCordzInfo; |
| } |
| |
| #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER |
| constexpr Rep SanitizerSafeCopy() const { |
| if (!absl::is_constant_evaluated()) { |
| Rep res; |
| if (is_tree()) { |
| res = *this; |
| } else { |
| res.set_tag(tag()); |
| memcpy(res.as_chars(), as_chars(), inline_size()); |
| } |
| return res; |
| } else { |
| return *this; |
| } |
| } |
| #else |
| constexpr const Rep& SanitizerSafeCopy() const { return *this; } |
| #endif |
| |
| // If the data has length <= kMaxInline, we store it in `data`, and |
| // store the size in the first char of `data` shifted left + 1. |
| // Else we store it in a tree and store a pointer to that tree in |
| // `as_tree.rep` with a tagged pointer to make `tag() & 1` non zero. |
| union { |
| char data[kMaxInline + 1]; |
| AsTree as_tree; |
| }; |
| |
| // TODO(b/145829486): see swap(InlineData, InlineData) for more info. |
| inline void SwapValue(Rep rhs, Rep& refrhs) { |
| memcpy(&refrhs, this, sizeof(*this)); |
| memcpy(this, &rhs, sizeof(*this)); |
| } |
| }; |
| |
| // Private implementation of `Compare()` |
| static inline int Compare(const Rep& lhs, const Rep& rhs) { |
| uint64_t x, y; |
| memcpy(&x, lhs.as_chars(), sizeof(x)); |
| memcpy(&y, rhs.as_chars(), sizeof(y)); |
| if (x == y) { |
| memcpy(&x, lhs.as_chars() + 7, sizeof(x)); |
| memcpy(&y, rhs.as_chars() + 7, sizeof(y)); |
| if (x == y) { |
| if (lhs.inline_size() == rhs.inline_size()) return 0; |
| return lhs.inline_size() < rhs.inline_size() ? -1 : 1; |
| } |
| } |
| x = absl::big_endian::FromHost64(x); |
| y = absl::big_endian::FromHost64(y); |
| return x < y ? -1 : 1; |
| } |
| |
| Rep rep_; |
| }; |
| |
| static_assert(sizeof(InlineData) == kMaxInline + 1, ""); |
| |
| #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER |
| |
| constexpr InlineData::InlineData(const InlineData& rhs) noexcept |
| : rep_(rhs.rep_.SanitizerSafeCopy()) { |
| poison(); |
| } |
| |
| inline InlineData& InlineData::operator=(const InlineData& rhs) noexcept { |
| unpoison(); |
| rep_ = rhs.rep_.SanitizerSafeCopy(); |
| poison(); |
| return *this; |
| } |
| |
| constexpr void InlineData::poison_this() { |
| if (!absl::is_constant_evaluated()) { |
| container_internal::SanitizerPoisonObject(this); |
| } |
| } |
| |
| constexpr void InlineData::unpoison() { |
| if (!absl::is_constant_evaluated()) { |
| container_internal::SanitizerUnpoisonObject(this); |
| } |
| } |
| |
| constexpr void InlineData::poison() { |
| if (!absl::is_constant_evaluated()) { |
| if (is_tree()) { |
| container_internal::SanitizerUnpoisonObject(this); |
| } else if (const size_t size = inline_size()) { |
| if (size < kMaxInline) { |
| const char* end = rep_.as_chars() + size; |
| container_internal::SanitizerPoisonMemoryRegion(end, kMaxInline - size); |
| } |
| } else { |
| container_internal::SanitizerPoisonObject(this); |
| } |
| } |
| } |
| |
| #else // ABSL_INTERNAL_CORD_HAVE_SANITIZER |
| |
| constexpr InlineData::InlineData(const InlineData&) noexcept = default; |
| inline InlineData& InlineData::operator=(const InlineData&) noexcept = default; |
| |
| constexpr void InlineData::poison_this() {} |
| constexpr void InlineData::unpoison() {} |
| constexpr void InlineData::poison() {} |
| |
| #endif // ABSL_INTERNAL_CORD_HAVE_SANITIZER |
| |
| inline CordRepSubstring* CordRep::substring() { |
| assert(IsSubstring()); |
| return static_cast<CordRepSubstring*>(this); |
| } |
| |
| inline const CordRepSubstring* CordRep::substring() const { |
| assert(IsSubstring()); |
| return static_cast<const CordRepSubstring*>(this); |
| } |
| |
| inline CordRepExternal* CordRep::external() { |
| assert(IsExternal()); |
| return static_cast<CordRepExternal*>(this); |
| } |
| |
| inline const CordRepExternal* CordRep::external() const { |
| assert(IsExternal()); |
| return static_cast<const CordRepExternal*>(this); |
| } |
| |
| inline CordRep* CordRep::Ref(CordRep* rep) { |
| // ABSL_ASSUME is a workaround for |
| // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105585 |
| ABSL_ASSUME(rep != nullptr); |
| rep->refcount.Increment(); |
| return rep; |
| } |
| |
| inline void CordRep::Unref(CordRep* rep) { |
| assert(rep != nullptr); |
| // Expect refcount to be 0. Avoiding the cost of an atomic decrement should |
| // typically outweigh the cost of an extra branch checking for ref == 1. |
| if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) { |
| Destroy(rep); |
| } |
| } |
| |
| inline void swap(InlineData& lhs, InlineData& rhs) noexcept { |
| lhs.unpoison(); |
| rhs.unpoison(); |
| // TODO(b/145829486): `std::swap(lhs.rep_, rhs.rep_)` results in bad codegen |
| // on clang, spilling the temporary swap value on the stack. Since `Rep` is |
| // trivial, we can make clang DTRT by calling a hand-rolled `SwapValue` where |
| // we pass `rhs` both by value (register allocated) and by reference. The IR |
| // then folds and inlines correctly into an optimized swap without spill. |
| lhs.rep_.SwapValue(rhs.rep_, rhs.rep_); |
| rhs.poison(); |
| lhs.poison(); |
| } |
| |
| } // namespace cord_internal |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| #endif // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_ |
| *¸ |
| osoong/.intermediates/external/abseil-cpp/absl_strings_cord_hdrs/gen/my_include_dir/absl/strings/cord_analysis.hÄ// 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_STRINGS_CORD_ANALYSIS_H_ |
| #define ABSL_STRINGS_CORD_ANALYSIS_H_ |
| |
| #include <cstddef> |
| #include <cstdint> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/nullability.h" |
| #include "absl/strings/internal/cord_internal.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // Returns the *approximate* number of bytes held in full or in part by this |
| // Cord (which may not remain the same between invocations). Cords that share |
| // memory could each be "charged" independently for the same shared memory. |
| size_t GetEstimatedMemoryUsage(const CordRep* absl_nonnull rep); |
| |
| // Returns the *approximate* number of bytes held in full or in part by this |
| // Cord for the distinct memory held by this cord. This is similar to |
| // `GetEstimatedMemoryUsage()`, except that if the cord has multiple references |
| // to the same memory, that memory is only counted once. |
| // |
| // For example: |
| // absl::Cord cord; |
| // cord.append(some_other_cord); |
| // cord.append(some_other_cord); |
| // // Calls GetEstimatedMemoryUsage() and counts `other_cord` twice: |
| // cord.EstimatedMemoryUsage(kTotal); |
| // // Calls GetMorePreciseMemoryUsage() and counts `other_cord` once: |
| // cord.EstimatedMemoryUsage(kTotalMorePrecise); |
| // |
| // This is more expensive than `GetEstimatedMemoryUsage()` as it requires |
| // deduplicating all memory references. |
| size_t GetMorePreciseMemoryUsage(const CordRep* absl_nonnull rep); |
| |
| // Returns the *approximate* number of bytes held in full or in part by this |
| // CordRep weighted by the sharing ratio of that data. For example, if some data |
| // edge is shared by 4 different Cords, then each cord is attribute 1/4th of |
| // the total memory usage as a 'fair share' of the total memory usage. |
| size_t GetEstimatedFairShareMemoryUsage(const CordRep* absl_nonnull rep); |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| |
| #endif // ABSL_STRINGS_CORD_ANALYSIS_H_ |
| * |
| soong/.intermediates/external/abseil-cpp/absl_functional_any_invocable_hdrs/gen/my_include_dir/absl/functional/internal/any_invocable.h// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // Implementation details for `absl::AnyInvocable` |
| |
| #ifndef ABSL_FUNCTIONAL_INTERNAL_ANY_INVOCABLE_H_ |
| #define ABSL_FUNCTIONAL_INTERNAL_ANY_INVOCABLE_H_ |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // // |
| // This implementation chooses between local storage and remote storage for // |
| // the contained target object based on the target object's size, alignment // |
| // requirements, and whether or not it has a nothrow move constructor. // |
| // Additional optimizations are performed when the object is a trivially // |
| // copyable type [basic.types]. // |
| // // |
| // There are three datamembers per `AnyInvocable` instance // |
| // // |
| // 1) A union containing either // |
| // - A pointer to the target object referred to via a void*, or // |
| // - the target object, emplaced into a raw char buffer // |
| // // |
| // 2) A function pointer to a "manager" function operation that takes a // |
| // discriminator and logically branches to either perform a move operation // |
| // or destroy operation based on that discriminator. // |
| // // |
| // 3) A function pointer to an "invoker" function operation that invokes the // |
| // target object, directly returning the result. // |
| // // |
| // When in the logically empty state, the manager function is an empty // |
| // function and the invoker function is one that would be undefined behavior // |
| // to call. // |
| // // |
| // An additional optimization is performed when converting from one // |
| // AnyInvocable to another where only the noexcept specification and/or the // |
| // cv/ref qualifiers of the function type differ. In these cases, the // |
| // conversion works by "moving the guts", similar to if they were the same // |
| // exact type, as opposed to having to perform an additional layer of // |
| // wrapping through remote storage. // |
| // // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // IWYU pragma: private, include "absl/functional/any_invocable.h" |
| |
| #include <cassert> |
| #include <cstddef> |
| #include <cstring> |
| #include <exception> |
| #include <functional> |
| #include <memory> |
| #include <new> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/optimization.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/utility/utility.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // Defined in functional/any_invocable.h |
| template <class Sig> |
| class AnyInvocable; |
| |
| namespace internal_any_invocable { |
| |
| // Constants relating to the small-object-storage for AnyInvocable |
| enum StorageProperty : std::size_t { |
| kAlignment = alignof(std::max_align_t), // The alignment of the storage |
| kStorageSize = sizeof(void*) * 2 // The size of the storage |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // A metafunction for checking if a type is an AnyInvocable instantiation. |
| // This is used during conversion operations. |
| template <class T> |
| struct IsAnyInvocable : std::false_type {}; |
| |
| template <class Sig> |
| struct IsAnyInvocable<AnyInvocable<Sig>> : std::true_type {}; |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // A metafunction that tells us whether or not a target function type should be |
| // stored locally in the small object optimization storage |
| template <class T> |
| constexpr bool IsStoredLocally() { |
| if constexpr (sizeof(T) <= kStorageSize && alignof(T) <= kAlignment && |
| kAlignment % alignof(T) == 0) { |
| return std::is_nothrow_move_constructible<T>::value; |
| } |
| return false; |
| } |
| |
| // An implementation of std::remove_cvref_t of C++20. |
| template <class T> |
| using RemoveCVRef = |
| typename std::remove_cv<typename std::remove_reference<T>::type>::type; |
| |
| // An implementation of std::invoke_r of C++23. |
| template <class ReturnType, class F, class... P> |
| ReturnType InvokeR(F&& f, P&&... args) { |
| if constexpr (std::is_void_v<ReturnType>) { |
| std::invoke(std::forward<F>(f), std::forward<P>(args)...); |
| } else { |
| return std::invoke(std::forward<F>(f), std::forward<P>(args)...); |
| } |
| } |
| |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| /// |
| // A metafunction that takes a "T" corresponding to a parameter type of the |
| // user's specified function type, and yields the parameter type to use for the |
| // type-erased invoker. In order to prevent observable moves, this must be |
| // either a reference or, if the type is trivial, the original parameter type |
| // itself. Since the parameter type may be incomplete at the point that this |
| // metafunction is used, we can only do this optimization for scalar types |
| // rather than for any trivial type. |
| template <typename T> |
| T ForwardImpl(std::true_type); |
| |
| template <typename T> |
| T&& ForwardImpl(std::false_type); |
| |
| // NOTE: We deliberately use an intermediate struct instead of a direct alias, |
| // as a workaround for b/206991861 on MSVC versions < 1924. |
| template <class T> |
| struct ForwardedParameter { |
| using type = decltype(( |
| ForwardImpl<T>)(std::integral_constant<bool, |
| std::is_scalar<T>::value>())); |
| }; |
| |
| template <class T> |
| using ForwardedParameterType = typename ForwardedParameter<T>::type; |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // A discriminator when calling the "manager" function that describes operation |
| // type-erased operation should be invoked. |
| // |
| // "relocate_from_to" specifies that the manager should perform a move. |
| // |
| // "dispose" specifies that the manager should perform a destroy. |
| enum class FunctionToCall : bool { relocate_from_to, dispose }; |
| |
| // The portion of `AnyInvocable` state that contains either a pointer to the |
| // target object or the object itself in local storage |
| union TypeErasedState { |
| struct { |
| // A pointer to the type-erased object when remotely stored |
| void* target; |
| // The size of the object for `RemoteManagerTrivial` |
| std::size_t size; |
| } remote; |
| |
| // Local-storage for the type-erased object when small and trivial enough |
| alignas(kAlignment) unsigned char storage[kStorageSize]; |
| }; |
| |
| // A typed accessor for the object in `TypeErasedState` storage |
| template <class T> |
| T& ObjectInLocalStorage(TypeErasedState* const state) { |
| // We launder here because the storage may be reused with the same type. |
| return *std::launder(reinterpret_cast<T*>(&state->storage)); |
| } |
| |
| // The type for functions issuing lifetime-related operations: move and dispose |
| // A pointer to such a function is contained in each `AnyInvocable` instance. |
| // NOTE: When specifying `FunctionToCall::`dispose, the same state must be |
| // passed as both "from" and "to". |
| using ManagerType = void(FunctionToCall /*operation*/, |
| TypeErasedState* /*from*/, |
| TypeErasedState* /*to*/) noexcept(true); |
| |
| // The type for functions issuing the actual invocation of the object |
| // A pointer to such a function is contained in each AnyInvocable instance. |
| template <bool SigIsNoexcept, class ReturnType, class... P> |
| using InvokerType = ReturnType( |
| TypeErasedState*, ForwardedParameterType<P>...) noexcept(SigIsNoexcept); |
| |
| // The manager that is used when AnyInvocable is empty |
| inline void EmptyManager(FunctionToCall /*operation*/, |
| TypeErasedState* /*from*/, |
| TypeErasedState* /*to*/) noexcept {} |
| |
| // The manager that is used when a target function is in local storage and is |
| // a trivially copyable type. |
| inline void LocalManagerTrivial(FunctionToCall /*operation*/, |
| TypeErasedState* const from, |
| TypeErasedState* const to) noexcept { |
| // This single statement without branching handles both possible operations. |
| // |
| // For FunctionToCall::dispose, "from" and "to" point to the same state, and |
| // so this assignment logically would do nothing. |
| // |
| // Note: Correctness here relies on http://wg21.link/p0593, which has only |
| // become standard in C++20, though implementations do not break it in |
| // practice for earlier versions of C++. |
| // |
| // The correct way to do this without that paper is to first placement-new a |
| // default-constructed T in "to->storage" prior to the memmove, but doing so |
| // requires a different function to be created for each T that is stored |
| // locally, which can cause unnecessary bloat and be less cache friendly. |
| *to = *from; |
| |
| // Note: Because the type is trivially copyable, the destructor does not need |
| // to be called ("trivially copyable" requires a trivial destructor). |
| } |
| |
| // The manager that is used when a target function is in local storage and is |
| // not a trivially copyable type. |
| template <class T> |
| void LocalManagerNontrivial(FunctionToCall operation, |
| TypeErasedState* const from, |
| TypeErasedState* const to) noexcept { |
| static_assert(IsStoredLocally<T>(), |
| "Local storage must only be used for supported types."); |
| static_assert(!std::is_trivially_copyable<T>::value, |
| "Locally stored types must be trivially copyable."); |
| |
| T& from_object = (ObjectInLocalStorage<T>)(from); |
| |
| switch (operation) { |
| case FunctionToCall::relocate_from_to: |
| // NOTE: Requires that the left-hand operand is already empty. |
| ::new (static_cast<void*>(&to->storage)) T(std::move(from_object)); |
| ABSL_FALLTHROUGH_INTENDED; |
| case FunctionToCall::dispose: |
| from_object.~T(); // Must not throw. // NOLINT |
| return; |
| } |
| ABSL_UNREACHABLE(); |
| } |
| |
| // The invoker that is used when a target function is in local storage |
| // Note: QualTRef here is the target function type along with cv and reference |
| // qualifiers that must be used when calling the function. |
| template <bool SigIsNoexcept, class ReturnType, class QualTRef, class... P> |
| ReturnType LocalInvoker( |
| TypeErasedState* const state, |
| ForwardedParameterType<P>... args) noexcept(SigIsNoexcept) { |
| using RawT = RemoveCVRef<QualTRef>; |
| static_assert( |
| IsStoredLocally<RawT>(), |
| "Target object must be in local storage in order to be invoked from it."); |
| |
| auto& f = (ObjectInLocalStorage<RawT>)(state); |
| return (InvokeR<ReturnType>)(static_cast<QualTRef>(f), |
| static_cast<ForwardedParameterType<P>>(args)...); |
| } |
| |
| // The manager that is used when a target function is in remote storage and it |
| // has a trivial destructor |
| inline void RemoteManagerTrivial(FunctionToCall operation, |
| TypeErasedState* const from, |
| TypeErasedState* const to) noexcept { |
| switch (operation) { |
| case FunctionToCall::relocate_from_to: |
| // NOTE: Requires that the left-hand operand is already empty. |
| to->remote = from->remote; |
| return; |
| case FunctionToCall::dispose: |
| #if defined(__cpp_sized_deallocation) |
| ::operator delete(from->remote.target, from->remote.size); |
| #else // __cpp_sized_deallocation |
| ::operator delete(from->remote.target); |
| #endif // __cpp_sized_deallocation |
| return; |
| } |
| ABSL_UNREACHABLE(); |
| } |
| |
| // The manager that is used when a target function is in remote storage and the |
| // destructor of the type is not trivial |
| template <class T> |
| void RemoteManagerNontrivial(FunctionToCall operation, |
| TypeErasedState* const from, |
| TypeErasedState* const to) noexcept { |
| static_assert(!IsStoredLocally<T>(), |
| "Remote storage must only be used for types that do not " |
| "qualify for local storage."); |
| |
| switch (operation) { |
| case FunctionToCall::relocate_from_to: |
| // NOTE: Requires that the left-hand operand is already empty. |
| to->remote.target = from->remote.target; |
| return; |
| case FunctionToCall::dispose: |
| ::delete static_cast<T*>(from->remote.target); // Must not throw. |
| return; |
| } |
| ABSL_UNREACHABLE(); |
| } |
| |
| // The invoker that is used when a target function is in remote storage |
| template <bool SigIsNoexcept, class ReturnType, class QualTRef, class... P> |
| ReturnType RemoteInvoker( |
| TypeErasedState* const state, |
| ForwardedParameterType<P>... args) noexcept(SigIsNoexcept) { |
| using RawT = RemoveCVRef<QualTRef>; |
| static_assert(!IsStoredLocally<RawT>(), |
| "Target object must be in remote storage in order to be " |
| "invoked from it."); |
| |
| auto& f = *static_cast<RawT*>(state->remote.target); |
| return (InvokeR<ReturnType>)(static_cast<QualTRef>(f), |
| static_cast<ForwardedParameterType<P>>(args)...); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // A metafunction that checks if a type T is an instantiation of |
| // absl::in_place_type_t (needed for constructor constraints of AnyInvocable). |
| template <class T> |
| struct IsInPlaceType : std::false_type {}; |
| |
| template <class T> |
| struct IsInPlaceType<absl::in_place_type_t<T>> : std::true_type {}; |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // A constructor name-tag used with CoreImpl (below) to request the |
| // conversion-constructor. QualDecayedTRef is the decayed-type of the object to |
| // wrap, along with the cv and reference qualifiers that must be applied when |
| // performing an invocation of the wrapped object. |
| template <class QualDecayedTRef> |
| struct TypedConversionConstruct {}; |
| |
| // A helper base class for all core operations of AnyInvocable. Most notably, |
| // this class creates the function call operator and constraint-checkers so that |
| // the top-level class does not have to be a series of partial specializations. |
| // |
| // Note: This definition exists (as opposed to being a declaration) so that if |
| // the user of the top-level template accidentally passes a template argument |
| // that is not a function type, they will get a static_assert in AnyInvocable's |
| // class body rather than an error stating that Impl is not defined. |
| template <class Sig> |
| class Impl {}; // Note: This is partially-specialized later. |
| |
| // A std::unique_ptr deleter that deletes memory allocated via ::operator new. |
| #if defined(__cpp_sized_deallocation) |
| class TrivialDeleter { |
| public: |
| explicit TrivialDeleter(std::size_t size) : size_(size) {} |
| |
| void operator()(void* target) const { |
| ::operator delete(target, size_); |
| } |
| |
| private: |
| std::size_t size_; |
| }; |
| #else // __cpp_sized_deallocation |
| class TrivialDeleter { |
| public: |
| explicit TrivialDeleter(std::size_t) {} |
| |
| void operator()(void* target) const { ::operator delete(target); } |
| }; |
| #endif // __cpp_sized_deallocation |
| |
| template <bool SigIsNoexcept, class ReturnType, class... P> |
| class CoreImpl; |
| |
| constexpr bool IsCompatibleConversion(void*, void*) { return false; } |
| template <bool NoExceptSrc, bool NoExceptDest, class... T> |
| constexpr bool IsCompatibleConversion(CoreImpl<NoExceptSrc, T...>*, |
| CoreImpl<NoExceptDest, T...>*) { |
| return !NoExceptDest || NoExceptSrc; |
| } |
| |
| // A helper base class for all core operations of AnyInvocable that do not |
| // depend on the cv/ref qualifiers of the function type. |
| template <bool SigIsNoexcept, class ReturnType, class... P> |
| class CoreImpl { |
| public: |
| using result_type = ReturnType; |
| |
| CoreImpl() noexcept : manager_(EmptyManager), invoker_(nullptr) {} |
| |
| // Note: QualDecayedTRef here includes the cv-ref qualifiers associated with |
| // the invocation of the Invocable. The unqualified type is the target object |
| // type to be stored. |
| template <class QualDecayedTRef, class F> |
| explicit CoreImpl(TypedConversionConstruct<QualDecayedTRef>, F&& f) { |
| using DecayedT = RemoveCVRef<QualDecayedTRef>; |
| |
| if constexpr (std::is_pointer<DecayedT>::value || |
| std::is_member_pointer<DecayedT>::value) { |
| // This condition handles types that decay into pointers. This includes |
| // function references, which cannot be null. GCC warns against comparing |
| // their decayed form with nullptr (https://godbolt.org/z/9r9TMTcPK). |
| // We could work around this warning with constexpr programming, using |
| // std::is_function_v<std::remove_reference_t<F>>, but we choose to ignore |
| // it instead of writing more code. |
| #if !defined(__clang__) && defined(__GNUC__) |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic ignored "-Wpragmas" |
| #pragma GCC diagnostic ignored "-Waddress" |
| #pragma GCC diagnostic ignored "-Wnonnull-compare" |
| #endif |
| if (static_cast<DecayedT>(f) == nullptr) { |
| #if !defined(__clang__) && defined(__GNUC__) |
| #pragma GCC diagnostic pop |
| #endif |
| manager_ = EmptyManager; |
| invoker_ = nullptr; |
| } else { |
| InitializeStorage<QualDecayedTRef>(std::forward<F>(f)); |
| } |
| } else if constexpr (IsCompatibleAnyInvocable<DecayedT>::value) { |
| // In this case we can "steal the guts" of the other AnyInvocable. |
| f.manager_(FunctionToCall::relocate_from_to, &f.state_, &state_); |
| manager_ = f.manager_; |
| invoker_ = f.invoker_; |
| |
| f.manager_ = EmptyManager; |
| f.invoker_ = nullptr; |
| } else if constexpr (IsAnyInvocable<DecayedT>::value) { |
| if (f.HasValue()) { |
| InitializeStorage<QualDecayedTRef>(std::forward<F>(f)); |
| } else { |
| manager_ = EmptyManager; |
| invoker_ = nullptr; |
| } |
| } else { |
| InitializeStorage<QualDecayedTRef>(std::forward<F>(f)); |
| } |
| } |
| |
| // Note: QualTRef here includes the cv-ref qualifiers associated with the |
| // invocation of the Invocable. The unqualified type is the target object |
| // type to be stored. |
| template <class QualTRef, class... Args> |
| explicit CoreImpl(absl::in_place_type_t<QualTRef>, Args&&... args) { |
| InitializeStorage<QualTRef>(std::forward<Args>(args)...); |
| } |
| |
| CoreImpl(CoreImpl&& other) noexcept { |
| other.manager_(FunctionToCall::relocate_from_to, &other.state_, &state_); |
| manager_ = other.manager_; |
| invoker_ = other.invoker_; |
| other.manager_ = EmptyManager; |
| other.invoker_ = nullptr; |
| } |
| |
| CoreImpl& operator=(CoreImpl&& other) noexcept { |
| // Put the left-hand operand in an empty state. |
| // |
| // Note: A full reset that leaves us with an object that has its invariants |
| // intact is necessary in order to handle self-move. This is required by |
| // types that are used with certain operations of the standard library, such |
| // as the default definition of std::swap when both operands target the same |
| // object. |
| Clear(); |
| |
| // Perform the actual move/destroy operation on the target function. |
| other.manager_(FunctionToCall::relocate_from_to, &other.state_, &state_); |
| manager_ = other.manager_; |
| invoker_ = other.invoker_; |
| other.manager_ = EmptyManager; |
| other.invoker_ = nullptr; |
| |
| return *this; |
| } |
| |
| ~CoreImpl() { manager_(FunctionToCall::dispose, &state_, &state_); } |
| |
| // Check whether or not the AnyInvocable is in the empty state. |
| bool HasValue() const { return invoker_ != nullptr; } |
| |
| // Effects: Puts the object into its empty state. |
| void Clear() { |
| manager_(FunctionToCall::dispose, &state_, &state_); |
| manager_ = EmptyManager; |
| invoker_ = nullptr; |
| } |
| |
| // Use local (inline) storage for applicable target object types. |
| template <class QualTRef, class... Args> |
| void InitializeStorage(Args&&... args) { |
| using RawT = RemoveCVRef<QualTRef>; |
| if constexpr (IsStoredLocally<RawT>()) { |
| ::new (static_cast<void*>(&state_.storage)) |
| RawT(std::forward<Args>(args)...); |
| invoker_ = LocalInvoker<SigIsNoexcept, ReturnType, QualTRef, P...>; |
| // We can simplify our manager if we know the type is trivially copyable. |
| if constexpr (std::is_trivially_copyable_v<RawT>) { |
| manager_ = LocalManagerTrivial; |
| } else { |
| manager_ = LocalManagerNontrivial<RawT>; |
| } |
| } else { |
| InitializeRemoteManager<RawT>(std::forward<Args>(args)...); |
| // This is set after everything else in case an exception is thrown in an |
| // earlier step of the initialization. |
| invoker_ = RemoteInvoker<SigIsNoexcept, ReturnType, QualTRef, P...>; |
| } |
| } |
| |
| template <class T, class... Args> |
| void InitializeRemoteManager(Args&&... args) { |
| if constexpr (std::is_trivially_destructible_v<T> && |
| alignof(T) <= ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT) { |
| // unique_ptr is used for exception-safety in case construction throws. |
| std::unique_ptr<void, TrivialDeleter> uninitialized_target( |
| ::operator new(sizeof(T)), TrivialDeleter(sizeof(T))); |
| ::new (uninitialized_target.get()) T(std::forward<Args>(args)...); |
| state_.remote.target = uninitialized_target.release(); |
| state_.remote.size = sizeof(T); |
| manager_ = RemoteManagerTrivial; |
| } else { |
| state_.remote.target = ::new T(std::forward<Args>(args)...); |
| manager_ = RemoteManagerNontrivial<T>; |
| } |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // Type trait to determine if the template argument is an AnyInvocable whose |
| // function type is compatible enough with ours such that we can |
| // "move the guts" out of it when moving, rather than having to place a new |
| // object into remote storage. |
| |
| template <typename Other> |
| struct IsCompatibleAnyInvocable { |
| static constexpr bool value = false; |
| }; |
| |
| template <typename Sig> |
| struct IsCompatibleAnyInvocable<AnyInvocable<Sig>> { |
| static constexpr bool value = |
| (IsCompatibleConversion)(static_cast< |
| typename AnyInvocable<Sig>::CoreImpl*>( |
| nullptr), |
| static_cast<CoreImpl*>(nullptr)); |
| }; |
| |
| // |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| TypeErasedState state_; |
| ManagerType* manager_; |
| InvokerType<SigIsNoexcept, ReturnType, P...>* invoker_; |
| }; |
| |
| // A constructor name-tag used with Impl to request the |
| // conversion-constructor |
| struct ConversionConstruct {}; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // A metafunction that is normally an identity metafunction except that when |
| // given a std::reference_wrapper<T>, it yields T&. This is necessary because |
| // currently std::reference_wrapper's operator() is not conditionally noexcept, |
| // so when checking if such an Invocable is nothrow-invocable, we must pull out |
| // the underlying type. |
| template <class T> |
| struct UnwrapStdReferenceWrapperImpl { |
| using type = T; |
| }; |
| |
| template <class T> |
| struct UnwrapStdReferenceWrapperImpl<std::reference_wrapper<T>> { |
| using type = T&; |
| }; |
| |
| template <class T> |
| using UnwrapStdReferenceWrapper = |
| typename UnwrapStdReferenceWrapperImpl<T>::type; |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // An alias that always yields std::true_type (used with constraints) where |
| // substitution failures happen when forming the template arguments. |
| template <class... T> |
| using TrueAlias = |
| std::integral_constant<bool, sizeof(absl::void_t<T...>*) != 0>; |
| |
| /*SFINAE constraints for the conversion-constructor.*/ |
| template <class Sig, class F, |
| class = absl::enable_if_t< |
| !std::is_same<RemoveCVRef<F>, AnyInvocable<Sig>>::value>> |
| using CanConvert = TrueAlias< |
| absl::enable_if_t<!IsInPlaceType<RemoveCVRef<F>>::value>, |
| absl::enable_if_t<Impl<Sig>::template CallIsValid<F>::value>, |
| absl::enable_if_t< |
| Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept<F>::value>, |
| absl::enable_if_t<std::is_constructible<absl::decay_t<F>, F>::value>>; |
| |
| /*SFINAE constraints for the std::in_place constructors.*/ |
| template <class Sig, class F, class... Args> |
| using CanEmplace = TrueAlias< |
| absl::enable_if_t<Impl<Sig>::template CallIsValid<F>::value>, |
| absl::enable_if_t< |
| Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept<F>::value>, |
| absl::enable_if_t<std::is_constructible<absl::decay_t<F>, Args...>::value>>; |
| |
| /*SFINAE constraints for the conversion-assign operator.*/ |
| template <class Sig, class F, |
| class = absl::enable_if_t< |
| !std::is_same<RemoveCVRef<F>, AnyInvocable<Sig>>::value>> |
| using CanAssign = TrueAlias< |
| absl::enable_if_t<Impl<Sig>::template CallIsValid<F>::value>, |
| absl::enable_if_t< |
| Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept<F>::value>, |
| absl::enable_if_t<std::is_constructible<absl::decay_t<F>, F>::value>>; |
| |
| /*SFINAE constraints for the reference-wrapper conversion-assign operator.*/ |
| template <class Sig, class F> |
| using CanAssignReferenceWrapper = TrueAlias< |
| absl::enable_if_t< |
| Impl<Sig>::template CallIsValid<std::reference_wrapper<F>>::value>, |
| absl::enable_if_t<Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept< |
| std::reference_wrapper<F>>::value>>; |
| |
| // The constraint for checking whether or not a call meets the noexcept |
| // callability requirements. We use a preprocessor macro because specifying it |
| // this way as opposed to a disjunction/branch can improve the user-side error |
| // messages and avoids an instantiation of std::is_nothrow_invocable_r in the |
| // cases where the user did not specify a noexcept function type. |
| // |
| // The disjunction below is because we can't rely on std::is_nothrow_invocable_r |
| // to give the right result when ReturnType is non-moveable in toolchains that |
| // don't treat non-moveable result types correctly. For example this was the |
| // case in libc++ before commit c3a24882 (2022-05). |
| #define ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_true(inv_quals) \ |
| absl::enable_if_t<absl::disjunction< \ |
| std::is_nothrow_invocable_r< \ |
| ReturnType, UnwrapStdReferenceWrapper<absl::decay_t<F>> inv_quals, \ |
| P...>, \ |
| std::conjunction< \ |
| std::is_nothrow_invocable< \ |
| UnwrapStdReferenceWrapper<absl::decay_t<F>> inv_quals, P...>, \ |
| std::is_same< \ |
| ReturnType, \ |
| std::invoke_result_t< \ |
| UnwrapStdReferenceWrapper<absl::decay_t<F>> inv_quals, \ |
| P...>>>>::value> |
| |
| #define ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_false(inv_quals) |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| // A macro to generate partial specializations of Impl with the different |
| // combinations of supported cv/reference qualifiers and noexcept specifier. |
| // |
| // Here, `cv` are the cv-qualifiers if any, `ref` is the ref-qualifier if any, |
| // inv_quals is the reference type to be used when invoking the target, and |
| // noex is "true" if the function type is noexcept, or false if it is not. |
| // |
| // The CallIsValid condition is more complicated than simply using |
| // std::is_invocable_r because we can't rely on it to give the right result |
| // when ReturnType is non-moveable in toolchains that don't treat non-moveable |
| // result types correctly. For example this was the case in libc++ before commit |
| // c3a24882 (2022-05). |
| #define ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, noex) \ |
| template <class ReturnType, class... P> \ |
| class Impl<ReturnType(P...) cv ref noexcept(noex)> \ |
| : public CoreImpl<noex, ReturnType, P...> { \ |
| public: \ |
| /*The base class, which contains the datamembers and core operations*/ \ |
| using Core = CoreImpl<noex, ReturnType, P...>; \ |
| \ |
| /*SFINAE constraint to check if F is invocable with the proper signature*/ \ |
| template <class F> \ |
| using CallIsValid = TrueAlias<absl::enable_if_t<absl::disjunction< \ |
| std::is_invocable_r<ReturnType, absl::decay_t<F> inv_quals, P...>, \ |
| std::is_same< \ |
| ReturnType, \ |
| std::invoke_result_t<absl::decay_t<F> inv_quals, P...>>>::value>>; \ |
| \ |
| /*SFINAE constraint to check if F is nothrow-invocable when necessary*/ \ |
| template <class F> \ |
| using CallIsNoexceptIfSigIsNoexcept = \ |
| TrueAlias<ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_##noex( \ |
| inv_quals)>; \ |
| \ |
| /*Put the AnyInvocable into an empty state.*/ \ |
| Impl() = default; \ |
| \ |
| /*The implementation of a conversion-constructor from "f*/ \ |
| /*This forwards to Core, attaching inv_quals so that the base class*/ \ |
| /*knows how to properly type-erase the invocation.*/ \ |
| template <class F> \ |
| explicit Impl(ConversionConstruct, F&& f) \ |
| : Core(TypedConversionConstruct< \ |
| typename std::decay<F>::type inv_quals>(), \ |
| std::forward<F>(f)) {} \ |
| \ |
| /*Forward along the in-place construction parameters.*/ \ |
| template <class T, class... Args> \ |
| explicit Impl(absl::in_place_type_t<T>, Args&&... args) \ |
| : Core(absl::in_place_type<absl::decay_t<T> inv_quals>, \ |
| std::forward<Args>(args)...) {} \ |
| \ |
| /*Raises a fatal error when the AnyInvocable is invoked after a move*/ \ |
| static ReturnType InvokedAfterMove( \ |
| TypeErasedState*, ForwardedParameterType<P>...) noexcept(noex) { \ |
| ABSL_HARDENING_ASSERT(false && "AnyInvocable use-after-move"); \ |
| std::terminate(); \ |
| } \ |
| \ |
| InvokerType<noex, ReturnType, P...>* ExtractInvoker() cv { \ |
| using QualifiedTestType = int cv ref; \ |
| auto* invoker = this->invoker_; \ |
| if (!std::is_const<QualifiedTestType>::value && \ |
| std::is_rvalue_reference<QualifiedTestType>::value) { \ |
| ABSL_ASSERT([this]() { \ |
| /* We checked that this isn't const above, so const_cast is safe */ \ |
| const_cast<Impl*>(this)->invoker_ = InvokedAfterMove; \ |
| return this->HasValue(); \ |
| }()); \ |
| } \ |
| return invoker; \ |
| } \ |
| \ |
| /*The actual invocation operation with the proper signature*/ \ |
| ReturnType operator()(P... args) cv ref noexcept(noex) { \ |
| assert(this->invoker_ != nullptr); \ |
| return this->ExtractInvoker()( \ |
| const_cast<TypeErasedState*>(&this->state_), \ |
| static_cast<ForwardedParameterType<P>>(args)...); \ |
| } \ |
| } |
| |
| // A convenience macro that defines specializations for the noexcept(true) and |
| // noexcept(false) forms, given the other properties. |
| #define ABSL_INTERNAL_ANY_INVOCABLE_IMPL(cv, ref, inv_quals) \ |
| ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, false); \ |
| ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, true) |
| |
| // Non-ref-qualified partial specializations |
| ABSL_INTERNAL_ANY_INVOCABLE_IMPL(, , &); |
| ABSL_INTERNAL_ANY_INVOCABLE_IMPL(const, , const&); |
| |
| // Lvalue-ref-qualified partial specializations |
| ABSL_INTERNAL_ANY_INVOCABLE_IMPL(, &, &); |
| ABSL_INTERNAL_ANY_INVOCABLE_IMPL(const, &, const&); |
| |
| // Rvalue-ref-qualified partial specializations |
| ABSL_INTERNAL_ANY_INVOCABLE_IMPL(, &&, &&); |
| ABSL_INTERNAL_ANY_INVOCABLE_IMPL(const, &&, const&&); |
| |
| // Undef the detail-only macros. |
| #undef ABSL_INTERNAL_ANY_INVOCABLE_IMPL |
| #undef ABSL_INTERNAL_ANY_INVOCABLE_IMPL_ |
| #undef ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_false |
| #undef ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_true |
| |
| } // namespace internal_any_invocable |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_FUNCTIONAL_INTERNAL_ANY_INVOCABLE_H_ |
| *f |
| ~soong/.intermediates/external/abseil-cpp/absl_functional_any_invocable_hdrs/gen/my_include_dir/absl/functional/any_invocable.he// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: any_invocable.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines an `absl::AnyInvocable` type that assumes ownership |
| // and wraps an object of an invocable type. (Invocable types adhere to the |
| // concept specified in https://en.cppreference.com/w/cpp/concepts/invocable.) |
| // |
| // In general, prefer `absl::AnyInvocable` when you need a type-erased |
| // function parameter that needs to take ownership of the type. |
| // |
| // NOTE: `absl::AnyInvocable` is similar to the C++23 `std::move_only_function` |
| // abstraction, but has a slightly different API and is not designed to be a |
| // drop-in replacement or backfill of that type. |
| // |
| // Credits to Matt Calabrese (https://github.com/mattcalabrese) for the original |
| // implementation. |
| |
| #ifndef ABSL_FUNCTIONAL_ANY_INVOCABLE_H_ |
| #define ABSL_FUNCTIONAL_ANY_INVOCABLE_H_ |
| |
| #include <cstddef> |
| #include <functional> |
| #include <initializer_list> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/config.h" |
| #include "absl/functional/internal/any_invocable.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/utility/utility.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // absl::AnyInvocable |
| // |
| // `absl::AnyInvocable` is a functional wrapper type, like `std::function`, that |
| // assumes ownership of an invocable object. Unlike `std::function`, an |
| // `absl::AnyInvocable` is more type-safe and provides the following additional |
| // benefits: |
| // |
| // * Properly adheres to const correctness of the underlying type |
| // * Is move-only so avoids concurrency problems with copied invocables and |
| // unnecessary copies in general. |
| // * Supports reference qualifiers allowing it to perform unique actions (noted |
| // below). |
| // |
| // `absl::AnyInvocable` is a template, and an `absl::AnyInvocable` instantiation |
| // may wrap any invocable object with a compatible function signature, e.g. |
| // having arguments and return types convertible to types matching the |
| // `absl::AnyInvocable` signature, and also matching any stated reference |
| // qualifiers, as long as that type is moveable. It therefore provides broad |
| // type erasure for functional objects. |
| // |
| // An `absl::AnyInvocable` is typically used as a type-erased function parameter |
| // for accepting various functional objects: |
| // |
| // // Define a function taking an AnyInvocable parameter. |
| // void my_func(absl::AnyInvocable<int()> f) { |
| // ... |
| // }; |
| // |
| // // That function can accept any invocable type: |
| // |
| // // Accept a function reference. We don't need to move a reference. |
| // int func1() { return 0; }; |
| // my_func(func1); |
| // |
| // // Accept a lambda. We use std::move here because otherwise my_func would |
| // // copy the lambda. |
| // auto lambda = []() { return 0; }; |
| // my_func(std::move(lambda)); |
| // |
| // // Accept a function pointer. We don't need to move a function pointer. |
| // func2 = &func1; |
| // my_func(func2); |
| // |
| // // Accept an std::function by moving it. Note that the lambda is copyable |
| // // (satisfying std::function requirements) and moveable (satisfying |
| // // absl::AnyInvocable requirements). |
| // std::function<int()> func6 = []() { return 0; }; |
| // my_func(std::move(func6)); |
| // |
| // `AnyInvocable` also properly respects `const` qualifiers, reference |
| // qualifiers, and the `noexcept` specification as part of the user-specified |
| // function type (e.g. `AnyInvocable<void() const && noexcept>`). These |
| // qualifiers will be applied to the `AnyInvocable` object's `operator()`, and |
| // the underlying invocable must be compatible with those qualifiers. |
| // |
| // Comparison of const and non-const function types: |
| // |
| // // Store a closure inside of `func` with the function type `int()`. |
| // // Note that we have made `func` itself `const`. |
| // const AnyInvocable<int()> func = [](){ return 0; }; |
| // |
| // func(); // Compile-error: the passed type `int()` isn't `const`. |
| // |
| // // Store a closure inside of `const_func` with the function type |
| // // `int() const`. |
| // // Note that we have also made `const_func` itself `const`. |
| // const AnyInvocable<int() const> const_func = [](){ return 0; }; |
| // |
| // const_func(); // Fine: `int() const` is `const`. |
| // |
| // In the above example, the call `func()` would have compiled if |
| // `std::function` were used even though the types are not const compatible. |
| // This is a bug, and using `absl::AnyInvocable` properly detects that bug. |
| // |
| // In addition to affecting the signature of `operator()`, the `const` and |
| // reference qualifiers of the function type also appropriately constrain which |
| // kinds of invocable objects you are allowed to place into the `AnyInvocable` |
| // instance. If you specify a function type that is const-qualified, then |
| // anything that you attempt to put into the `AnyInvocable` must be callable on |
| // a `const` instance of that type. |
| // |
| // Constraint example: |
| // |
| // // Fine because the lambda is callable when `const`. |
| // AnyInvocable<int() const> func = [=](){ return 0; }; |
| // |
| // // This is a compile-error because the lambda isn't callable when `const`. |
| // AnyInvocable<int() const> error = [=]() mutable { return 0; }; |
| // |
| // An `&&` qualifier can be used to express that an `absl::AnyInvocable` |
| // instance should be invoked at most once: |
| // |
| // // Invokes `continuation` with the logical result of an operation when |
| // // that operation completes (common in asynchronous code). |
| // void CallOnCompletion(AnyInvocable<void(int)&&> continuation) { |
| // int result_of_foo = foo(); |
| // |
| // // `std::move` is required because the `operator()` of `continuation` is |
| // // rvalue-reference qualified. |
| // std::move(continuation)(result_of_foo); |
| // } |
| // |
| // Attempting to call `absl::AnyInvocable` multiple times in such a case |
| // results in undefined behavior. |
| // |
| // Invoking an empty `absl::AnyInvocable` results in undefined behavior: |
| // |
| // // Create an empty instance using the default constructor. |
| // AnyInvocable<void()> empty; |
| // empty(); // WARNING: Undefined behavior! |
| template <class Sig> |
| class AnyInvocable : private internal_any_invocable::Impl<Sig> { |
| private: |
| static_assert( |
| std::is_function<Sig>::value, |
| "The template argument of AnyInvocable must be a function type."); |
| |
| using Impl = internal_any_invocable::Impl<Sig>; |
| |
| public: |
| // The return type of Sig |
| using result_type = typename Impl::result_type; |
| |
| // Constructors |
| |
| // Constructs the `AnyInvocable` in an empty state. |
| // Invoking it results in undefined behavior. |
| AnyInvocable() noexcept = default; |
| AnyInvocable(std::nullptr_t) noexcept {} // NOLINT |
| |
| // Constructs the `AnyInvocable` from an existing `AnyInvocable` by a move. |
| // Note that `f` is not guaranteed to be empty after move-construction, |
| // although it may be. |
| AnyInvocable(AnyInvocable&& /*f*/) noexcept = default; |
| |
| // Constructs an `AnyInvocable` from an invocable object. |
| // |
| // Upon construction, `*this` is only empty if `f` is a function pointer or |
| // member pointer type and is null, or if `f` is an `AnyInvocable` that is |
| // empty. |
| template <class F, typename = absl::enable_if_t< |
| internal_any_invocable::CanConvert<Sig, F>::value>> |
| AnyInvocable(F&& f) // NOLINT |
| : Impl(internal_any_invocable::ConversionConstruct(), |
| std::forward<F>(f)) {} |
| |
| // Constructs an `AnyInvocable` that holds an invocable object of type `T`, |
| // which is constructed in-place from the given arguments. |
| // |
| // Example: |
| // |
| // AnyInvocable<int(int)> func( |
| // absl::in_place_type<PossiblyImmovableType>, arg1, arg2); |
| // |
| template <class T, class... Args, |
| typename = absl::enable_if_t< |
| internal_any_invocable::CanEmplace<Sig, T, Args...>::value>> |
| explicit AnyInvocable(absl::in_place_type_t<T>, Args&&... args) |
| : Impl(absl::in_place_type<absl::decay_t<T>>, |
| std::forward<Args>(args)...) { |
| static_assert(std::is_same<T, absl::decay_t<T>>::value, |
| "The explicit template argument of in_place_type is required " |
| "to be an unqualified object type."); |
| } |
| |
| // Overload of the above constructor to support list-initialization. |
| template <class T, class U, class... Args, |
| typename = absl::enable_if_t<internal_any_invocable::CanEmplace< |
| Sig, T, std::initializer_list<U>&, Args...>::value>> |
| explicit AnyInvocable(absl::in_place_type_t<T>, |
| std::initializer_list<U> ilist, Args&&... args) |
| : Impl(absl::in_place_type<absl::decay_t<T>>, ilist, |
| std::forward<Args>(args)...) { |
| static_assert(std::is_same<T, absl::decay_t<T>>::value, |
| "The explicit template argument of in_place_type is required " |
| "to be an unqualified object type."); |
| } |
| |
| // Assignment Operators |
| |
| // Assigns an `AnyInvocable` through move-assignment. |
| // Note that `f` is not guaranteed to be empty after move-assignment |
| // although it may be. |
| AnyInvocable& operator=(AnyInvocable&& /*f*/) noexcept = default; |
| |
| // Assigns an `AnyInvocable` from a nullptr, clearing the `AnyInvocable`. If |
| // not empty, destroys the target, putting `*this` into an empty state. |
| AnyInvocable& operator=(std::nullptr_t) noexcept { |
| this->Clear(); |
| return *this; |
| } |
| |
| // Assigns an `AnyInvocable` from an existing `AnyInvocable` instance. |
| // |
| // Upon assignment, `*this` is only empty if `f` is a function pointer or |
| // member pointer type and is null, or if `f` is an `AnyInvocable` that is |
| // empty. |
| template <class F, typename = absl::enable_if_t< |
| internal_any_invocable::CanAssign<Sig, F>::value>> |
| AnyInvocable& operator=(F&& f) { |
| *this = AnyInvocable(std::forward<F>(f)); |
| return *this; |
| } |
| |
| // Assigns an `AnyInvocable` from a reference to an invocable object. |
| // Upon assignment, stores a reference to the invocable object in the |
| // `AnyInvocable` instance. |
| template < |
| class F, |
| typename = absl::enable_if_t< |
| internal_any_invocable::CanAssignReferenceWrapper<Sig, F>::value>> |
| AnyInvocable& operator=(std::reference_wrapper<F> f) noexcept { |
| *this = AnyInvocable(f); |
| return *this; |
| } |
| |
| // Destructor |
| |
| // If not empty, destroys the target. |
| ~AnyInvocable() = default; |
| |
| // absl::AnyInvocable::swap() |
| // |
| // Exchanges the targets of `*this` and `other`. |
| void swap(AnyInvocable& other) noexcept { std::swap(*this, other); } |
| |
| // absl::AnyInvocable::operator bool() |
| // |
| // Returns `true` if `*this` is not empty. |
| // |
| // WARNING: An `AnyInvocable` that wraps an empty `std::function` is not |
| // itself empty. This behavior is consistent with the standard equivalent |
| // `std::move_only_function`. In the following example, `a()` will actually |
| // invoke `f()`, leading to an `std::bad_function_call` exception: |
| // std::function<void()> f; // empty |
| // absl::AnyInvocable<void()> a = f; // not empty |
| // |
| // Invoking an empty `AnyInvocable` results in undefined behavior. |
| explicit operator bool() const noexcept { return this->HasValue(); } |
| |
| // Invokes the target object of `*this`. `*this` must not be empty. |
| // |
| // Note: The signature of this function call operator is the same as the |
| // template parameter `Sig`. |
| using Impl::operator(); |
| |
| // Equality operators |
| |
| // Returns `true` if `*this` is empty. |
| friend bool operator==(const AnyInvocable& f, std::nullptr_t) noexcept { |
| return !f.HasValue(); |
| } |
| |
| // Returns `true` if `*this` is empty. |
| friend bool operator==(std::nullptr_t, const AnyInvocable& f) noexcept { |
| return !f.HasValue(); |
| } |
| |
| // Returns `false` if `*this` is empty. |
| friend bool operator!=(const AnyInvocable& f, std::nullptr_t) noexcept { |
| return f.HasValue(); |
| } |
| |
| // Returns `false` if `*this` is empty. |
| friend bool operator!=(std::nullptr_t, const AnyInvocable& f) noexcept { |
| return f.HasValue(); |
| } |
| |
| // swap() |
| // |
| // Exchanges the targets of `f1` and `f2`. |
| friend void swap(AnyInvocable& f1, AnyInvocable& f2) noexcept { f1.swap(f2); } |
| |
| private: |
| // Friending other instantiations is necessary for conversions. |
| template <bool /*SigIsNoexcept*/, class /*ReturnType*/, class... /*P*/> |
| friend class internal_any_invocable::CoreImpl; |
| }; |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_FUNCTIONAL_ANY_INVOCABLE_H_ |
| *¡ |
|
soong/.intermediates/external/abseil-cpp/absl_functional_function_ref_hdrs/gen/my_include_dir/absl/functional/internal/function_ref.h// Copyright 2019 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_ |
| #define ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_ |
| |
| #include <cassert> |
| #include <functional> |
| #include <type_traits> |
| |
| #include "absl/functional/any_invocable.h" |
| #include "absl/meta/type_traits.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace functional_internal { |
| |
| // Like a void* that can handle function pointers as well. The standard does not |
| // allow function pointers to round-trip through void*, but void(*)() is fine. |
| // |
| // Note: It's important that this class remains trivial and is the same size as |
| // a pointer, since this allows the compiler to perform tail-call optimizations |
| // when the underlying function is a callable object with a matching signature. |
| union VoidPtr { |
| const void* obj; |
| void (*fun)(); |
| }; |
| |
| // Chooses the best type for passing T as an argument. |
| // Attempt to be close to SystemV AMD64 ABI. Objects with trivial copy ctor are |
| // passed by value. |
| template <typename T, |
| bool IsLValueReference = std::is_lvalue_reference<T>::value> |
| struct PassByValue : std::false_type {}; |
| |
| template <typename T> |
| struct PassByValue<T, /*IsLValueReference=*/false> |
| : std::integral_constant<bool, |
| absl::is_trivially_copy_constructible<T>::value && |
| absl::is_trivially_copy_assignable< |
| typename std::remove_cv<T>::type>::value && |
| std::is_trivially_destructible<T>::value && |
| sizeof(T) <= 2 * sizeof(void*)> {}; |
| |
| template <typename T> |
| struct ForwardT : std::conditional<PassByValue<T>::value, T, T&&> {}; |
| |
| // An Invoker takes a pointer to the type-erased invokable object, followed by |
| // the arguments that the invokable object expects. |
| // |
| // Note: The order of arguments here is an optimization, since member functions |
| // have an implicit "this" pointer as their first argument, putting VoidPtr |
| // first allows the compiler to perform tail-call optimization in many cases. |
| template <typename R, typename... Args> |
| using Invoker = R (*)(VoidPtr, typename ForwardT<Args>::type...); |
| |
| // |
| // InvokeObject and InvokeFunction provide static "Invoke" functions that can be |
| // used as Invokers for objects or functions respectively. |
| // |
| // static_cast<R> handles the case the return type is void. |
| template <typename Obj, typename R, typename... Args> |
| R InvokeObject(VoidPtr ptr, typename ForwardT<Args>::type... args) { |
| auto o = static_cast<const Obj*>(ptr.obj); |
| return static_cast<R>(std::invoke(*o, std::forward<Args>(args)...)); |
| } |
| |
| template <typename Fun, typename R, typename... Args> |
| R InvokeFunction(VoidPtr ptr, typename ForwardT<Args>::type... args) { |
| auto f = reinterpret_cast<Fun>(ptr.fun); |
| return static_cast<R>(std::invoke(f, std::forward<Args>(args)...)); |
| } |
| |
| template <typename Sig> |
| void AssertNonNull(const std::function<Sig>& f) { |
| assert(f != nullptr); |
| (void)f; |
| } |
| |
| template <typename Sig> |
| void AssertNonNull(const AnyInvocable<Sig>& f) { |
| assert(f != nullptr); |
| (void)f; |
| } |
| |
| template <typename F> |
| void AssertNonNull(const F&) {} |
| |
| template <typename F, typename C> |
| void AssertNonNull(F C::*f) { |
| assert(f != nullptr); |
| (void)f; |
| } |
| |
| template <bool C> |
| using EnableIf = typename ::std::enable_if<C, int>::type; |
| |
| } // namespace functional_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_ |
| *Ù- |
| |soong/.intermediates/external/abseil-cpp/absl_functional_function_ref_hdrs/gen/my_include_dir/absl/functional/function_ref.hØ,// 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: function_ref.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines the `absl::FunctionRef` type for holding a |
| // non-owning reference to an object of any invocable type. This function |
| // reference is typically most useful as a type-erased argument type for |
| // accepting function types that neither take ownership nor copy the type; using |
| // the reference type in this case avoids a copy and an allocation. Best |
| // practices of other non-owning reference-like objects (such as |
| // `absl::string_view`) apply here. |
| // |
| // An `absl::FunctionRef` is similar in usage to a `std::function` but has the |
| // following differences: |
| // |
| // * It doesn't own the underlying object. |
| // * It doesn't have a null or empty state. |
| // * It never performs deep copies or allocations. |
| // * It's much faster and cheaper to construct. |
| // * It's trivially copyable and destructable. |
| // |
| // Generally, `absl::FunctionRef` should not be used as a return value, data |
| // member, or to initialize a `std::function`. Such usages will often lead to |
| // problematic lifetime issues. Once you convert something to an |
| // `absl::FunctionRef` you cannot make a deep copy later. |
| // |
| // This class is suitable for use wherever a "const std::function<>&" |
| // would be used without making a copy. ForEach functions and other versions of |
| // the visitor pattern are a good example of when this class should be used. |
| // |
| // This class is trivial to copy and should be passed by value. |
| #ifndef ABSL_FUNCTIONAL_FUNCTION_REF_H_ |
| #define ABSL_FUNCTIONAL_FUNCTION_REF_H_ |
| |
| #include <cassert> |
| #include <functional> |
| #include <type_traits> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/functional/internal/function_ref.h" |
| #include "absl/meta/type_traits.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // FunctionRef |
| // |
| // Dummy class declaration to allow the partial specialization based on function |
| // types below. |
| template <typename T> |
| class FunctionRef; |
| |
| // FunctionRef |
| // |
| // An `absl::FunctionRef` is a lightweight wrapper to any invocable object with |
| // a compatible signature. Generally, an `absl::FunctionRef` should only be used |
| // as an argument type and should be preferred as an argument over a const |
| // reference to a `std::function`. `absl::FunctionRef` itself does not allocate, |
| // although the wrapped invocable may. |
| // |
| // Example: |
| // |
| // // The following function takes a function callback by const reference |
| // bool Visitor(const std::function<void(my_proto&, |
| // absl::string_view)>& callback); |
| // |
| // // Assuming that the function is not stored or otherwise copied, it can be |
| // // replaced by an `absl::FunctionRef`: |
| // bool Visitor(absl::FunctionRef<void(my_proto&, absl::string_view)> |
| // callback); |
| template <typename R, typename... Args> |
| class FunctionRef<R(Args...)> { |
| private: |
| // Used to disable constructors for objects that are not compatible with the |
| // signature of this FunctionRef. |
| template <typename F, typename FR = std::invoke_result_t<F, Args&&...>> |
| using EnableIfCompatible = |
| typename std::enable_if<std::is_void<R>::value || |
| std::is_convertible<FR, R>::value>::type; |
| |
| public: |
| // Constructs a FunctionRef from any invocable type. |
| template <typename F, typename = EnableIfCompatible<const F&>> |
| // NOLINTNEXTLINE(runtime/explicit) |
| FunctionRef(const F& f ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| : invoker_(&absl::functional_internal::InvokeObject<F, R, Args...>) { |
| absl::functional_internal::AssertNonNull(f); |
| ptr_.obj = &f; |
| } |
| |
| // Overload for function pointers. This eliminates a level of indirection that |
| // would happen if the above overload was used (it lets us store the pointer |
| // instead of a pointer to a pointer). |
| // |
| // This overload is also used for references to functions, since references to |
| // functions can decay to function pointers implicitly. |
| template < |
| typename F, typename = EnableIfCompatible<F*>, |
| absl::functional_internal::EnableIf<absl::is_function<F>::value> = 0> |
| FunctionRef(F* f) // NOLINT(runtime/explicit) |
| : invoker_(&absl::functional_internal::InvokeFunction<F*, R, Args...>) { |
| assert(f != nullptr); |
| ptr_.fun = reinterpret_cast<decltype(ptr_.fun)>(f); |
| } |
| |
| FunctionRef& operator=(const FunctionRef& rhs) = default; |
| FunctionRef(const FunctionRef& rhs) = default; |
| |
| // Call the underlying object. |
| R operator()(Args... args) const { |
| return invoker_(ptr_, std::forward<Args>(args)...); |
| } |
| |
| private: |
| absl::functional_internal::VoidPtr ptr_; |
| absl::functional_internal::Invoker<R, Args...> invoker_; |
| }; |
| |
| // Allow const qualified function signatures. Since FunctionRef requires |
| // constness anyway we can just make this a no-op. |
| template <typename R, typename... Args> |
| class FunctionRef<R(Args...) const> : public FunctionRef<R(Args...)> { |
| public: |
| using FunctionRef<R(Args...)>::FunctionRef; |
| }; |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_FUNCTIONAL_FUNCTION_REF_H_ |
| *Ú |
| nsoong/.intermediates/external/abseil-cpp/absl_base_core_headers_hdrs/gen/my_include_dir/absl/base/const_init.hç// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // kConstInit |
| // ----------------------------------------------------------------------------- |
| // |
| // A constructor tag used to mark an object as safe for use as a global |
| // variable, avoiding the usual lifetime issues that can affect globals. |
| |
| #ifndef ABSL_BASE_CONST_INIT_H_ |
| #define ABSL_BASE_CONST_INIT_H_ |
| |
| #include "absl/base/config.h" |
| |
| // In general, objects with static storage duration (such as global variables) |
| // can trigger tricky object lifetime situations. Attempting to access them |
| // from the constructors or destructors of other global objects can result in |
| // undefined behavior, unless their constructors and destructors are designed |
| // with this issue in mind. |
| // |
| // The normal way to deal with this issue in C++11 is to use constant |
| // initialization and trivial destructors. |
| // |
| // Constant initialization is guaranteed to occur before any other code |
| // executes. Constructors that are declared 'constexpr' are eligible for |
| // constant initialization. You can annotate a variable declaration with the |
| // ABSL_CONST_INIT macro to express this intent. For compilers that support |
| // it, this annotation will cause a compilation error for declarations that |
| // aren't subject to constant initialization (perhaps because a runtime value |
| // was passed as a constructor argument). |
| // |
| // On program shutdown, lifetime issues can be avoided on global objects by |
| // ensuring that they contain trivial destructors. A class has a trivial |
| // destructor unless it has a user-defined destructor, a virtual method or base |
| // class, or a data member or base class with a non-trivial destructor of its |
| // own. Objects with static storage duration and a trivial destructor are not |
| // cleaned up on program shutdown, and are thus safe to access from other code |
| // running during shutdown. |
| // |
| // For a few core Abseil classes, we make a best effort to allow for safe global |
| // instances, even though these classes have non-trivial destructors. These |
| // objects can be created with the absl::kConstInit tag. For example: |
| // ABSL_CONST_INIT absl::Mutex global_mutex(absl::kConstInit); |
| // |
| // The line above declares a global variable of type absl::Mutex which can be |
| // accessed at any point during startup or shutdown. global_mutex's destructor |
| // will still run, but will not invalidate the object. Note that C++ specifies |
| // that accessing an object after its destructor has run results in undefined |
| // behavior, but this pattern works on the toolchains we support. |
| // |
| // The absl::kConstInit tag should only be used to define objects with static |
| // or thread_local storage duration. |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| enum ConstInitType { |
| kConstInit, |
| }; |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_CONST_INIT_H_ |
| *¢Y |
| asoong/.intermediates/external/abseil-cpp/absl_memory_hdrs/gen/my_include_dir/absl/memory/memory.h¼X// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: memory.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file contains utility functions for managing the creation and |
| // conversion of smart pointers. This file is an extension to the C++ |
| // standard <memory> library header file. |
| |
| #ifndef ABSL_MEMORY_MEMORY_H_ |
| #define ABSL_MEMORY_MEMORY_H_ |
| |
| #include <cstddef> |
| #include <limits> |
| #include <memory> |
| #include <new> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/macros.h" |
| #include "absl/meta/type_traits.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // ----------------------------------------------------------------------------- |
| // Function Template: WrapUnique() |
| // ----------------------------------------------------------------------------- |
| // |
| // Adopts ownership from a raw pointer and transfers it to the returned |
| // `std::unique_ptr`, whose type is deduced. Because of this deduction, *do not* |
| // specify the template type `T` when calling `WrapUnique`. |
| // |
| // Example: |
| // X* NewX(int, int); |
| // auto x = WrapUnique(NewX(1, 2)); // 'x' is std::unique_ptr<X>. |
| // |
| // Do not call WrapUnique with an explicit type, as in |
| // `WrapUnique<X>(NewX(1, 2))`. The purpose of WrapUnique is to automatically |
| // deduce the pointer type. If you wish to make the type explicit, just use |
| // `std::unique_ptr` directly. |
| // |
| // auto x = std::unique_ptr<X>(NewX(1, 2)); |
| // - or - |
| // std::unique_ptr<X> x(NewX(1, 2)); |
| // |
| // While `absl::WrapUnique` is useful for capturing the output of a raw |
| // pointer factory, prefer 'absl::make_unique<T>(args...)' over |
| // 'absl::WrapUnique(new T(args...))'. |
| // |
| // auto x = WrapUnique(new X(1, 2)); // works, but nonideal. |
| // auto x = make_unique<X>(1, 2); // safer, standard, avoids raw 'new'. |
| // |
| // Note that `absl::WrapUnique(p)` is valid only if `delete p` is a valid |
| // expression. In particular, `absl::WrapUnique()` cannot wrap pointers to |
| // arrays, functions or void, and it must not be used to capture pointers |
| // obtained from array-new expressions (even though that would compile!). |
| template <typename T> |
| std::unique_ptr<T> WrapUnique(T* ptr) { |
| static_assert(!std::is_array<T>::value, "array types are unsupported"); |
| static_assert(std::is_object<T>::value, "non-object types are unsupported"); |
| return std::unique_ptr<T>(ptr); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| // Function Template: make_unique<T>() |
| // ----------------------------------------------------------------------------- |
| // |
| // Creates a `std::unique_ptr<>`, while avoiding issues creating temporaries |
| // during the construction process. `absl::make_unique<>` also avoids redundant |
| // type declarations, by avoiding the need to explicitly use the `new` operator. |
| // |
| // https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique |
| // |
| // For more background on why `std::unique_ptr<T>(new T(a,b))` is problematic, |
| // see Herb Sutter's explanation on |
| // (Exception-Safe Function Calls)[https://herbsutter.com/gotw/_102/]. |
| // (In general, reviewers should treat `new T(a,b)` with scrutiny.) |
| // |
| // Historical note: Abseil once provided a C++11 compatible implementation of |
| // the C++14's `std::make_unique`. Now that C++11 support has been sunsetted, |
| // `absl::make_unique` simply uses the STL-provided implementation. New code |
| // should use `std::make_unique`. |
| using std::make_unique; |
| |
| // ----------------------------------------------------------------------------- |
| // Function Template: RawPtr() |
| // ----------------------------------------------------------------------------- |
| // |
| // Extracts the raw pointer from a pointer-like value `ptr`. `absl::RawPtr` is |
| // useful within templates that need to handle a complement of raw pointers, |
| // `std::nullptr_t`, and smart pointers. |
| template <typename T> |
| auto RawPtr(T&& ptr) -> decltype(std::addressof(*ptr)) { |
| // ptr is a forwarding reference to support Ts with non-const operators. |
| return (ptr != nullptr) ? std::addressof(*ptr) : nullptr; |
| } |
| inline std::nullptr_t RawPtr(std::nullptr_t) { return nullptr; } |
| |
| // ----------------------------------------------------------------------------- |
| // Function Template: ShareUniquePtr() |
| // ----------------------------------------------------------------------------- |
| // |
| // Adopts a `std::unique_ptr` rvalue and returns a `std::shared_ptr` of deduced |
| // type. Ownership (if any) of the held value is transferred to the returned |
| // shared pointer. |
| // |
| // Example: |
| // |
| // auto up = absl::make_unique<int>(10); |
| // auto sp = absl::ShareUniquePtr(std::move(up)); // shared_ptr<int> |
| // CHECK_EQ(*sp, 10); |
| // CHECK(up == nullptr); |
| // |
| // Note that this conversion is correct even when T is an array type, and more |
| // generally it works for *any* deleter of the `unique_ptr` (single-object |
| // deleter, array deleter, or any custom deleter), since the deleter is adopted |
| // by the shared pointer as well. The deleter is copied (unless it is a |
| // reference). |
| // |
| // Implements the resolution of [LWG 2415](http://wg21.link/lwg2415), by which a |
| // null shared pointer does not attempt to call the deleter. |
| template <typename T, typename D> |
| std::shared_ptr<T> ShareUniquePtr(std::unique_ptr<T, D>&& ptr) { |
| return ptr ? std::shared_ptr<T>(std::move(ptr)) : std::shared_ptr<T>(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| // Function Template: WeakenPtr() |
| // ----------------------------------------------------------------------------- |
| // |
| // Creates a weak pointer associated with a given shared pointer. The returned |
| // value is a `std::weak_ptr` of deduced type. |
| // |
| // Example: |
| // |
| // auto sp = std::make_shared<int>(10); |
| // auto wp = absl::WeakenPtr(sp); |
| // CHECK_EQ(sp.get(), wp.lock().get()); |
| // sp.reset(); |
| // CHECK(wp.lock() == nullptr); |
| // |
| template <typename T> |
| std::weak_ptr<T> WeakenPtr(const std::shared_ptr<T>& ptr) { |
| return std::weak_ptr<T>(ptr); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| // Class Template: pointer_traits |
| // ----------------------------------------------------------------------------- |
| // |
| // Historical note: Abseil once provided an implementation of |
| // `std::pointer_traits` for platforms that had not yet provided it. Those |
| // platforms are no longer supported. New code should simply use |
| // `std::pointer_traits`. |
| using std::pointer_traits; |
| |
| // ----------------------------------------------------------------------------- |
| // Class Template: allocator_traits |
| // ----------------------------------------------------------------------------- |
| // |
| // Historical note: Abseil once provided an implementation of |
| // `std::allocator_traits` for platforms that had not yet provided it. Those |
| // platforms are no longer supported. New code should simply use |
| // `std::allocator_traits`. |
| using std::allocator_traits; |
| |
| namespace memory_internal { |
| |
| // ExtractOr<E, O, D>::type evaluates to E<O> if possible. Otherwise, D. |
| template <template <typename> class Extract, typename Obj, typename Default, |
| typename> |
| struct ExtractOr { |
| using type = Default; |
| }; |
| |
| template <template <typename> class Extract, typename Obj, typename Default> |
| struct ExtractOr<Extract, Obj, Default, void_t<Extract<Obj>>> { |
| using type = Extract<Obj>; |
| }; |
| |
| template <template <typename> class Extract, typename Obj, typename Default> |
| using ExtractOrT = typename ExtractOr<Extract, Obj, Default, void>::type; |
| |
| // This template alias transforms Alloc::is_nothrow into a metafunction with |
| // Alloc as a parameter so it can be used with ExtractOrT<>. |
| template <typename Alloc> |
| using GetIsNothrow = typename Alloc::is_nothrow; |
| |
| } // namespace memory_internal |
| |
| // ABSL_ALLOCATOR_NOTHROW is a build time configuration macro for user to |
| // specify whether the default allocation function can throw or never throws. |
| // If the allocation function never throws, user should define it to a non-zero |
| // value (e.g. via `-DABSL_ALLOCATOR_NOTHROW`). |
| // If the allocation function can throw, user should leave it undefined or |
| // define it to zero. |
| // |
| // allocator_is_nothrow<Alloc> is a traits class that derives from |
| // Alloc::is_nothrow if present, otherwise std::false_type. It's specialized |
| // for Alloc = std::allocator<T> for any type T according to the state of |
| // ABSL_ALLOCATOR_NOTHROW. |
| // |
| // default_allocator_is_nothrow is a class that derives from std::true_type |
| // when the default allocator (global operator new) never throws, and |
| // std::false_type when it can throw. It is a convenience shorthand for writing |
| // allocator_is_nothrow<std::allocator<T>> (T can be any type). |
| // NOTE: allocator_is_nothrow<std::allocator<T>> is guaranteed to derive from |
| // the same type for all T, because users should specialize neither |
| // allocator_is_nothrow nor std::allocator. |
| template <typename Alloc> |
| struct allocator_is_nothrow |
| : memory_internal::ExtractOrT<memory_internal::GetIsNothrow, Alloc, |
| std::false_type> {}; |
| |
| #if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW |
| template <typename T> |
| struct allocator_is_nothrow<std::allocator<T>> : std::true_type {}; |
| struct default_allocator_is_nothrow : std::true_type {}; |
| #else |
| struct default_allocator_is_nothrow : std::false_type {}; |
| #endif |
| |
| namespace memory_internal { |
| template <typename Allocator, typename Iterator, typename... Args> |
| void ConstructRange(Allocator& alloc, Iterator first, Iterator last, |
| const Args&... args) { |
| for (Iterator cur = first; cur != last; ++cur) { |
| ABSL_INTERNAL_TRY { |
| std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur), |
| args...); |
| } |
| ABSL_INTERNAL_CATCH_ANY { |
| while (cur != first) { |
| --cur; |
| std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur)); |
| } |
| ABSL_INTERNAL_RETHROW; |
| } |
| } |
| } |
| |
| template <typename Allocator, typename Iterator, typename InputIterator> |
| void CopyRange(Allocator& alloc, Iterator destination, InputIterator first, |
| InputIterator last) { |
| for (Iterator cur = destination; first != last; |
| static_cast<void>(++cur), static_cast<void>(++first)) { |
| ABSL_INTERNAL_TRY { |
| std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur), |
| *first); |
| } |
| ABSL_INTERNAL_CATCH_ANY { |
| while (cur != destination) { |
| --cur; |
| std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur)); |
| } |
| ABSL_INTERNAL_RETHROW; |
| } |
| } |
| } |
| } // namespace memory_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_MEMORY_MEMORY_H_ |
| *¯¶ |
| soong/.intermediates/external/abseil-cpp/absl_container_inlined_vector_internal_hdrs/gen/my_include_dir/absl/container/internal/inlined_vector.hµ// Copyright 2019 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_H_ |
| #define ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_H_ |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <cstring> |
| #include <iterator> |
| #include <limits> |
| #include <memory> |
| #include <new> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/identity.h" |
| #include "absl/base/macros.h" |
| #include "absl/container/internal/compressed_tuple.h" |
| #include "absl/memory/memory.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/types/span.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace inlined_vector_internal { |
| |
| // GCC does not deal very well with the below code |
| #if !defined(__clang__) && defined(__GNUC__) |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic ignored "-Warray-bounds" |
| #endif |
| |
| template <typename A> |
| using AllocatorTraits = std::allocator_traits<A>; |
| template <typename A> |
| using ValueType = typename AllocatorTraits<A>::value_type; |
| template <typename A> |
| using SizeType = typename AllocatorTraits<A>::size_type; |
| template <typename A> |
| using Pointer = typename AllocatorTraits<A>::pointer; |
| template <typename A> |
| using ConstPointer = typename AllocatorTraits<A>::const_pointer; |
| template <typename A> |
| using SizeType = typename AllocatorTraits<A>::size_type; |
| template <typename A> |
| using DifferenceType = typename AllocatorTraits<A>::difference_type; |
| template <typename A> |
| using Reference = ValueType<A>&; |
| template <typename A> |
| using ConstReference = const ValueType<A>&; |
| template <typename A> |
| using Iterator = Pointer<A>; |
| template <typename A> |
| using ConstIterator = ConstPointer<A>; |
| template <typename A> |
| using ReverseIterator = typename std::reverse_iterator<Iterator<A>>; |
| template <typename A> |
| using ConstReverseIterator = typename std::reverse_iterator<ConstIterator<A>>; |
| template <typename A> |
| using MoveIterator = typename std::move_iterator<Iterator<A>>; |
| |
| template <typename A> |
| using IsMoveAssignOk = std::is_move_assignable<ValueType<A>>; |
| template <typename A> |
| using IsSwapOk = absl::type_traits_internal::IsSwappable<ValueType<A>>; |
| |
| template <typename A, |
| bool IsTriviallyDestructible = |
| absl::is_trivially_destructible<ValueType<A>>::value && |
| std::is_same<A, std::allocator<ValueType<A>>>::value> |
| struct DestroyAdapter; |
| |
| template <typename A> |
| struct DestroyAdapter<A, /* IsTriviallyDestructible */ false> { |
| static void DestroyElements(A& allocator, Pointer<A> destroy_first, |
| SizeType<A> destroy_size) { |
| for (SizeType<A> i = destroy_size; i != 0;) { |
| --i; |
| AllocatorTraits<A>::destroy(allocator, destroy_first + i); |
| } |
| } |
| }; |
| |
| template <typename A> |
| struct DestroyAdapter<A, /* IsTriviallyDestructible */ true> { |
| static void DestroyElements(A& allocator, Pointer<A> destroy_first, |
| SizeType<A> destroy_size) { |
| static_cast<void>(allocator); |
| static_cast<void>(destroy_first); |
| static_cast<void>(destroy_size); |
| } |
| }; |
| |
| template <typename A> |
| struct Allocation { |
| Pointer<A> data = nullptr; |
| SizeType<A> capacity = 0; |
| }; |
| |
| template <typename A, |
| bool IsOverAligned = |
| (alignof(ValueType<A>) > ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT)> |
| struct MallocAdapter { |
| static Allocation<A> Allocate(A& allocator, SizeType<A> requested_capacity) { |
| return {AllocatorTraits<A>::allocate(allocator, requested_capacity), |
| requested_capacity}; |
| } |
| |
| static void Deallocate(A& allocator, Pointer<A> pointer, |
| SizeType<A> capacity) { |
| AllocatorTraits<A>::deallocate(allocator, pointer, capacity); |
| } |
| }; |
| |
| template <typename A, typename ValueAdapter> |
| void ConstructElements(absl::internal::type_identity_t<A>& allocator, |
| Pointer<A> construct_first, ValueAdapter& values, |
| SizeType<A> construct_size) { |
| for (SizeType<A> i = 0; i < construct_size; ++i) { |
| ABSL_INTERNAL_TRY { values.ConstructNext(allocator, construct_first + i); } |
| ABSL_INTERNAL_CATCH_ANY { |
| DestroyAdapter<A>::DestroyElements(allocator, construct_first, i); |
| ABSL_INTERNAL_RETHROW; |
| } |
| } |
| } |
| |
| template <typename A, typename ValueAdapter> |
| void AssignElements(Pointer<A> assign_first, ValueAdapter& values, |
| SizeType<A> assign_size) { |
| for (SizeType<A> i = 0; i < assign_size; ++i) { |
| values.AssignNext(assign_first + i); |
| } |
| } |
| |
| template <typename A> |
| struct StorageView { |
| Pointer<A> data; |
| SizeType<A> size; |
| SizeType<A> capacity; |
| }; |
| |
| template <typename A, typename Iterator> |
| class IteratorValueAdapter { |
| public: |
| explicit IteratorValueAdapter(const Iterator& it) : it_(it) {} |
| |
| void ConstructNext(A& allocator, Pointer<A> construct_at) { |
| AllocatorTraits<A>::construct(allocator, construct_at, *it_); |
| ++it_; |
| } |
| |
| void AssignNext(Pointer<A> assign_at) { |
| *assign_at = *it_; |
| ++it_; |
| } |
| |
| private: |
| Iterator it_; |
| }; |
| |
| template <typename A> |
| class CopyValueAdapter { |
| public: |
| explicit CopyValueAdapter(ConstPointer<A> p) : ptr_(p) {} |
| |
| void ConstructNext(A& allocator, Pointer<A> construct_at) { |
| AllocatorTraits<A>::construct(allocator, construct_at, *ptr_); |
| } |
| |
| void AssignNext(Pointer<A> assign_at) { *assign_at = *ptr_; } |
| |
| private: |
| ConstPointer<A> ptr_; |
| }; |
| |
| template <typename A> |
| class DefaultValueAdapter { |
| public: |
| explicit DefaultValueAdapter() {} |
| |
| void ConstructNext(A& allocator, Pointer<A> construct_at) { |
| AllocatorTraits<A>::construct(allocator, construct_at); |
| } |
| |
| void AssignNext(Pointer<A> assign_at) { *assign_at = ValueType<A>(); } |
| }; |
| |
| template <typename A> |
| class AllocationTransaction { |
| public: |
| explicit AllocationTransaction(A& allocator) |
| : allocator_data_(allocator, nullptr), capacity_(0) {} |
| |
| ~AllocationTransaction() { |
| if (DidAllocate()) { |
| MallocAdapter<A>::Deallocate(GetAllocator(), GetData(), GetCapacity()); |
| } |
| } |
| |
| AllocationTransaction(const AllocationTransaction&) = delete; |
| void operator=(const AllocationTransaction&) = delete; |
| |
| A& GetAllocator() { return allocator_data_.template get<0>(); } |
| Pointer<A>& GetData() { return allocator_data_.template get<1>(); } |
| SizeType<A>& GetCapacity() { return capacity_; } |
| |
| bool DidAllocate() { return GetData() != nullptr; } |
| |
| Pointer<A> Allocate(SizeType<A> requested_capacity) { |
| Allocation<A> result = |
| MallocAdapter<A>::Allocate(GetAllocator(), requested_capacity); |
| GetData() = result.data; |
| GetCapacity() = result.capacity; |
| return result.data; |
| } |
| |
| [[nodiscard]] Allocation<A> Release() && { |
| Allocation<A> result = {GetData(), GetCapacity()}; |
| Reset(); |
| return result; |
| } |
| |
| private: |
| void Reset() { |
| GetData() = nullptr; |
| GetCapacity() = 0; |
| } |
| |
| container_internal::CompressedTuple<A, Pointer<A>> allocator_data_; |
| SizeType<A> capacity_; |
| }; |
| |
| template <typename A> |
| class ConstructionTransaction { |
| public: |
| explicit ConstructionTransaction(A& allocator) |
| : allocator_data_(allocator, nullptr), size_(0) {} |
| |
| ~ConstructionTransaction() { |
| if (DidConstruct()) { |
| DestroyAdapter<A>::DestroyElements(GetAllocator(), GetData(), GetSize()); |
| } |
| } |
| |
| ConstructionTransaction(const ConstructionTransaction&) = delete; |
| void operator=(const ConstructionTransaction&) = delete; |
| |
| A& GetAllocator() { return allocator_data_.template get<0>(); } |
| Pointer<A>& GetData() { return allocator_data_.template get<1>(); } |
| SizeType<A>& GetSize() { return size_; } |
| |
| bool DidConstruct() { return GetData() != nullptr; } |
| template <typename ValueAdapter> |
| void Construct(Pointer<A> data, ValueAdapter& values, SizeType<A> size) { |
| ConstructElements<A>(GetAllocator(), data, values, size); |
| GetData() = data; |
| GetSize() = size; |
| } |
| void Commit() && { |
| GetData() = nullptr; |
| GetSize() = 0; |
| } |
| |
| private: |
| container_internal::CompressedTuple<A, Pointer<A>> allocator_data_; |
| SizeType<A> size_; |
| }; |
| |
| template <typename T, size_t N, typename A> |
| class Storage { |
| public: |
| struct MemcpyPolicy {}; |
| struct ElementwiseAssignPolicy {}; |
| struct ElementwiseSwapPolicy {}; |
| struct ElementwiseConstructPolicy {}; |
| |
| using MoveAssignmentPolicy = absl::conditional_t< |
| // Fast path: if the value type can be trivially move assigned and |
| // destroyed, and we know the allocator doesn't do anything fancy, then |
| // it's safe for us to simply adopt the contents of the storage for |
| // `other` and remove its own reference to them. It's as if we had |
| // individually move-assigned each value and then destroyed the original. |
| absl::conjunction<absl::is_trivially_move_assignable<ValueType<A>>, |
| absl::is_trivially_destructible<ValueType<A>>, |
| std::is_same<A, std::allocator<ValueType<A>>>>::value, |
| MemcpyPolicy, |
| // Otherwise we use move assignment if possible. If not, we simulate |
| // move assignment using move construction. |
| // |
| // Note that this is in contrast to e.g. std::vector and std::optional, |
| // which are themselves not move-assignable when their contained type is |
| // not. |
| absl::conditional_t<IsMoveAssignOk<A>::value, ElementwiseAssignPolicy, |
| ElementwiseConstructPolicy>>; |
| |
| // The policy to be used specifically when swapping inlined elements. |
| using SwapInlinedElementsPolicy = absl::conditional_t< |
| // Fast path: if the value type can be trivially relocated, and we |
| // know the allocator doesn't do anything fancy, then it's safe for us |
| // to simply swap the bytes in the inline storage. It's as if we had |
| // relocated the first vector's elements into temporary storage, |
| // relocated the second's elements into the (now-empty) first's, |
| // and then relocated from temporary storage into the second. |
| absl::conjunction<absl::is_trivially_relocatable<ValueType<A>>, |
| std::is_same<A, std::allocator<ValueType<A>>>>::value, |
| MemcpyPolicy, |
| absl::conditional_t<IsSwapOk<A>::value, ElementwiseSwapPolicy, |
| ElementwiseConstructPolicy>>; |
| |
| static SizeType<A> NextCapacity(SizeType<A> current_capacity) { |
| return current_capacity * 2; |
| } |
| |
| static SizeType<A> ComputeCapacity(SizeType<A> current_capacity, |
| SizeType<A> requested_capacity) { |
| return (std::max)(NextCapacity(current_capacity), requested_capacity); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Storage Constructors and Destructor |
| // --------------------------------------------------------------------------- |
| |
| Storage() : metadata_(A(), /* size and is_allocated */ 0u) {} |
| |
| explicit Storage(const A& allocator) |
| : metadata_(allocator, /* size and is_allocated */ 0u) {} |
| |
| ~Storage() { |
| // Fast path: if we are empty and not allocated, there's nothing to do. |
| if (GetSizeAndIsAllocated() == 0) { |
| return; |
| } |
| |
| // Fast path: if no destructors need to be run and we know the allocator |
| // doesn't do anything fancy, then all we need to do is deallocate (and |
| // maybe not even that). |
| if (absl::is_trivially_destructible<ValueType<A>>::value && |
| std::is_same<A, std::allocator<ValueType<A>>>::value) { |
| DeallocateIfAllocated(); |
| return; |
| } |
| |
| DestroyContents(); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Storage Member Accessors |
| // --------------------------------------------------------------------------- |
| |
| SizeType<A>& GetSizeAndIsAllocated() { return metadata_.template get<1>(); } |
| |
| const SizeType<A>& GetSizeAndIsAllocated() const { |
| return metadata_.template get<1>(); |
| } |
| |
| SizeType<A> GetSize() const { return GetSizeAndIsAllocated() >> 1; } |
| |
| bool GetIsAllocated() const { return GetSizeAndIsAllocated() & 1; } |
| |
| Pointer<A> GetAllocatedData() { |
| // GCC 12 has a false-positive -Wmaybe-uninitialized warning here. |
| #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0) |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" |
| #endif |
| return data_.allocated.allocated_data; |
| #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0) |
| #pragma GCC diagnostic pop |
| #endif |
| } |
| |
| ConstPointer<A> GetAllocatedData() const { |
| return data_.allocated.allocated_data; |
| } |
| |
| // ABSL_ATTRIBUTE_NO_SANITIZE_CFI is used because the memory pointed to may be |
| // uninitialized, a common pattern in allocate()+construct() APIs. |
| // https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking |
| // NOTE: When this was written, LLVM documentation did not explicitly |
| // mention that casting `char*` and using `reinterpret_cast` qualifies |
| // as a bad cast. |
| ABSL_ATTRIBUTE_NO_SANITIZE_CFI Pointer<A> GetInlinedData() { |
| return reinterpret_cast<Pointer<A>>(data_.inlined.inlined_data); |
| } |
| |
| ABSL_ATTRIBUTE_NO_SANITIZE_CFI ConstPointer<A> GetInlinedData() const { |
| return reinterpret_cast<ConstPointer<A>>(data_.inlined.inlined_data); |
| } |
| |
| SizeType<A> GetAllocatedCapacity() const { |
| return data_.allocated.allocated_capacity; |
| } |
| |
| SizeType<A> GetInlinedCapacity() const { |
| return static_cast<SizeType<A>>(kOptimalInlinedSize); |
| } |
| |
| StorageView<A> MakeStorageView() { |
| return GetIsAllocated() ? StorageView<A>{GetAllocatedData(), GetSize(), |
| GetAllocatedCapacity()} |
| : StorageView<A>{GetInlinedData(), GetSize(), |
| GetInlinedCapacity()}; |
| } |
| |
| A& GetAllocator() { return metadata_.template get<0>(); } |
| |
| const A& GetAllocator() const { return metadata_.template get<0>(); } |
| |
| // --------------------------------------------------------------------------- |
| // Storage Member Mutators |
| // --------------------------------------------------------------------------- |
| |
| ABSL_ATTRIBUTE_NOINLINE void InitFrom(const Storage& other); |
| |
| template <typename ValueAdapter> |
| void Initialize(ValueAdapter values, SizeType<A> new_size); |
| |
| template <typename ValueAdapter> |
| void Assign(ValueAdapter values, SizeType<A> new_size); |
| |
| template <typename ValueAdapter> |
| void Resize(ValueAdapter values, SizeType<A> new_size); |
| |
| template <typename ValueAdapter> |
| Iterator<A> Insert(ConstIterator<A> pos, ValueAdapter values, |
| SizeType<A> insert_count); |
| |
| template <typename... Args> |
| Reference<A> EmplaceBack(Args&&... args); |
| |
| Iterator<A> Erase(ConstIterator<A> from, ConstIterator<A> to); |
| |
| void Reserve(SizeType<A> requested_capacity); |
| |
| void ShrinkToFit(); |
| |
| void Swap(Storage* other_storage_ptr); |
| |
| void SetIsAllocated() { |
| GetSizeAndIsAllocated() |= static_cast<SizeType<A>>(1); |
| } |
| |
| void UnsetIsAllocated() { |
| GetSizeAndIsAllocated() &= ((std::numeric_limits<SizeType<A>>::max)() - 1); |
| } |
| |
| void SetSize(SizeType<A> size) { |
| GetSizeAndIsAllocated() = |
| (size << 1) | static_cast<SizeType<A>>(GetIsAllocated()); |
| } |
| |
| void SetAllocatedSize(SizeType<A> size) { |
| GetSizeAndIsAllocated() = (size << 1) | static_cast<SizeType<A>>(1); |
| } |
| |
| void SetInlinedSize(SizeType<A> size) { |
| GetSizeAndIsAllocated() = size << static_cast<SizeType<A>>(1); |
| } |
| |
| void AddSize(SizeType<A> count) { |
| GetSizeAndIsAllocated() += count << static_cast<SizeType<A>>(1); |
| } |
| |
| void SubtractSize(SizeType<A> count) { |
| ABSL_HARDENING_ASSERT(count <= GetSize()); |
| |
| GetSizeAndIsAllocated() -= count << static_cast<SizeType<A>>(1); |
| } |
| |
| void SetAllocation(Allocation<A> allocation) { |
| data_.allocated.allocated_data = allocation.data; |
| data_.allocated.allocated_capacity = allocation.capacity; |
| } |
| |
| void MemcpyFrom(const Storage& other_storage) { |
| // Assumption check: it doesn't make sense to memcpy inlined elements unless |
| // we know the allocator doesn't do anything fancy, and one of the following |
| // holds: |
| // |
| // * The elements are trivially relocatable. |
| // |
| // * It's possible to trivially assign the elements and then destroy the |
| // source. |
| // |
| // * It's possible to trivially copy construct/assign the elements. |
| // |
| { |
| using V = ValueType<A>; |
| ABSL_HARDENING_ASSERT( |
| other_storage.GetIsAllocated() || |
| (std::is_same<A, std::allocator<V>>::value && |
| ( |
| // First case above |
| absl::is_trivially_relocatable<V>::value || |
| // Second case above |
| (absl::is_trivially_move_assignable<V>::value && |
| absl::is_trivially_destructible<V>::value) || |
| // Third case above |
| (absl::is_trivially_copy_constructible<V>::value || |
| absl::is_trivially_copy_assignable<V>::value)))); |
| } |
| |
| GetSizeAndIsAllocated() = other_storage.GetSizeAndIsAllocated(); |
| data_ = other_storage.data_; |
| } |
| |
| void DeallocateIfAllocated() { |
| if (GetIsAllocated()) { |
| MallocAdapter<A>::Deallocate(GetAllocator(), GetAllocatedData(), |
| GetAllocatedCapacity()); |
| } |
| } |
| |
| private: |
| ABSL_ATTRIBUTE_NOINLINE void DestroyContents(); |
| |
| using Metadata = container_internal::CompressedTuple<A, SizeType<A>>; |
| |
| struct Allocated { |
| Pointer<A> allocated_data; |
| SizeType<A> allocated_capacity; |
| }; |
| |
| // `kOptimalInlinedSize` is an automatically adjusted inlined capacity of the |
| // `InlinedVector`. Sometimes, it is possible to increase the capacity (from |
| // the user requested `N`) without increasing the size of the `InlinedVector`. |
| static constexpr size_t kOptimalInlinedSize = |
| (std::max)(N, sizeof(Allocated) / sizeof(ValueType<A>)); |
| |
| struct Inlined { |
| alignas(ValueType<A>) unsigned char inlined_data[sizeof( |
| ValueType<A>[kOptimalInlinedSize])]; |
| }; |
| |
| union Data { |
| Allocated allocated; |
| Inlined inlined; |
| }; |
| |
| void SwapN(ElementwiseSwapPolicy, Storage* other, SizeType<A> n); |
| void SwapN(ElementwiseConstructPolicy, Storage* other, SizeType<A> n); |
| |
| void SwapInlinedElements(MemcpyPolicy, Storage* other); |
| template <typename NotMemcpyPolicy> |
| void SwapInlinedElements(NotMemcpyPolicy, Storage* other); |
| |
| template <typename... Args> |
| ABSL_ATTRIBUTE_NOINLINE Reference<A> EmplaceBackSlow(Args&&... args); |
| |
| Metadata metadata_; |
| Data data_; |
| }; |
| |
| template <typename T, size_t N, typename A> |
| void Storage<T, N, A>::DestroyContents() { |
| Pointer<A> data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData(); |
| DestroyAdapter<A>::DestroyElements(GetAllocator(), data, GetSize()); |
| DeallocateIfAllocated(); |
| } |
| |
| template <typename T, size_t N, typename A> |
| void Storage<T, N, A>::InitFrom(const Storage& other) { |
| const SizeType<A> n = other.GetSize(); |
| ABSL_HARDENING_ASSERT(n > 0); // Empty sources handled handled in caller. |
| ConstPointer<A> src; |
| Pointer<A> dst; |
| if (!other.GetIsAllocated()) { |
| dst = GetInlinedData(); |
| src = other.GetInlinedData(); |
| } else { |
| // Because this is only called from the `InlinedVector` constructors, it's |
| // safe to take on the allocation with size `0`. If `ConstructElements(...)` |
| // throws, deallocation will be automatically handled by `~Storage()`. |
| SizeType<A> requested_capacity = ComputeCapacity(GetInlinedCapacity(), n); |
| Allocation<A> allocation = |
| MallocAdapter<A>::Allocate(GetAllocator(), requested_capacity); |
| SetAllocation(allocation); |
| dst = allocation.data; |
| src = other.GetAllocatedData(); |
| } |
| |
| // Fast path: if the value type is trivially copy constructible and we know |
| // the allocator doesn't do anything fancy, then we know it is legal for us to |
| // simply memcpy the other vector's elements. |
| if (absl::is_trivially_copy_constructible<ValueType<A>>::value && |
| std::is_same<A, std::allocator<ValueType<A>>>::value) { |
| std::memcpy(reinterpret_cast<char*>(dst), |
| reinterpret_cast<const char*>(src), n * sizeof(ValueType<A>)); |
| } else { |
| auto values = IteratorValueAdapter<A, ConstPointer<A>>(src); |
| ConstructElements<A>(GetAllocator(), dst, values, n); |
| } |
| |
| GetSizeAndIsAllocated() = other.GetSizeAndIsAllocated(); |
| } |
| |
| template <typename T, size_t N, typename A> |
| template <typename ValueAdapter> |
| auto Storage<T, N, A>::Initialize(ValueAdapter values, |
| SizeType<A> new_size) -> void { |
| // Only callable from constructors! |
| ABSL_HARDENING_ASSERT(!GetIsAllocated()); |
| ABSL_HARDENING_ASSERT(GetSize() == 0); |
| |
| Pointer<A> construct_data; |
| if (new_size > GetInlinedCapacity()) { |
| // Because this is only called from the `InlinedVector` constructors, it's |
| // safe to take on the allocation with size `0`. If `ConstructElements(...)` |
| // throws, deallocation will be automatically handled by `~Storage()`. |
| SizeType<A> requested_capacity = |
| ComputeCapacity(GetInlinedCapacity(), new_size); |
| Allocation<A> allocation = |
| MallocAdapter<A>::Allocate(GetAllocator(), requested_capacity); |
| construct_data = allocation.data; |
| SetAllocation(allocation); |
| SetIsAllocated(); |
| } else { |
| construct_data = GetInlinedData(); |
| } |
| |
| ConstructElements<A>(GetAllocator(), construct_data, values, new_size); |
| |
| // Since the initial size was guaranteed to be `0` and the allocated bit is |
| // already correct for either case, *adding* `new_size` gives us the correct |
| // result faster than setting it directly. |
| AddSize(new_size); |
| } |
| |
| template <typename T, size_t N, typename A> |
| template <typename ValueAdapter> |
| auto Storage<T, N, A>::Assign(ValueAdapter values, |
| SizeType<A> new_size) -> void { |
| StorageView<A> storage_view = MakeStorageView(); |
| |
| AllocationTransaction<A> allocation_tx(GetAllocator()); |
| |
| absl::Span<ValueType<A>> assign_loop; |
| absl::Span<ValueType<A>> construct_loop; |
| absl::Span<ValueType<A>> destroy_loop; |
| |
| if (new_size > storage_view.capacity) { |
| SizeType<A> requested_capacity = |
| ComputeCapacity(storage_view.capacity, new_size); |
| construct_loop = {allocation_tx.Allocate(requested_capacity), new_size}; |
| destroy_loop = {storage_view.data, storage_view.size}; |
| } else if (new_size > storage_view.size) { |
| assign_loop = {storage_view.data, storage_view.size}; |
| construct_loop = {storage_view.data + storage_view.size, |
| new_size - storage_view.size}; |
| } else { |
| assign_loop = {storage_view.data, new_size}; |
| destroy_loop = {storage_view.data + new_size, storage_view.size - new_size}; |
| } |
| |
| AssignElements<A>(assign_loop.data(), values, assign_loop.size()); |
| |
| ConstructElements<A>(GetAllocator(), construct_loop.data(), values, |
| construct_loop.size()); |
| |
| DestroyAdapter<A>::DestroyElements(GetAllocator(), destroy_loop.data(), |
| destroy_loop.size()); |
| |
| if (allocation_tx.DidAllocate()) { |
| DeallocateIfAllocated(); |
| SetAllocation(std::move(allocation_tx).Release()); |
| SetIsAllocated(); |
| } |
| |
| SetSize(new_size); |
| } |
| |
| template <typename T, size_t N, typename A> |
| template <typename ValueAdapter> |
| auto Storage<T, N, A>::Resize(ValueAdapter values, |
| SizeType<A> new_size) -> void { |
| StorageView<A> storage_view = MakeStorageView(); |
| Pointer<A> const base = storage_view.data; |
| const SizeType<A> size = storage_view.size; |
| A& alloc = GetAllocator(); |
| if (new_size <= size) { |
| // Destroy extra old elements. |
| DestroyAdapter<A>::DestroyElements(alloc, base + new_size, size - new_size); |
| } else if (new_size <= storage_view.capacity) { |
| // Construct new elements in place. |
| ConstructElements<A>(alloc, base + size, values, new_size - size); |
| } else { |
| // Steps: |
| // a. Allocate new backing store. |
| // b. Construct new elements in new backing store. |
| // c. Move existing elements from old backing store to new backing store. |
| // d. Destroy all elements in old backing store. |
| // Use transactional wrappers for the first two steps so we can roll |
| // back if necessary due to exceptions. |
| AllocationTransaction<A> allocation_tx(alloc); |
| SizeType<A> requested_capacity = |
| ComputeCapacity(storage_view.capacity, new_size); |
| Pointer<A> new_data = allocation_tx.Allocate(requested_capacity); |
| |
| ConstructionTransaction<A> construction_tx(alloc); |
| construction_tx.Construct(new_data + size, values, new_size - size); |
| |
| IteratorValueAdapter<A, MoveIterator<A>> move_values( |
| (MoveIterator<A>(base))); |
| ConstructElements<A>(alloc, new_data, move_values, size); |
| |
| DestroyAdapter<A>::DestroyElements(alloc, base, size); |
| std::move(construction_tx).Commit(); |
| DeallocateIfAllocated(); |
| SetAllocation(std::move(allocation_tx).Release()); |
| SetIsAllocated(); |
| } |
| SetSize(new_size); |
| } |
| |
| template <typename T, size_t N, typename A> |
| template <typename ValueAdapter> |
| auto Storage<T, N, A>::Insert(ConstIterator<A> pos, ValueAdapter values, |
| SizeType<A> insert_count) -> Iterator<A> { |
| StorageView<A> storage_view = MakeStorageView(); |
| |
| auto insert_index = static_cast<SizeType<A>>( |
| std::distance(ConstIterator<A>(storage_view.data), pos)); |
| SizeType<A> insert_end_index = insert_index + insert_count; |
| SizeType<A> new_size = storage_view.size + insert_count; |
| |
| if (new_size > storage_view.capacity) { |
| AllocationTransaction<A> allocation_tx(GetAllocator()); |
| ConstructionTransaction<A> construction_tx(GetAllocator()); |
| ConstructionTransaction<A> move_construction_tx(GetAllocator()); |
| |
| IteratorValueAdapter<A, MoveIterator<A>> move_values( |
| MoveIterator<A>(storage_view.data)); |
| |
| SizeType<A> requested_capacity = |
| ComputeCapacity(storage_view.capacity, new_size); |
| Pointer<A> new_data = allocation_tx.Allocate(requested_capacity); |
| |
| construction_tx.Construct(new_data + insert_index, values, insert_count); |
| |
| move_construction_tx.Construct(new_data, move_values, insert_index); |
| |
| ConstructElements<A>(GetAllocator(), new_data + insert_end_index, |
| move_values, storage_view.size - insert_index); |
| |
| DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data, |
| storage_view.size); |
| |
| std::move(construction_tx).Commit(); |
| std::move(move_construction_tx).Commit(); |
| DeallocateIfAllocated(); |
| SetAllocation(std::move(allocation_tx).Release()); |
| |
| SetAllocatedSize(new_size); |
| return Iterator<A>(new_data + insert_index); |
| } else { |
| SizeType<A> move_construction_destination_index = |
| (std::max)(insert_end_index, storage_view.size); |
| |
| ConstructionTransaction<A> move_construction_tx(GetAllocator()); |
| |
| IteratorValueAdapter<A, MoveIterator<A>> move_construction_values( |
| MoveIterator<A>(storage_view.data + |
| (move_construction_destination_index - insert_count))); |
| absl::Span<ValueType<A>> move_construction = { |
| storage_view.data + move_construction_destination_index, |
| new_size - move_construction_destination_index}; |
| |
| Pointer<A> move_assignment_values = storage_view.data + insert_index; |
| absl::Span<ValueType<A>> move_assignment = { |
| storage_view.data + insert_end_index, |
| move_construction_destination_index - insert_end_index}; |
| |
| absl::Span<ValueType<A>> insert_assignment = {move_assignment_values, |
| move_construction.size()}; |
| |
| absl::Span<ValueType<A>> insert_construction = { |
| insert_assignment.data() + insert_assignment.size(), |
| insert_count - insert_assignment.size()}; |
| |
| move_construction_tx.Construct(move_construction.data(), |
| move_construction_values, |
| move_construction.size()); |
| |
| for (Pointer<A> |
| destination = move_assignment.data() + move_assignment.size(), |
| last_destination = move_assignment.data(), |
| source = move_assignment_values + move_assignment.size(); |
| ;) { |
| --destination; |
| --source; |
| if (destination < last_destination) break; |
| *destination = std::move(*source); |
| } |
| |
| AssignElements<A>(insert_assignment.data(), values, |
| insert_assignment.size()); |
| |
| ConstructElements<A>(GetAllocator(), insert_construction.data(), values, |
| insert_construction.size()); |
| |
| std::move(move_construction_tx).Commit(); |
| |
| AddSize(insert_count); |
| return Iterator<A>(storage_view.data + insert_index); |
| } |
| } |
| |
| template <typename T, size_t N, typename A> |
| template <typename... Args> |
| auto Storage<T, N, A>::EmplaceBack(Args&&... args) -> Reference<A> { |
| StorageView<A> storage_view = MakeStorageView(); |
| const SizeType<A> n = storage_view.size; |
| if (ABSL_PREDICT_TRUE(n != storage_view.capacity)) { |
| // Fast path; new element fits. |
| Pointer<A> last_ptr = storage_view.data + n; |
| AllocatorTraits<A>::construct(GetAllocator(), last_ptr, |
| std::forward<Args>(args)...); |
| AddSize(1); |
| return *last_ptr; |
| } |
| // TODO(b/173712035): Annotate with musttail attribute to prevent regression. |
| return EmplaceBackSlow(std::forward<Args>(args)...); |
| } |
| |
| template <typename T, size_t N, typename A> |
| template <typename... Args> |
| auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> Reference<A> { |
| StorageView<A> storage_view = MakeStorageView(); |
| AllocationTransaction<A> allocation_tx(GetAllocator()); |
| IteratorValueAdapter<A, MoveIterator<A>> move_values( |
| MoveIterator<A>(storage_view.data)); |
| SizeType<A> requested_capacity = NextCapacity(storage_view.capacity); |
| Pointer<A> construct_data = allocation_tx.Allocate(requested_capacity); |
| Pointer<A> last_ptr = construct_data + storage_view.size; |
| |
| // Construct new element. |
| AllocatorTraits<A>::construct(GetAllocator(), last_ptr, |
| std::forward<Args>(args)...); |
| // Move elements from old backing store to new backing store. |
| ABSL_INTERNAL_TRY { |
| ConstructElements<A>(GetAllocator(), allocation_tx.GetData(), move_values, |
| storage_view.size); |
| } |
| ABSL_INTERNAL_CATCH_ANY { |
| AllocatorTraits<A>::destroy(GetAllocator(), last_ptr); |
| ABSL_INTERNAL_RETHROW; |
| } |
| // Destroy elements in old backing store. |
| DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data, |
| storage_view.size); |
| |
| DeallocateIfAllocated(); |
| SetAllocation(std::move(allocation_tx).Release()); |
| SetIsAllocated(); |
| AddSize(1); |
| return *last_ptr; |
| } |
| |
| template <typename T, size_t N, typename A> |
| auto Storage<T, N, A>::Erase(ConstIterator<A> from, |
| ConstIterator<A> to) -> Iterator<A> { |
| StorageView<A> storage_view = MakeStorageView(); |
| |
| auto erase_size = static_cast<SizeType<A>>(std::distance(from, to)); |
| auto erase_index = static_cast<SizeType<A>>( |
| std::distance(ConstIterator<A>(storage_view.data), from)); |
| SizeType<A> erase_end_index = erase_index + erase_size; |
| |
| // Fast path: if the value type is trivially relocatable and we know |
| // the allocator doesn't do anything fancy, then we know it is legal for us to |
| // simply destroy the elements in the "erasure window" (which cannot throw) |
| // and then memcpy downward to close the window. |
| if (absl::is_trivially_relocatable<ValueType<A>>::value && |
| std::is_nothrow_destructible<ValueType<A>>::value && |
| std::is_same<A, std::allocator<ValueType<A>>>::value) { |
| DestroyAdapter<A>::DestroyElements( |
| GetAllocator(), storage_view.data + erase_index, erase_size); |
| std::memmove( |
| reinterpret_cast<char*>(storage_view.data + erase_index), |
| reinterpret_cast<const char*>(storage_view.data + erase_end_index), |
| (storage_view.size - erase_end_index) * sizeof(ValueType<A>)); |
| } else { |
| IteratorValueAdapter<A, MoveIterator<A>> move_values( |
| MoveIterator<A>(storage_view.data + erase_end_index)); |
| |
| AssignElements<A>(storage_view.data + erase_index, move_values, |
| storage_view.size - erase_end_index); |
| |
| DestroyAdapter<A>::DestroyElements( |
| GetAllocator(), storage_view.data + (storage_view.size - erase_size), |
| erase_size); |
| } |
| SubtractSize(erase_size); |
| return Iterator<A>(storage_view.data + erase_index); |
| } |
| |
| template <typename T, size_t N, typename A> |
| auto Storage<T, N, A>::Reserve(SizeType<A> requested_capacity) -> void { |
| StorageView<A> storage_view = MakeStorageView(); |
| |
| if (ABSL_PREDICT_FALSE(requested_capacity <= storage_view.capacity)) return; |
| |
| AllocationTransaction<A> allocation_tx(GetAllocator()); |
| |
| IteratorValueAdapter<A, MoveIterator<A>> move_values( |
| MoveIterator<A>(storage_view.data)); |
| |
| SizeType<A> new_requested_capacity = |
| ComputeCapacity(storage_view.capacity, requested_capacity); |
| Pointer<A> new_data = allocation_tx.Allocate(new_requested_capacity); |
| |
| ConstructElements<A>(GetAllocator(), new_data, move_values, |
| storage_view.size); |
| |
| DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data, |
| storage_view.size); |
| |
| DeallocateIfAllocated(); |
| SetAllocation(std::move(allocation_tx).Release()); |
| SetIsAllocated(); |
| } |
| |
| template <typename T, size_t N, typename A> |
| auto Storage<T, N, A>::ShrinkToFit() -> void { |
| // May only be called on allocated instances! |
| ABSL_HARDENING_ASSERT(GetIsAllocated()); |
| |
| StorageView<A> storage_view{GetAllocatedData(), GetSize(), |
| GetAllocatedCapacity()}; |
| |
| if (ABSL_PREDICT_FALSE(storage_view.size == storage_view.capacity)) return; |
| |
| AllocationTransaction<A> allocation_tx(GetAllocator()); |
| |
| IteratorValueAdapter<A, MoveIterator<A>> move_values( |
| MoveIterator<A>(storage_view.data)); |
| |
| Pointer<A> construct_data; |
| if (storage_view.size > GetInlinedCapacity()) { |
| SizeType<A> requested_capacity = storage_view.size; |
| construct_data = allocation_tx.Allocate(requested_capacity); |
| if (allocation_tx.GetCapacity() >= storage_view.capacity) { |
| // Already using the smallest available heap allocation. |
| return; |
| } |
| } else { |
| construct_data = GetInlinedData(); |
| } |
| |
| ABSL_INTERNAL_TRY { |
| ConstructElements<A>(GetAllocator(), construct_data, move_values, |
| storage_view.size); |
| } |
| ABSL_INTERNAL_CATCH_ANY { |
| SetAllocation({storage_view.data, storage_view.capacity}); |
| ABSL_INTERNAL_RETHROW; |
| } |
| |
| DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data, |
| storage_view.size); |
| |
| MallocAdapter<A>::Deallocate(GetAllocator(), storage_view.data, |
| storage_view.capacity); |
| |
| if (allocation_tx.DidAllocate()) { |
| SetAllocation(std::move(allocation_tx).Release()); |
| } else { |
| UnsetIsAllocated(); |
| } |
| } |
| |
| template <typename T, size_t N, typename A> |
| auto Storage<T, N, A>::Swap(Storage* other_storage_ptr) -> void { |
| using std::swap; |
| ABSL_HARDENING_ASSERT(this != other_storage_ptr); |
| |
| if (GetIsAllocated() && other_storage_ptr->GetIsAllocated()) { |
| swap(data_.allocated, other_storage_ptr->data_.allocated); |
| } else if (!GetIsAllocated() && !other_storage_ptr->GetIsAllocated()) { |
| SwapInlinedElements(SwapInlinedElementsPolicy{}, other_storage_ptr); |
| } else { |
| Storage* allocated_ptr = this; |
| Storage* inlined_ptr = other_storage_ptr; |
| if (!allocated_ptr->GetIsAllocated()) swap(allocated_ptr, inlined_ptr); |
| |
| StorageView<A> allocated_storage_view{ |
| allocated_ptr->GetAllocatedData(), allocated_ptr->GetSize(), |
| allocated_ptr->GetAllocatedCapacity()}; |
| |
| IteratorValueAdapter<A, MoveIterator<A>> move_values( |
| MoveIterator<A>(inlined_ptr->GetInlinedData())); |
| |
| ABSL_INTERNAL_TRY { |
| ConstructElements<A>(inlined_ptr->GetAllocator(), |
| allocated_ptr->GetInlinedData(), move_values, |
| inlined_ptr->GetSize()); |
| } |
| ABSL_INTERNAL_CATCH_ANY { |
| allocated_ptr->SetAllocation(Allocation<A>{ |
| allocated_storage_view.data, allocated_storage_view.capacity}); |
| ABSL_INTERNAL_RETHROW; |
| } |
| |
| DestroyAdapter<A>::DestroyElements(inlined_ptr->GetAllocator(), |
| inlined_ptr->GetInlinedData(), |
| inlined_ptr->GetSize()); |
| |
| inlined_ptr->SetAllocation(Allocation<A>{allocated_storage_view.data, |
| allocated_storage_view.capacity}); |
| } |
| |
| swap(GetSizeAndIsAllocated(), other_storage_ptr->GetSizeAndIsAllocated()); |
| swap(GetAllocator(), other_storage_ptr->GetAllocator()); |
| } |
| |
| template <typename T, size_t N, typename A> |
| void Storage<T, N, A>::SwapN(ElementwiseSwapPolicy, Storage* other, |
| SizeType<A> n) { |
| std::swap_ranges(GetInlinedData(), GetInlinedData() + n, |
| other->GetInlinedData()); |
| } |
| |
| template <typename T, size_t N, typename A> |
| void Storage<T, N, A>::SwapN(ElementwiseConstructPolicy, Storage* other, |
| SizeType<A> n) { |
| Pointer<A> a = GetInlinedData(); |
| Pointer<A> b = other->GetInlinedData(); |
| // see note on allocators in `SwapInlinedElements`. |
| A& allocator_a = GetAllocator(); |
| A& allocator_b = other->GetAllocator(); |
| for (SizeType<A> i = 0; i < n; ++i, ++a, ++b) { |
| ValueType<A> tmp(std::move(*a)); |
| |
| AllocatorTraits<A>::destroy(allocator_a, a); |
| AllocatorTraits<A>::construct(allocator_b, a, std::move(*b)); |
| |
| AllocatorTraits<A>::destroy(allocator_b, b); |
| AllocatorTraits<A>::construct(allocator_a, b, std::move(tmp)); |
| } |
| } |
| |
| template <typename T, size_t N, typename A> |
| void Storage<T, N, A>::SwapInlinedElements(MemcpyPolicy, Storage* other) { |
| Data tmp = data_; |
| data_ = other->data_; |
| other->data_ = tmp; |
| } |
| |
| template <typename T, size_t N, typename A> |
| template <typename NotMemcpyPolicy> |
| void Storage<T, N, A>::SwapInlinedElements(NotMemcpyPolicy policy, |
| Storage* other) { |
| // Note: `destroy` needs to use pre-swap allocator while `construct` - |
| // post-swap allocator. Allocators will be swapped later on outside of |
| // `SwapInlinedElements`. |
| Storage* small_ptr = this; |
| Storage* large_ptr = other; |
| if (small_ptr->GetSize() > large_ptr->GetSize()) { |
| std::swap(small_ptr, large_ptr); |
| } |
| |
| auto small_size = small_ptr->GetSize(); |
| auto diff = large_ptr->GetSize() - small_size; |
| SwapN(policy, other, small_size); |
| |
| IteratorValueAdapter<A, MoveIterator<A>> move_values( |
| MoveIterator<A>(large_ptr->GetInlinedData() + small_size)); |
| |
| ConstructElements<A>(large_ptr->GetAllocator(), |
| small_ptr->GetInlinedData() + small_size, move_values, |
| diff); |
| |
| DestroyAdapter<A>::DestroyElements(large_ptr->GetAllocator(), |
| large_ptr->GetInlinedData() + small_size, |
| diff); |
| } |
| |
| // End ignore "array-bounds" |
| #if !defined(__clang__) && defined(__GNUC__) |
| #pragma GCC diagnostic pop |
| #endif |
| |
| } // namespace inlined_vector_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_H_ |
| *ø |
| soong/.intermediates/external/abseil-cpp/absl_base_iterator_traits_internal_hdrs/gen/my_include_dir/absl/base/internal/iterator_traits.hê// Copyright 2025 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: internal/iterator_traits.h |
| // ----------------------------------------------------------------------------- |
| // |
| // Helpers for querying traits of iterators, for implementing containers, etc. |
| |
| #ifndef ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_ |
| #define ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_ |
| |
| #include <iterator> |
| #include <type_traits> |
| |
| #include "absl/base/config.h" |
| #include "absl/meta/type_traits.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace base_internal { |
| |
| template <typename Iterator, typename = void> |
| struct IteratorCategory {}; |
| |
| template <typename Iterator> |
| struct IteratorCategory< |
| Iterator, |
| absl::void_t<typename std::iterator_traits<Iterator>::iterator_category>> { |
| using type = typename std::iterator_traits<Iterator>::iterator_category; |
| }; |
| |
| template <typename Iterator, typename = void> |
| struct IteratorConceptImpl : IteratorCategory<Iterator> {}; |
| |
| template <typename Iterator> |
| struct IteratorConceptImpl< |
| Iterator, |
| absl::void_t<typename std::iterator_traits<Iterator>::iterator_concept>> { |
| using type = typename std::iterator_traits<Iterator>::iterator_concept; |
| }; |
| |
| // The newer `std::iterator_traits<Iterator>::iterator_concept` if available, |
| // else `std::iterator_traits<Iterator>::iterator_category`. |
| template <typename Iterator> |
| using IteratorConcept = typename IteratorConceptImpl<Iterator>::type; |
| |
| template <typename IteratorTag, typename Iterator> |
| using IsAtLeastIterator = |
| std::is_convertible<IteratorConcept<Iterator>, IteratorTag>; |
| |
| template <typename Iterator> |
| using IsAtLeastForwardIterator = |
| IsAtLeastIterator<std::forward_iterator_tag, Iterator>; |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_ |
| *ĺ |
| ~soong/.intermediates/external/abseil-cpp/absl_container_inlined_vector_hdrs/gen/my_include_dir/absl/container/inlined_vector.hÀ¹// Copyright 2019 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: inlined_vector.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file contains the declaration and definition of an "inlined |
| // vector" which behaves in an equivalent fashion to a `std::vector`, except |
| // that storage for small sequences of the vector are provided inline without |
| // requiring any heap allocation. |
| // |
| // An `absl::InlinedVector<T, N>` specifies the default capacity `N` as one of |
| // its template parameters. Instances where `size() <= N` hold contained |
| // elements in inline space. Typically `N` is very small so that sequences that |
| // are expected to be short do not require allocations. |
| // |
| // An `absl::InlinedVector` does not usually require a specific allocator. If |
| // the inlined vector grows beyond its initial constraints, it will need to |
| // allocate (as any normal `std::vector` would). This is usually performed with |
| // the default allocator (defined as `std::allocator<T>`). Optionally, a custom |
| // allocator type may be specified as `A` in `absl::InlinedVector<T, N, A>`. |
| |
| #ifndef ABSL_CONTAINER_INLINED_VECTOR_H_ |
| #define ABSL_CONTAINER_INLINED_VECTOR_H_ |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <cstdlib> |
| #include <cstring> |
| #include <initializer_list> |
| #include <iterator> |
| #include <memory> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/algorithm/algorithm.h" |
| #include "absl/base/attributes.h" |
| #include "absl/base/internal/iterator_traits.h" |
| #include "absl/base/internal/throw_delegate.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/optimization.h" |
| #include "absl/base/port.h" |
| #include "absl/container/internal/inlined_vector.h" |
| #include "absl/hash/internal/weakly_mixed_integer.h" |
| #include "absl/memory/memory.h" |
| #include "absl/meta/type_traits.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| // ----------------------------------------------------------------------------- |
| // InlinedVector |
| // ----------------------------------------------------------------------------- |
| // |
| // An `absl::InlinedVector` is designed to be a drop-in replacement for |
| // `std::vector` for use cases where the vector's size is sufficiently small |
| // that it can be inlined. If the inlined vector does grow beyond its estimated |
| // capacity, it will trigger an initial allocation on the heap, and will behave |
| // as a `std::vector`. The API of the `absl::InlinedVector` within this file is |
| // designed to cover the same API footprint as covered by `std::vector`. |
| template <typename T, size_t N, typename A = std::allocator<T>> |
| class ABSL_ATTRIBUTE_WARN_UNUSED InlinedVector { |
| static_assert(N > 0, "`absl::InlinedVector` requires an inlined capacity."); |
| |
| using Storage = inlined_vector_internal::Storage<T, N, A>; |
| |
| template <typename TheA> |
| using AllocatorTraits = inlined_vector_internal::AllocatorTraits<TheA>; |
| template <typename TheA> |
| using MoveIterator = inlined_vector_internal::MoveIterator<TheA>; |
| template <typename TheA> |
| using IsMoveAssignOk = inlined_vector_internal::IsMoveAssignOk<TheA>; |
| |
| template <typename TheA, typename Iterator> |
| using IteratorValueAdapter = |
| inlined_vector_internal::IteratorValueAdapter<TheA, Iterator>; |
| template <typename TheA> |
| using CopyValueAdapter = inlined_vector_internal::CopyValueAdapter<TheA>; |
| template <typename TheA> |
| using DefaultValueAdapter = |
| inlined_vector_internal::DefaultValueAdapter<TheA>; |
| |
| template <typename Iterator> |
| using EnableIfAtLeastForwardIterator = std::enable_if_t< |
| base_internal::IsAtLeastForwardIterator<Iterator>::value, int>; |
| template <typename Iterator> |
| using DisableIfAtLeastForwardIterator = std::enable_if_t< |
| !base_internal::IsAtLeastForwardIterator<Iterator>::value, int>; |
| |
| using MemcpyPolicy = typename Storage::MemcpyPolicy; |
| using ElementwiseAssignPolicy = typename Storage::ElementwiseAssignPolicy; |
| using ElementwiseConstructPolicy = |
| typename Storage::ElementwiseConstructPolicy; |
| using MoveAssignmentPolicy = typename Storage::MoveAssignmentPolicy; |
| |
| public: |
| using allocator_type = A; |
| using value_type = inlined_vector_internal::ValueType<A>; |
| using pointer = inlined_vector_internal::Pointer<A>; |
| using const_pointer = inlined_vector_internal::ConstPointer<A>; |
| using size_type = inlined_vector_internal::SizeType<A>; |
| using difference_type = inlined_vector_internal::DifferenceType<A>; |
| using reference = inlined_vector_internal::Reference<A>; |
| using const_reference = inlined_vector_internal::ConstReference<A>; |
| using iterator = inlined_vector_internal::Iterator<A>; |
| using const_iterator = inlined_vector_internal::ConstIterator<A>; |
| using reverse_iterator = inlined_vector_internal::ReverseIterator<A>; |
| using const_reverse_iterator = |
| inlined_vector_internal::ConstReverseIterator<A>; |
| |
| // --------------------------------------------------------------------------- |
| // InlinedVector Constructors and Destructor |
| // --------------------------------------------------------------------------- |
| |
| // Creates an empty inlined vector with a value-initialized allocator. |
| InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {} |
| |
| // Creates an empty inlined vector with a copy of `allocator`. |
| explicit InlinedVector(const allocator_type& allocator) noexcept |
| : storage_(allocator) {} |
| |
| // Creates an inlined vector with `n` copies of `value_type()`. |
| explicit InlinedVector(size_type n, |
| const allocator_type& allocator = allocator_type()) |
| : storage_(allocator) { |
| storage_.Initialize(DefaultValueAdapter<A>(), n); |
| } |
| |
| // Creates an inlined vector with `n` copies of `v`. |
| InlinedVector(size_type n, const_reference v, |
| const allocator_type& allocator = allocator_type()) |
| : storage_(allocator) { |
| storage_.Initialize(CopyValueAdapter<A>(std::addressof(v)), n); |
| } |
| |
| // Creates an inlined vector with copies of the elements of `list`. |
| InlinedVector(std::initializer_list<value_type> list, |
| const allocator_type& allocator = allocator_type()) |
| : InlinedVector(list.begin(), list.end(), allocator) {} |
| |
| // Creates an inlined vector with elements constructed from the provided |
| // forward iterator range [`first`, `last`). |
| // |
| // NOTE: the `enable_if` prevents ambiguous interpretation between a call to |
| // this constructor with two integral arguments and a call to the above |
| // `InlinedVector(size_type, const_reference)` constructor. |
| template <typename ForwardIterator, |
| EnableIfAtLeastForwardIterator<ForwardIterator> = 0> |
| InlinedVector(ForwardIterator first, ForwardIterator last, |
| const allocator_type& allocator = allocator_type()) |
| : storage_(allocator) { |
| storage_.Initialize(IteratorValueAdapter<A, ForwardIterator>(first), |
| static_cast<size_t>(std::distance(first, last))); |
| } |
| |
| // Creates an inlined vector with elements constructed from the provided input |
| // iterator range [`first`, `last`). |
| template <typename InputIterator, |
| DisableIfAtLeastForwardIterator<InputIterator> = 0> |
| InlinedVector(InputIterator first, InputIterator last, |
| const allocator_type& allocator = allocator_type()) |
| : storage_(allocator) { |
| std::copy(first, last, std::back_inserter(*this)); |
| } |
| |
| // Creates an inlined vector by copying the contents of `other` using |
| // `other`'s allocator. |
| InlinedVector(const InlinedVector& other) |
| : InlinedVector(other, other.storage_.GetAllocator()) {} |
| |
| // Creates an inlined vector by copying the contents of `other` using the |
| // provided `allocator`. |
| InlinedVector(const InlinedVector& other, const allocator_type& allocator) |
| : storage_(allocator) { |
| // Fast path: if the other vector is empty, there's nothing for us to do. |
| if (other.empty()) { |
| return; |
| } |
| |
| // Fast path: if the value type is trivially copy constructible, we know the |
| // allocator doesn't do anything fancy, and there is nothing on the heap |
| // then we know it is legal for us to simply memcpy the other vector's |
| // inlined bytes to form our copy of its elements. |
| if (absl::is_trivially_copy_constructible<value_type>::value && |
| std::is_same<A, std::allocator<value_type>>::value && |
| !other.storage_.GetIsAllocated()) { |
| storage_.MemcpyFrom(other.storage_); |
| return; |
| } |
| |
| storage_.InitFrom(other.storage_); |
| } |
| |
| // Creates an inlined vector by moving in the contents of `other` without |
| // allocating. If `other` contains allocated memory, the newly-created inlined |
| // vector will take ownership of that memory. However, if `other` does not |
| // contain allocated memory, the newly-created inlined vector will perform |
| // element-wise move construction of the contents of `other`. |
| // |
| // NOTE: since no allocation is performed for the inlined vector in either |
| // case, the `noexcept(...)` specification depends on whether moving the |
| // underlying objects can throw. It is assumed assumed that... |
| // a) move constructors should only throw due to allocation failure. |
| // b) if `value_type`'s move constructor allocates, it uses the same |
| // allocation function as the inlined vector's allocator. |
| // Thus, the move constructor is non-throwing if the allocator is non-throwing |
| // or `value_type`'s move constructor is specified as `noexcept`. |
| InlinedVector(InlinedVector&& other) noexcept( |
| absl::allocator_is_nothrow<allocator_type>::value || |
| std::is_nothrow_move_constructible<value_type>::value) |
| : storage_(other.storage_.GetAllocator()) { |
| // Fast path: if the value type can be trivially relocated (i.e. moved from |
| // and destroyed), and we know the allocator doesn't do anything fancy, then |
| // it's safe for us to simply adopt the contents of the storage for `other` |
| // and remove its own reference to them. It's as if we had individually |
| // move-constructed each value and then destroyed the original. |
| if (absl::is_trivially_relocatable<value_type>::value && |
| std::is_same<A, std::allocator<value_type>>::value) { |
| storage_.MemcpyFrom(other.storage_); |
| other.storage_.SetInlinedSize(0); |
| return; |
| } |
| |
| // Fast path: if the other vector is on the heap, we can simply take over |
| // its allocation. |
| if (other.storage_.GetIsAllocated()) { |
| storage_.SetAllocation({other.storage_.GetAllocatedData(), |
| other.storage_.GetAllocatedCapacity()}); |
| storage_.SetAllocatedSize(other.storage_.GetSize()); |
| |
| other.storage_.SetInlinedSize(0); |
| return; |
| } |
| |
| // Otherwise we must move each element individually. |
| IteratorValueAdapter<A, MoveIterator<A>> other_values( |
| MoveIterator<A>(other.storage_.GetInlinedData())); |
| |
| inlined_vector_internal::ConstructElements<A>( |
| storage_.GetAllocator(), storage_.GetInlinedData(), other_values, |
| other.storage_.GetSize()); |
| |
| storage_.SetInlinedSize(other.storage_.GetSize()); |
| } |
| |
| // Creates an inlined vector by moving in the contents of `other` with a copy |
| // of `allocator`. |
| // |
| // NOTE: if `other`'s allocator is not equal to `allocator`, even if `other` |
| // contains allocated memory, this move constructor will still allocate. Since |
| // allocation is performed, this constructor can only be `noexcept` if the |
| // specified allocator is also `noexcept`. |
| InlinedVector( |
| InlinedVector&& other, |
| const allocator_type& |
| allocator) noexcept(absl::allocator_is_nothrow<allocator_type>::value) |
| : storage_(allocator) { |
| // Fast path: if the value type can be trivially relocated (i.e. moved from |
| // and destroyed), and we know the allocator doesn't do anything fancy, then |
| // it's safe for us to simply adopt the contents of the storage for `other` |
| // and remove its own reference to them. It's as if we had individually |
| // move-constructed each value and then destroyed the original. |
| if (absl::is_trivially_relocatable<value_type>::value && |
| std::is_same<A, std::allocator<value_type>>::value) { |
| storage_.MemcpyFrom(other.storage_); |
| other.storage_.SetInlinedSize(0); |
| return; |
| } |
| |
| // Fast path: if the other vector is on the heap and shared the same |
| // allocator, we can simply take over its allocation. |
| if ((storage_.GetAllocator() == other.storage_.GetAllocator()) && |
| other.storage_.GetIsAllocated()) { |
| storage_.SetAllocation({other.storage_.GetAllocatedData(), |
| other.storage_.GetAllocatedCapacity()}); |
| storage_.SetAllocatedSize(other.storage_.GetSize()); |
| |
| other.storage_.SetInlinedSize(0); |
| return; |
| } |
| |
| // Otherwise we must move each element individually. |
| storage_.Initialize( |
| IteratorValueAdapter<A, MoveIterator<A>>(MoveIterator<A>(other.data())), |
| other.size()); |
| } |
| |
| ~InlinedVector() {} |
| |
| // --------------------------------------------------------------------------- |
| // InlinedVector Member Accessors |
| // --------------------------------------------------------------------------- |
| |
| // `InlinedVector::empty()` |
| // |
| // Returns whether the inlined vector contains no elements. |
| bool empty() const noexcept { return !size(); } |
| |
| // `InlinedVector::size()` |
| // |
| // Returns the number of elements in the inlined vector. |
| size_type size() const noexcept { return storage_.GetSize(); } |
| |
| // `InlinedVector::max_size()` |
| // |
| // Returns the maximum number of elements the inlined vector can hold. |
| size_type max_size() const noexcept { |
| // One bit of the size storage is used to indicate whether the inlined |
| // vector contains allocated memory. As a result, the maximum size that the |
| // inlined vector can express is the minimum of the limit of how many |
| // objects we can allocate and std::numeric_limits<size_type>::max() / 2. |
| return (std::min)(AllocatorTraits<A>::max_size(storage_.GetAllocator()), |
| (std::numeric_limits<size_type>::max)() / 2); |
| } |
| |
| // `InlinedVector::capacity()` |
| // |
| // Returns the number of elements that could be stored in the inlined vector |
| // without requiring a reallocation. |
| // |
| // NOTE: for most inlined vectors, `capacity()` should be equal to the |
| // template parameter `N`. For inlined vectors which exceed this capacity, |
| // they will no longer be inlined and `capacity()` will equal the capactity of |
| // the allocated memory. |
| size_type capacity() const noexcept { |
| return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity() |
| : storage_.GetInlinedCapacity(); |
| } |
| |
| // `InlinedVector::data()` |
| // |
| // Returns a `pointer` to the elements of the inlined vector. This pointer |
| // can be used to access and modify the contained elements. |
| // |
| // NOTE: only elements within [`data()`, `data() + size()`) are valid. |
| pointer data() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return storage_.GetIsAllocated() ? storage_.GetAllocatedData() |
| : storage_.GetInlinedData(); |
| } |
| |
| // Overload of `InlinedVector::data()` that returns a `const_pointer` to the |
| // elements of the inlined vector. This pointer can be used to access but not |
| // modify the contained elements. |
| // |
| // NOTE: only elements within [`data()`, `data() + size()`) are valid. |
| const_pointer data() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return storage_.GetIsAllocated() ? storage_.GetAllocatedData() |
| : storage_.GetInlinedData(); |
| } |
| |
| // `InlinedVector::operator[](...)` |
| // |
| // Returns a `reference` to the `i`th element of the inlined vector. |
| reference operator[](size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(i < size()); |
| return data()[i]; |
| } |
| |
| // Overload of `InlinedVector::operator[](...)` that returns a |
| // `const_reference` to the `i`th element of the inlined vector. |
| const_reference operator[](size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(i < size()); |
| return data()[i]; |
| } |
| |
| // `InlinedVector::at(...)` |
| // |
| // Returns a `reference` to the `i`th element of the inlined vector. |
| // |
| // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`, |
| // in both debug and non-debug builds, `std::out_of_range` will be thrown. |
| reference at(size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| if (ABSL_PREDICT_FALSE(i >= size())) { |
| base_internal::ThrowStdOutOfRange( |
| "`InlinedVector::at(size_type)` failed bounds check"); |
| } |
| return data()[i]; |
| } |
| |
| // Overload of `InlinedVector::at(...)` that returns a `const_reference` to |
| // the `i`th element of the inlined vector. |
| // |
| // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`, |
| // in both debug and non-debug builds, `std::out_of_range` will be thrown. |
| const_reference at(size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| if (ABSL_PREDICT_FALSE(i >= size())) { |
| base_internal::ThrowStdOutOfRange( |
| "`InlinedVector::at(size_type) const` failed bounds check"); |
| } |
| return data()[i]; |
| } |
| |
| // `InlinedVector::front()` |
| // |
| // Returns a `reference` to the first element of the inlined vector. |
| reference front() ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(!empty()); |
| return data()[0]; |
| } |
| |
| // Overload of `InlinedVector::front()` that returns a `const_reference` to |
| // the first element of the inlined vector. |
| const_reference front() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(!empty()); |
| return data()[0]; |
| } |
| |
| // `InlinedVector::back()` |
| // |
| // Returns a `reference` to the last element of the inlined vector. |
| reference back() ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(!empty()); |
| return data()[size() - 1]; |
| } |
| |
| // Overload of `InlinedVector::back()` that returns a `const_reference` to the |
| // last element of the inlined vector. |
| const_reference back() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(!empty()); |
| return data()[size() - 1]; |
| } |
| |
| // `InlinedVector::begin()` |
| // |
| // Returns an `iterator` to the beginning of the inlined vector. |
| iterator begin() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); } |
| |
| // Overload of `InlinedVector::begin()` that returns a `const_iterator` to |
| // the beginning of the inlined vector. |
| const_iterator begin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return data(); |
| } |
| |
| // `InlinedVector::end()` |
| // |
| // Returns an `iterator` to the end of the inlined vector. |
| iterator end() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return data() + size(); |
| } |
| |
| // Overload of `InlinedVector::end()` that returns a `const_iterator` to the |
| // end of the inlined vector. |
| const_iterator end() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return data() + size(); |
| } |
| |
| // `InlinedVector::cbegin()` |
| // |
| // Returns a `const_iterator` to the beginning of the inlined vector. |
| const_iterator cbegin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return begin(); |
| } |
| |
| // `InlinedVector::cend()` |
| // |
| // Returns a `const_iterator` to the end of the inlined vector. |
| const_iterator cend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return end(); |
| } |
| |
| // `InlinedVector::rbegin()` |
| // |
| // Returns a `reverse_iterator` from the end of the inlined vector. |
| reverse_iterator rbegin() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return reverse_iterator(end()); |
| } |
| |
| // Overload of `InlinedVector::rbegin()` that returns a |
| // `const_reverse_iterator` from the end of the inlined vector. |
| const_reverse_iterator rbegin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return const_reverse_iterator(end()); |
| } |
| |
| // `InlinedVector::rend()` |
| // |
| // Returns a `reverse_iterator` from the beginning of the inlined vector. |
| reverse_iterator rend() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return reverse_iterator(begin()); |
| } |
| |
| // Overload of `InlinedVector::rend()` that returns a `const_reverse_iterator` |
| // from the beginning of the inlined vector. |
| const_reverse_iterator rend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return const_reverse_iterator(begin()); |
| } |
| |
| // `InlinedVector::crbegin()` |
| // |
| // Returns a `const_reverse_iterator` from the end of the inlined vector. |
| const_reverse_iterator crbegin() const noexcept |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return rbegin(); |
| } |
| |
| // `InlinedVector::crend()` |
| // |
| // Returns a `const_reverse_iterator` from the beginning of the inlined |
| // vector. |
| const_reverse_iterator crend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return rend(); |
| } |
| |
| // `InlinedVector::get_allocator()` |
| // |
| // Returns a copy of the inlined vector's allocator. |
| allocator_type get_allocator() const { return storage_.GetAllocator(); } |
| |
| // --------------------------------------------------------------------------- |
| // InlinedVector Member Mutators |
| // --------------------------------------------------------------------------- |
| |
| // `InlinedVector::operator=(...)` |
| // |
| // Replaces the elements of the inlined vector with copies of the elements of |
| // `list`. |
| InlinedVector& operator=(std::initializer_list<value_type> list) { |
| assign(list.begin(), list.end()); |
| |
| return *this; |
| } |
| |
| // Overload of `InlinedVector::operator=(...)` that replaces the elements of |
| // the inlined vector with copies of the elements of `other`. |
| InlinedVector& operator=(const InlinedVector& other) { |
| if (ABSL_PREDICT_TRUE(this != std::addressof(other))) { |
| const_pointer other_data = other.data(); |
| assign(other_data, other_data + other.size()); |
| } |
| |
| return *this; |
| } |
| |
| // Overload of `InlinedVector::operator=(...)` that moves the elements of |
| // `other` into the inlined vector. |
| // |
| // NOTE: as a result of calling this overload, `other` is left in a valid but |
| // unspecified state. |
| InlinedVector& operator=(InlinedVector&& other) { |
| if (ABSL_PREDICT_TRUE(this != std::addressof(other))) { |
| MoveAssignment(MoveAssignmentPolicy{}, std::move(other)); |
| } |
| |
| return *this; |
| } |
| |
| // `InlinedVector::assign(...)` |
| // |
| // Replaces the contents of the inlined vector with `n` copies of `v`. |
| void assign(size_type n, const_reference v) { |
| storage_.Assign(CopyValueAdapter<A>(std::addressof(v)), n); |
| } |
| |
| // Overload of `InlinedVector::assign(...)` that replaces the contents of the |
| // inlined vector with copies of the elements of `list`. |
| void assign(std::initializer_list<value_type> list) { |
| assign(list.begin(), list.end()); |
| } |
| |
| // Overload of `InlinedVector::assign(...)` to replace the contents of the |
| // inlined vector with the range [`first`, `last`). |
| // |
| // NOTE: this overload is for iterators that are "forward" category or better. |
| template <typename ForwardIterator, |
| EnableIfAtLeastForwardIterator<ForwardIterator> = 0> |
| void assign(ForwardIterator first, ForwardIterator last) { |
| storage_.Assign(IteratorValueAdapter<A, ForwardIterator>(first), |
| static_cast<size_t>(std::distance(first, last))); |
| } |
| |
| // Overload of `InlinedVector::assign(...)` to replace the contents of the |
| // inlined vector with the range [`first`, `last`). |
| // |
| // NOTE: this overload is for iterators that are "input" category. |
| template <typename InputIterator, |
| DisableIfAtLeastForwardIterator<InputIterator> = 0> |
| void assign(InputIterator first, InputIterator last) { |
| size_type i = 0; |
| for (; i < size() && first != last; ++i, static_cast<void>(++first)) { |
| data()[i] = *first; |
| } |
| |
| erase(data() + i, data() + size()); |
| std::copy(first, last, std::back_inserter(*this)); |
| } |
| |
| // `InlinedVector::resize(...)` |
| // |
| // Resizes the inlined vector to contain `n` elements. |
| // |
| // NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n` |
| // is larger than `size()`, new elements are value-initialized. |
| void resize(size_type n) { |
| ABSL_HARDENING_ASSERT(n <= max_size()); |
| storage_.Resize(DefaultValueAdapter<A>(), n); |
| } |
| |
| // Overload of `InlinedVector::resize(...)` that resizes the inlined vector to |
| // contain `n` elements. |
| // |
| // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n` |
| // is larger than `size()`, new elements are copied-constructed from `v`. |
| void resize(size_type n, const_reference v) { |
| ABSL_HARDENING_ASSERT(n <= max_size()); |
| storage_.Resize(CopyValueAdapter<A>(std::addressof(v)), n); |
| } |
| |
| // `InlinedVector::insert(...)` |
| // |
| // Inserts a copy of `v` at `pos`, returning an `iterator` to the newly |
| // inserted element. |
| iterator insert(const_iterator pos, |
| const_reference v) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return emplace(pos, v); |
| } |
| |
| // Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using |
| // move semantics, returning an `iterator` to the newly inserted element. |
| iterator insert(const_iterator pos, |
| value_type&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return emplace(pos, std::move(v)); |
| } |
| |
| // Overload of `InlinedVector::insert(...)` that inserts `n` contiguous copies |
| // of `v` starting at `pos`, returning an `iterator` pointing to the first of |
| // the newly inserted elements. |
| iterator insert(const_iterator pos, size_type n, |
| const_reference v) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(pos >= begin()); |
| ABSL_HARDENING_ASSERT(pos <= end()); |
| |
| if (ABSL_PREDICT_TRUE(n != 0)) { |
| value_type dealias = v; |
| // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2 |
| // It appears that GCC thinks that since `pos` is a const pointer and may |
| // point to uninitialized memory at this point, a warning should be |
| // issued. But `pos` is actually only used to compute an array index to |
| // write to. |
| #if !defined(__clang__) && defined(__GNUC__) |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" |
| #endif |
| return storage_.Insert(pos, CopyValueAdapter<A>(std::addressof(dealias)), |
| n); |
| #if !defined(__clang__) && defined(__GNUC__) |
| #pragma GCC diagnostic pop |
| #endif |
| } else { |
| return const_cast<iterator>(pos); |
| } |
| } |
| |
| // Overload of `InlinedVector::insert(...)` that inserts copies of the |
| // elements of `list` starting at `pos`, returning an `iterator` pointing to |
| // the first of the newly inserted elements. |
| iterator insert(const_iterator pos, std::initializer_list<value_type> list) |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return insert(pos, list.begin(), list.end()); |
| } |
| |
| // Overload of `InlinedVector::insert(...)` that inserts the range [`first`, |
| // `last`) starting at `pos`, returning an `iterator` pointing to the first |
| // of the newly inserted elements. |
| // |
| // NOTE: this overload is for iterators that are "forward" category or better. |
| template <typename ForwardIterator, |
| EnableIfAtLeastForwardIterator<ForwardIterator> = 0> |
| iterator insert(const_iterator pos, ForwardIterator first, |
| ForwardIterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(pos >= begin()); |
| ABSL_HARDENING_ASSERT(pos <= end()); |
| |
| if (ABSL_PREDICT_TRUE(first != last)) { |
| return storage_.Insert( |
| pos, IteratorValueAdapter<A, ForwardIterator>(first), |
| static_cast<size_type>(std::distance(first, last))); |
| } else { |
| return const_cast<iterator>(pos); |
| } |
| } |
| |
| // Overload of `InlinedVector::insert(...)` that inserts the range [`first`, |
| // `last`) starting at `pos`, returning an `iterator` pointing to the first |
| // of the newly inserted elements. |
| // |
| // NOTE: this overload is for iterators that are "input" category. |
| template <typename InputIterator, |
| DisableIfAtLeastForwardIterator<InputIterator> = 0> |
| iterator insert(const_iterator pos, InputIterator first, |
| InputIterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(pos >= begin()); |
| ABSL_HARDENING_ASSERT(pos <= end()); |
| |
| size_type index = static_cast<size_type>(std::distance(cbegin(), pos)); |
| for (size_type i = index; first != last; ++i, static_cast<void>(++first)) { |
| insert(data() + i, *first); |
| } |
| |
| return iterator(data() + index); |
| } |
| |
| // `InlinedVector::emplace(...)` |
| // |
| // Constructs and inserts an element using `args...` in the inlined vector at |
| // `pos`, returning an `iterator` pointing to the newly emplaced element. |
| template <typename... Args> |
| iterator emplace(const_iterator pos, |
| Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(pos >= begin()); |
| ABSL_HARDENING_ASSERT(pos <= end()); |
| |
| value_type dealias(std::forward<Args>(args)...); |
| // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2 |
| // It appears that GCC thinks that since `pos` is a const pointer and may |
| // point to uninitialized memory at this point, a warning should be |
| // issued. But `pos` is actually only used to compute an array index to |
| // write to. |
| #if !defined(__clang__) && defined(__GNUC__) |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" |
| #endif |
| return storage_.Insert(pos, |
| IteratorValueAdapter<A, MoveIterator<A>>( |
| MoveIterator<A>(std::addressof(dealias))), |
| 1); |
| #if !defined(__clang__) && defined(__GNUC__) |
| #pragma GCC diagnostic pop |
| #endif |
| } |
| |
| // `InlinedVector::emplace_back(...)` |
| // |
| // Constructs and inserts an element using `args...` in the inlined vector at |
| // `end()`, returning a `reference` to the newly emplaced element. |
| template <typename... Args> |
| reference emplace_back(Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return storage_.EmplaceBack(std::forward<Args>(args)...); |
| } |
| |
| // `InlinedVector::push_back(...)` |
| // |
| // Inserts a copy of `v` in the inlined vector at `end()`. |
| void push_back(const_reference v) { static_cast<void>(emplace_back(v)); } |
| |
| // Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()` |
| // using move semantics. |
| void push_back(value_type&& v) { |
| static_cast<void>(emplace_back(std::move(v))); |
| } |
| |
| // `InlinedVector::pop_back()` |
| // |
| // Destroys the element at `back()`, reducing the size by `1`. |
| void pop_back() noexcept { |
| ABSL_HARDENING_ASSERT(!empty()); |
| |
| AllocatorTraits<A>::destroy(storage_.GetAllocator(), data() + (size() - 1)); |
| storage_.SubtractSize(1); |
| } |
| |
| // `InlinedVector::erase(...)` |
| // |
| // Erases the element at `pos`, returning an `iterator` pointing to where the |
| // erased element was located. |
| // |
| // NOTE: may return `end()`, which is not dereferenceable. |
| iterator erase(const_iterator pos) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(pos >= begin()); |
| ABSL_HARDENING_ASSERT(pos < end()); |
| |
| // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2 |
| // It appears that GCC thinks that since `pos` is a const pointer and may |
| // point to uninitialized memory at this point, a warning should be |
| // issued. But `pos` is actually only used to compute an array index to |
| // write to. |
| #if !defined(__clang__) && defined(__GNUC__) |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" |
| #pragma GCC diagnostic ignored "-Wuninitialized" |
| #endif |
| return storage_.Erase(pos, pos + 1); |
| #if !defined(__clang__) && defined(__GNUC__) |
| #pragma GCC diagnostic pop |
| #endif |
| } |
| |
| // Overload of `InlinedVector::erase(...)` that erases every element in the |
| // range [`from`, `to`), returning an `iterator` pointing to where the first |
| // erased element was located. |
| // |
| // NOTE: may return `end()`, which is not dereferenceable. |
| iterator erase(const_iterator from, |
| const_iterator to) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| ABSL_HARDENING_ASSERT(from >= begin()); |
| ABSL_HARDENING_ASSERT(from <= to); |
| ABSL_HARDENING_ASSERT(to <= end()); |
| |
| if (ABSL_PREDICT_TRUE(from != to)) { |
| return storage_.Erase(from, to); |
| } else { |
| return const_cast<iterator>(from); |
| } |
| } |
| |
| // `InlinedVector::clear()` |
| // |
| // Destroys all elements in the inlined vector, setting the size to `0` and |
| // deallocating any held memory. |
| void clear() noexcept { |
| inlined_vector_internal::DestroyAdapter<A>::DestroyElements( |
| storage_.GetAllocator(), data(), size()); |
| storage_.DeallocateIfAllocated(); |
| |
| storage_.SetInlinedSize(0); |
| } |
| |
| // `InlinedVector::reserve(...)` |
| // |
| // Ensures that there is enough room for at least `n` elements. |
| void reserve(size_type n) { storage_.Reserve(n); } |
| |
| // `InlinedVector::shrink_to_fit()` |
| // |
| // Attempts to reduce memory usage by moving elements to (or keeping elements |
| // in) the smallest available buffer sufficient for containing `size()` |
| // elements. |
| // |
| // If `size()` is sufficiently small, the elements will be moved into (or kept |
| // in) the inlined space. |
| void shrink_to_fit() { |
| if (storage_.GetIsAllocated()) { |
| storage_.ShrinkToFit(); |
| } |
| } |
| |
| // `InlinedVector::swap(...)` |
| // |
| // Swaps the contents of the inlined vector with `other`. |
| void swap(InlinedVector& other) { |
| if (ABSL_PREDICT_TRUE(this != std::addressof(other))) { |
| storage_.Swap(std::addressof(other.storage_)); |
| } |
| } |
| |
| private: |
| template <typename H, typename TheT, size_t TheN, typename TheA> |
| friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a); |
| |
| void MoveAssignment(MemcpyPolicy, InlinedVector&& other) { |
| // Assumption check: we shouldn't be told to use memcpy to implement move |
| // assignment unless we have trivially destructible elements and an |
| // allocator that does nothing fancy. |
| static_assert(absl::is_trivially_destructible<value_type>::value, ""); |
| static_assert(std::is_same<A, std::allocator<value_type>>::value, ""); |
| |
| // Throw away our existing heap allocation, if any. There is no need to |
| // destroy the existing elements one by one because we know they are |
| // trivially destructible. |
| storage_.DeallocateIfAllocated(); |
| |
| // Adopt the other vector's inline elements or heap allocation. |
| storage_.MemcpyFrom(other.storage_); |
| other.storage_.SetInlinedSize(0); |
| } |
| |
| // Destroy our existing elements, if any, and adopt the heap-allocated |
| // elements of the other vector. |
| // |
| // REQUIRES: other.storage_.GetIsAllocated() |
| void DestroyExistingAndAdopt(InlinedVector&& other) { |
| ABSL_HARDENING_ASSERT(other.storage_.GetIsAllocated()); |
| |
| inlined_vector_internal::DestroyAdapter<A>::DestroyElements( |
| storage_.GetAllocator(), data(), size()); |
| storage_.DeallocateIfAllocated(); |
| |
| storage_.MemcpyFrom(other.storage_); |
| other.storage_.SetInlinedSize(0); |
| } |
| |
| void MoveAssignment(ElementwiseAssignPolicy, InlinedVector&& other) { |
| // Fast path: if the other vector is on the heap then we don't worry about |
| // actually move-assigning each element. Instead we only throw away our own |
| // existing elements and adopt the heap allocation of the other vector. |
| if (other.storage_.GetIsAllocated()) { |
| DestroyExistingAndAdopt(std::move(other)); |
| return; |
| } |
| |
| storage_.Assign(IteratorValueAdapter<A, MoveIterator<A>>( |
| MoveIterator<A>(other.storage_.GetInlinedData())), |
| other.size()); |
| } |
| |
| void MoveAssignment(ElementwiseConstructPolicy, InlinedVector&& other) { |
| // Fast path: if the other vector is on the heap then we don't worry about |
| // actually move-assigning each element. Instead we only throw away our own |
| // existing elements and adopt the heap allocation of the other vector. |
| if (other.storage_.GetIsAllocated()) { |
| DestroyExistingAndAdopt(std::move(other)); |
| return; |
| } |
| |
| inlined_vector_internal::DestroyAdapter<A>::DestroyElements( |
| storage_.GetAllocator(), data(), size()); |
| storage_.DeallocateIfAllocated(); |
| |
| IteratorValueAdapter<A, MoveIterator<A>> other_values( |
| MoveIterator<A>(other.storage_.GetInlinedData())); |
| inlined_vector_internal::ConstructElements<A>( |
| storage_.GetAllocator(), storage_.GetInlinedData(), other_values, |
| other.storage_.GetSize()); |
| storage_.SetInlinedSize(other.storage_.GetSize()); |
| } |
| |
| Storage storage_; |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // InlinedVector Non-Member Functions |
| // ----------------------------------------------------------------------------- |
| |
| // `swap(...)` |
| // |
| // Swaps the contents of two inlined vectors. |
| template <typename T, size_t N, typename A> |
| void swap(absl::InlinedVector<T, N, A>& a, |
| absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) { |
| a.swap(b); |
| } |
| |
| // `operator==(...)` |
| // |
| // Tests for value-equality of two inlined vectors. |
| template <typename T, size_t N, typename A> |
| bool operator==(const absl::InlinedVector<T, N, A>& a, |
| const absl::InlinedVector<T, N, A>& b) { |
| auto a_data = a.data(); |
| auto b_data = b.data(); |
| return std::equal(a_data, a_data + a.size(), b_data, b_data + b.size()); |
| } |
| |
| // `operator!=(...)` |
| // |
| // Tests for value-inequality of two inlined vectors. |
| template <typename T, size_t N, typename A> |
| bool operator!=(const absl::InlinedVector<T, N, A>& a, |
| const absl::InlinedVector<T, N, A>& b) { |
| return !(a == b); |
| } |
| |
| // `operator<(...)` |
| // |
| // Tests whether the value of an inlined vector is less than the value of |
| // another inlined vector using a lexicographical comparison algorithm. |
| template <typename T, size_t N, typename A> |
| bool operator<(const absl::InlinedVector<T, N, A>& a, |
| const absl::InlinedVector<T, N, A>& b) { |
| auto a_data = a.data(); |
| auto b_data = b.data(); |
| return std::lexicographical_compare(a_data, a_data + a.size(), b_data, |
| b_data + b.size()); |
| } |
| |
| // `operator>(...)` |
| // |
| // Tests whether the value of an inlined vector is greater than the value of |
| // another inlined vector using a lexicographical comparison algorithm. |
| template <typename T, size_t N, typename A> |
| bool operator>(const absl::InlinedVector<T, N, A>& a, |
| const absl::InlinedVector<T, N, A>& b) { |
| return b < a; |
| } |
| |
| // `operator<=(...)` |
| // |
| // Tests whether the value of an inlined vector is less than or equal to the |
| // value of another inlined vector using a lexicographical comparison algorithm. |
| template <typename T, size_t N, typename A> |
| bool operator<=(const absl::InlinedVector<T, N, A>& a, |
| const absl::InlinedVector<T, N, A>& b) { |
| return !(b < a); |
| } |
| |
| // `operator>=(...)` |
| // |
| // Tests whether the value of an inlined vector is greater than or equal to the |
| // value of another inlined vector using a lexicographical comparison algorithm. |
| template <typename T, size_t N, typename A> |
| bool operator>=(const absl::InlinedVector<T, N, A>& a, |
| const absl::InlinedVector<T, N, A>& b) { |
| return !(a < b); |
| } |
| |
| // `AbslHashValue(...)` |
| // |
| // Provides `absl::Hash` support for `absl::InlinedVector`. It is uncommon to |
| // call this directly. |
| template <typename H, typename T, size_t N, typename A> |
| H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a) { |
| auto size = a.size(); |
| return H::combine(H::combine_contiguous(std::move(h), a.data(), size), |
| hash_internal::WeaklyMixedInteger{size}); |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CONTAINER_INLINED_VECTOR_H_ |
| *q |
| soong/.intermediates/external/abseil-cpp/absl_strings_str_format_internal_hdrs/gen/my_include_dir/absl/strings/internal/str_format/extension.h
p// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ |
| #define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ |
| |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <ostream> |
| #include <string> |
| |
| #include "absl/base/config.h" |
| #include "absl/strings/internal/str_format/output.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| enum class FormatConversionChar : uint8_t; |
| enum class FormatConversionCharSet : uint64_t; |
| enum class LengthMod : std::uint8_t { h, hh, l, ll, L, j, z, t, q, none }; |
| |
| namespace str_format_internal { |
| |
| class FormatRawSinkImpl { |
| public: |
| // Implicitly convert from any type that provides the hook function as |
| // described above. |
| template <typename T, decltype(str_format_internal::InvokeFlush( |
| std::declval<T*>(), string_view()))* = nullptr> |
| FormatRawSinkImpl(T* raw) // NOLINT |
| : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {} |
| |
| void Write(string_view s) { write_(sink_, s); } |
| |
| template <typename T> |
| static FormatRawSinkImpl Extract(T s) { |
| return s.sink_; |
| } |
| |
| private: |
| template <typename T> |
| static void Flush(void* r, string_view s) { |
| str_format_internal::InvokeFlush(static_cast<T*>(r), s); |
| } |
| |
| void* sink_; |
| void (*write_)(void*, string_view); |
| }; |
| |
| // An abstraction to which conversions write their string data. |
| class FormatSinkImpl { |
| public: |
| explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {} |
| |
| ~FormatSinkImpl() { Flush(); } |
| |
| void Flush() { |
| raw_.Write(string_view(buf_, static_cast<size_t>(pos_ - buf_))); |
| pos_ = buf_; |
| } |
| |
| void Append(size_t n, char c) { |
| if (n == 0) return; |
| size_ += n; |
| auto raw_append = [&](size_t count) { |
| memset(pos_, c, count); |
| pos_ += count; |
| }; |
| while (n > Avail()) { |
| n -= Avail(); |
| if (Avail() > 0) { |
| raw_append(Avail()); |
| } |
| Flush(); |
| } |
| raw_append(n); |
| } |
| |
| void Append(string_view v) { |
| size_t n = v.size(); |
| if (n == 0) return; |
| size_ += n; |
| if (n >= Avail()) { |
| Flush(); |
| raw_.Write(v); |
| return; |
| } |
| memcpy(pos_, v.data(), n); |
| pos_ += n; |
| } |
| |
| size_t size() const { return size_; } |
| |
| // Put 'v' to 'sink' with specified width, precision, and left flag. |
| bool PutPaddedString(string_view v, int width, int precision, bool left); |
| |
| template <typename T> |
| T Wrap() { |
| return T(this); |
| } |
| |
| template <typename T> |
| static FormatSinkImpl* Extract(T* s) { |
| return s->sink_; |
| } |
| |
| private: |
| size_t Avail() const { |
| return static_cast<size_t>(buf_ + sizeof(buf_) - pos_); |
| } |
| |
| FormatRawSinkImpl raw_; |
| size_t size_ = 0; |
| char* pos_ = buf_; |
| char buf_[1024]; |
| }; |
| |
| enum class Flags : uint8_t { |
| kBasic = 0, |
| kLeft = 1 << 0, |
| kShowPos = 1 << 1, |
| kSignCol = 1 << 2, |
| kAlt = 1 << 3, |
| kZero = 1 << 4, |
| // This is not a real flag. It just exists to turn off kBasic when no other |
| // flags are set. This is for when width/precision are specified, or a length |
| // modifier affects the behavior ("%lc"). |
| kNonBasic = 1 << 5, |
| }; |
| |
| constexpr Flags operator|(Flags a, Flags b) { |
| return static_cast<Flags>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b)); |
| } |
| |
| constexpr bool FlagsContains(Flags haystack, Flags needle) { |
| return (static_cast<uint8_t>(haystack) & static_cast<uint8_t>(needle)) == |
| static_cast<uint8_t>(needle); |
| } |
| |
| std::string FlagsToString(Flags v); |
| |
| inline std::ostream& operator<<(std::ostream& os, Flags v) { |
| return os << FlagsToString(v); |
| } |
| |
| // clang-format off |
| #define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \ |
| /* text */ \ |
| X_VAL(c) X_SEP X_VAL(s) X_SEP \ |
| /* ints */ \ |
| X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \ |
| X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \ |
| /* floats */ \ |
| X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \ |
| X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \ |
| /* misc */ \ |
| X_VAL(n) X_SEP X_VAL(p) X_SEP X_VAL(v) |
| // clang-format on |
| |
| // This type should not be referenced, it exists only to provide labels |
| // internally that match the values declared in FormatConversionChar in |
| // str_format.h. This is meant to allow internal libraries to use the same |
| // declared interface type as the public interface |
| // (absl::StrFormatConversionChar) while keeping the definition in a public |
| // header. |
| // Internal libraries should use the form |
| // `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for |
| // comparisons. Use in switch statements is not recommended due to a bug in how |
| // gcc 4.9 -Wswitch handles declared but undefined enums. |
| struct FormatConversionCharInternal { |
| FormatConversionCharInternal() = delete; |
| |
| private: |
| // clang-format off |
| enum class Enum : uint8_t { |
| c, s, // text |
| d, i, o, u, x, X, // int |
| f, F, e, E, g, G, a, A, // float |
| n, p, v, // misc |
| kNone |
| }; |
| // clang-format on |
| public: |
| #define ABSL_INTERNAL_X_VAL(id) \ |
| static constexpr FormatConversionChar id = \ |
| static_cast<FormatConversionChar>(Enum::id); |
| ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) |
| #undef ABSL_INTERNAL_X_VAL |
| static constexpr FormatConversionChar kNone = |
| static_cast<FormatConversionChar>(Enum::kNone); |
| }; |
| // clang-format on |
| |
| inline FormatConversionChar FormatConversionCharFromChar(char c) { |
| switch (c) { |
| #define ABSL_INTERNAL_X_VAL(id) \ |
| case #id[0]: \ |
| return FormatConversionCharInternal::id; |
| ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) |
| #undef ABSL_INTERNAL_X_VAL |
| } |
| return FormatConversionCharInternal::kNone; |
| } |
| |
| inline bool FormatConversionCharIsUpper(FormatConversionChar c) { |
| if (c == FormatConversionCharInternal::X || |
| c == FormatConversionCharInternal::F || |
| c == FormatConversionCharInternal::E || |
| c == FormatConversionCharInternal::G || |
| c == FormatConversionCharInternal::A) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| inline bool FormatConversionCharIsFloat(FormatConversionChar c) { |
| if (c == FormatConversionCharInternal::a || |
| c == FormatConversionCharInternal::e || |
| c == FormatConversionCharInternal::f || |
| c == FormatConversionCharInternal::g || |
| c == FormatConversionCharInternal::A || |
| c == FormatConversionCharInternal::E || |
| c == FormatConversionCharInternal::F || |
| c == FormatConversionCharInternal::G) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| inline char FormatConversionCharToChar(FormatConversionChar c) { |
| if (c == FormatConversionCharInternal::kNone) { |
| return '\0'; |
| |
| #define ABSL_INTERNAL_X_VAL(e) \ |
| } else if (c == FormatConversionCharInternal::e) { \ |
| return #e[0]; |
| #define ABSL_INTERNAL_X_SEP |
| ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, |
| ABSL_INTERNAL_X_SEP) |
| } else { |
| return '\0'; |
| } |
| |
| #undef ABSL_INTERNAL_X_VAL |
| #undef ABSL_INTERNAL_X_SEP |
| } |
| |
| // The associated char. |
| inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) { |
| char c = FormatConversionCharToChar(v); |
| if (!c) c = '?'; |
| return os << c; |
| } |
| |
| struct FormatConversionSpecImplFriend; |
| |
| class FormatConversionSpecImpl { |
| public: |
| // Width and precision are not specified, no flags are set. |
| bool is_basic() const { return flags_ == Flags::kBasic; } |
| bool has_left_flag() const { return FlagsContains(flags_, Flags::kLeft); } |
| bool has_show_pos_flag() const { |
| return FlagsContains(flags_, Flags::kShowPos); |
| } |
| bool has_sign_col_flag() const { |
| return FlagsContains(flags_, Flags::kSignCol); |
| } |
| bool has_alt_flag() const { return FlagsContains(flags_, Flags::kAlt); } |
| bool has_zero_flag() const { return FlagsContains(flags_, Flags::kZero); } |
| |
| LengthMod length_mod() const { return length_mod_; } |
| |
| FormatConversionChar conversion_char() const { |
| // Keep this field first in the struct . It generates better code when |
| // accessing it when ConversionSpec is passed by value in registers. |
| static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, ""); |
| return conv_; |
| } |
| |
| void set_conversion_char(FormatConversionChar c) { conv_ = c; } |
| |
| // Returns the specified width. If width is unspecfied, it returns a negative |
| // value. |
| int width() const { return width_; } |
| // Returns the specified precision. If precision is unspecfied, it returns a |
| // negative value. |
| int precision() const { return precision_; } |
| |
| template <typename T> |
| T Wrap() { |
| return T(*this); |
| } |
| |
| private: |
| friend struct str_format_internal::FormatConversionSpecImplFriend; |
| FormatConversionChar conv_ = FormatConversionCharInternal::kNone; |
| Flags flags_; |
| LengthMod length_mod_ = LengthMod::none; |
| int width_; |
| int precision_; |
| }; |
| |
| struct FormatConversionSpecImplFriend final { |
| static void SetFlags(Flags f, FormatConversionSpecImpl* conv) { |
| conv->flags_ = f; |
| } |
| static void SetLengthMod(LengthMod l, FormatConversionSpecImpl* conv) { |
| conv->length_mod_ = l; |
| } |
| static void SetConversionChar(FormatConversionChar c, |
| FormatConversionSpecImpl* conv) { |
| conv->conv_ = c; |
| } |
| static void SetWidth(int w, FormatConversionSpecImpl* conv) { |
| conv->width_ = w; |
| } |
| static void SetPrecision(int p, FormatConversionSpecImpl* conv) { |
| conv->precision_ = p; |
| } |
| static std::string FlagsToString(const FormatConversionSpecImpl& spec) { |
| return str_format_internal::FlagsToString(spec.flags_); |
| } |
| }; |
| |
| // Type safe OR operator. |
| // We need this for two reasons: |
| // 1. operator| on enums makes them decay to integers and the result is an |
| // integer. We need the result to stay as an enum. |
| // 2. We use "enum class" which would not work even if we accepted the decay. |
| constexpr FormatConversionCharSet FormatConversionCharSetUnion( |
| FormatConversionCharSet a) { |
| return a; |
| } |
| |
| template <typename... CharSet> |
| constexpr FormatConversionCharSet FormatConversionCharSetUnion( |
| FormatConversionCharSet a, CharSet... rest) { |
| return static_cast<FormatConversionCharSet>( |
| static_cast<uint64_t>(a) | |
| static_cast<uint64_t>(FormatConversionCharSetUnion(rest...))); |
| } |
| |
| constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) { |
| return uint64_t{1} << (1 + static_cast<uint8_t>(c)); |
| } |
| |
| constexpr uint64_t FormatConversionCharToConvInt(char conv) { |
| return |
| #define ABSL_INTERNAL_CHAR_SET_CASE(c) \ |
| conv == #c[0] \ |
| ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \ |
| : |
| ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, ) |
| #undef ABSL_INTERNAL_CHAR_SET_CASE |
| conv == '*' |
| ? 1 |
| : 0; |
| } |
| |
| constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) { |
| return static_cast<FormatConversionCharSet>( |
| FormatConversionCharToConvInt(conv)); |
| } |
| |
| struct FormatConversionCharSetInternal { |
| #define ABSL_INTERNAL_CHAR_SET_CASE(c) \ |
| static constexpr FormatConversionCharSet c = \ |
| FormatConversionCharToConvValue(#c[0]); |
| ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, ) |
| #undef ABSL_INTERNAL_CHAR_SET_CASE |
| |
| // Used for width/precision '*' specification. |
| static constexpr FormatConversionCharSet kStar = |
| FormatConversionCharToConvValue('*'); |
| |
| static constexpr FormatConversionCharSet kIntegral = |
| FormatConversionCharSetUnion(d, i, u, o, x, X); |
| static constexpr FormatConversionCharSet kFloating = |
| FormatConversionCharSetUnion(a, e, f, g, A, E, F, G); |
| static constexpr FormatConversionCharSet kNumeric = |
| FormatConversionCharSetUnion(kIntegral, kFloating); |
| static constexpr FormatConversionCharSet kPointer = p; |
| }; |
| |
| // Type safe OR operator. |
| // We need this for two reasons: |
| // 1. operator| on enums makes them decay to integers and the result is an |
| // integer. We need the result to stay as an enum. |
| // 2. We use "enum class" which would not work even if we accepted the decay. |
| constexpr FormatConversionCharSet operator|(FormatConversionCharSet a, |
| FormatConversionCharSet b) { |
| return FormatConversionCharSetUnion(a, b); |
| } |
| |
| // Overloaded conversion functions to support absl::ParsedFormat. |
| // Get a conversion with a single character in it. |
| constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) { |
| return static_cast<FormatConversionCharSet>( |
| FormatConversionCharToConvValue(c)); |
| } |
| |
| // Get a conversion with a single character in it. |
| constexpr FormatConversionCharSet ToFormatConversionCharSet( |
| FormatConversionCharSet c) { |
| return c; |
| } |
| |
| template <typename T> |
| void ToFormatConversionCharSet(T) = delete; |
| |
| // Checks whether `c` exists in `set`. |
| constexpr bool Contains(FormatConversionCharSet set, char c) { |
| return (static_cast<uint64_t>(set) & |
| static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0; |
| } |
| |
| // Checks whether all the characters in `c` are contained in `set` |
| constexpr bool Contains(FormatConversionCharSet set, |
| FormatConversionCharSet c) { |
| return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) == |
| static_cast<uint64_t>(c); |
| } |
| |
| // Checks whether all the characters in `c` are contained in `set` |
| constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) { |
| return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0; |
| } |
| |
| // Return capacity - used, clipped to a minimum of 0. |
| inline size_t Excess(size_t used, size_t capacity) { |
| return used < capacity ? capacity - used : 0; |
| } |
| |
| } // namespace str_format_internal |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ |
| *²_ |
| ysoong/.intermediates/external/abseil-cpp/absl_numeric_int128_hdrs/gen/my_include_dir/absl/numeric/int128_no_intrinsic.inc´^// |
| // 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 contains :int128 implementation details that depend on internal |
| // representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file |
| // is included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined. |
| |
| constexpr uint64_t Int128Low64(int128 v) { return v.lo_; } |
| |
| constexpr int64_t Int128High64(int128 v) { return v.hi_; } |
| |
| #if defined(ABSL_IS_LITTLE_ENDIAN) |
| |
| constexpr int128::int128(int64_t high, uint64_t low) : lo_(low), hi_(high) {} |
| |
| constexpr int128::int128(int v) |
| : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {} |
| constexpr int128::int128(long v) // NOLINT(runtime/int) |
| : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {} |
| constexpr int128::int128(long long v) // NOLINT(runtime/int) |
| : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {} |
| |
| constexpr int128::int128(unsigned int v) : lo_{v}, hi_{0} {} |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr int128::int128(unsigned long v) : lo_{v}, hi_{0} {} |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr int128::int128(unsigned long long v) : lo_{v}, hi_{0} {} |
| |
| constexpr int128::int128(uint128 v) |
| : lo_{Uint128Low64(v)}, hi_{static_cast<int64_t>(Uint128High64(v))} {} |
| |
| #elif defined(ABSL_IS_BIG_ENDIAN) |
| |
| constexpr int128::int128(int64_t high, uint64_t low) : hi_{high}, lo_{low} {} |
| |
| constexpr int128::int128(int v) |
| : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {} |
| constexpr int128::int128(long v) // NOLINT(runtime/int) |
| : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {} |
| constexpr int128::int128(long long v) // NOLINT(runtime/int) |
| : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {} |
| |
| constexpr int128::int128(unsigned int v) : hi_{0}, lo_{v} {} |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr int128::int128(unsigned long v) : hi_{0}, lo_{v} {} |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr int128::int128(unsigned long long v) : hi_{0}, lo_{v} {} |
| |
| constexpr int128::int128(uint128 v) |
| : hi_{static_cast<int64_t>(Uint128High64(v))}, lo_{Uint128Low64(v)} {} |
| |
| #else // byte order |
| #error "Unsupported byte order: must be little-endian or big-endian." |
| #endif // byte order |
| |
| constexpr int128::operator bool() const { return lo_ || hi_; } |
| |
| constexpr int128::operator char() const { |
| // NOLINTNEXTLINE(runtime/int) |
| return static_cast<char>(static_cast<long long>(*this)); |
| } |
| |
| constexpr int128::operator signed char() const { |
| // NOLINTNEXTLINE(runtime/int) |
| return static_cast<signed char>(static_cast<long long>(*this)); |
| } |
| |
| constexpr int128::operator unsigned char() const { |
| return static_cast<unsigned char>(lo_); |
| } |
| |
| constexpr int128::operator char16_t() const { |
| return static_cast<char16_t>(lo_); |
| } |
| |
| constexpr int128::operator char32_t() const { |
| return static_cast<char32_t>(lo_); |
| } |
| |
| constexpr int128::operator ABSL_INTERNAL_WCHAR_T() const { |
| // NOLINTNEXTLINE(runtime/int) |
| return static_cast<ABSL_INTERNAL_WCHAR_T>(static_cast<long long>(*this)); |
| } |
| |
| constexpr int128::operator short() const { // NOLINT(runtime/int) |
| // NOLINTNEXTLINE(runtime/int) |
| return static_cast<short>(static_cast<long long>(*this)); |
| } |
| |
| constexpr int128::operator unsigned short() const { // NOLINT(runtime/int) |
| return static_cast<unsigned short>(lo_); // NOLINT(runtime/int) |
| } |
| |
| constexpr int128::operator int() const { |
| // NOLINTNEXTLINE(runtime/int) |
| return static_cast<int>(static_cast<long long>(*this)); |
| } |
| |
| constexpr int128::operator unsigned int() const { |
| return static_cast<unsigned int>(lo_); |
| } |
| |
| constexpr int128::operator long() const { // NOLINT(runtime/int) |
| // NOLINTNEXTLINE(runtime/int) |
| return static_cast<long>(static_cast<long long>(*this)); |
| } |
| |
| constexpr int128::operator unsigned long() const { // NOLINT(runtime/int) |
| return static_cast<unsigned long>(lo_); // NOLINT(runtime/int) |
| } |
| |
| constexpr int128::operator long long() const { // NOLINT(runtime/int) |
| // We don't bother checking the value of hi_. If *this < 0, lo_'s high bit |
| // must be set in order for the value to fit into a long long. Conversely, if |
| // lo_'s high bit is set, *this must be < 0 for the value to fit. |
| return int128_internal::BitCastToSigned(lo_); |
| } |
| |
| constexpr int128::operator unsigned long long() const { // NOLINT(runtime/int) |
| return static_cast<unsigned long long>(lo_); // NOLINT(runtime/int) |
| } |
| |
| inline int128::operator float() const { |
| // We must convert the absolute value and then negate as needed, because |
| // floating point types are typically sign-magnitude. Otherwise, the |
| // difference between the high and low 64 bits when interpreted as two's |
| // complement overwhelms the precision of the mantissa. |
| // |
| // Also check to make sure we don't negate Int128Min() |
| constexpr float pow_2_64 = 18446744073709551616.0f; |
| return hi_ < 0 && *this != Int128Min() |
| ? -static_cast<float>(-*this) |
| : static_cast<float>(lo_) + |
| static_cast<float>(hi_) * pow_2_64; |
| } |
| |
| inline int128::operator double() const { |
| // See comment in int128::operator float() above. |
| constexpr double pow_2_64 = 18446744073709551616.0; |
| return hi_ < 0 && *this != Int128Min() |
| ? -static_cast<double>(-*this) |
| : static_cast<double>(lo_) + |
| static_cast<double>(hi_) * pow_2_64; |
| } |
| |
| inline int128::operator long double() const { |
| // See comment in int128::operator float() above. |
| constexpr long double pow_2_64 = 18446744073709551616.0L; |
| return hi_ < 0 && *this != Int128Min() |
| ? -static_cast<long double>(-*this) |
| : static_cast<long double>(lo_) + |
| static_cast<long double>(hi_) * pow_2_64; |
| } |
| |
| // Comparison operators. |
| |
| constexpr bool operator==(int128 lhs, int128 rhs) { |
| return (Int128Low64(lhs) == Int128Low64(rhs) && |
| Int128High64(lhs) == Int128High64(rhs)); |
| } |
| |
| constexpr bool operator!=(int128 lhs, int128 rhs) { return !(lhs == rhs); } |
| |
| constexpr bool operator<(int128 lhs, int128 rhs) { |
| return (Int128High64(lhs) == Int128High64(rhs)) |
| ? (Int128Low64(lhs) < Int128Low64(rhs)) |
| : (Int128High64(lhs) < Int128High64(rhs)); |
| } |
| |
| constexpr bool operator>(int128 lhs, int128 rhs) { |
| return (Int128High64(lhs) == Int128High64(rhs)) |
| ? (Int128Low64(lhs) > Int128Low64(rhs)) |
| : (Int128High64(lhs) > Int128High64(rhs)); |
| } |
| |
| constexpr bool operator<=(int128 lhs, int128 rhs) { return !(lhs > rhs); } |
| |
| constexpr bool operator>=(int128 lhs, int128 rhs) { return !(lhs < rhs); } |
| |
| #ifdef __cpp_impl_three_way_comparison |
| constexpr absl::strong_ordering operator<=>(int128 lhs, int128 rhs) { |
| if (int64_t lhs_high = Int128High64(lhs), rhs_high = Int128High64(rhs); |
| lhs_high < rhs_high) { |
| return absl::strong_ordering::less; |
| } else if (lhs_high > rhs_high) { |
| return absl::strong_ordering::greater; |
| } else if (uint64_t lhs_low = Uint128Low64(lhs), rhs_low = Uint128Low64(rhs); |
| lhs_low < rhs_low) { |
| return absl::strong_ordering::less; |
| } else if (lhs_low > rhs_low) { |
| return absl::strong_ordering::greater; |
| } else { |
| return absl::strong_ordering::equal; |
| } |
| } |
| #endif |
| |
| // Unary operators. |
| |
| constexpr int128 operator-(int128 v) { |
| return MakeInt128(~Int128High64(v) + (Int128Low64(v) == 0), |
| ~Int128Low64(v) + 1); |
| } |
| |
| constexpr bool operator!(int128 v) { |
| return !Int128Low64(v) && !Int128High64(v); |
| } |
| |
| constexpr int128 operator~(int128 val) { |
| return MakeInt128(~Int128High64(val), ~Int128Low64(val)); |
| } |
| |
| // Arithmetic operators. |
| |
| namespace int128_internal { |
| constexpr int128 SignedAddResult(int128 result, int128 lhs) { |
| // check for carry |
| return (Int128Low64(result) < Int128Low64(lhs)) |
| ? MakeInt128(Int128High64(result) + 1, Int128Low64(result)) |
| : result; |
| } |
| } // namespace int128_internal |
| constexpr int128 operator+(int128 lhs, int128 rhs) { |
| return int128_internal::SignedAddResult( |
| MakeInt128(Int128High64(lhs) + Int128High64(rhs), |
| Int128Low64(lhs) + Int128Low64(rhs)), |
| lhs); |
| } |
| |
| namespace int128_internal { |
| constexpr int128 SignedSubstructResult(int128 result, int128 lhs, int128 rhs) { |
| // check for carry |
| return (Int128Low64(lhs) < Int128Low64(rhs)) |
| ? MakeInt128(Int128High64(result) - 1, Int128Low64(result)) |
| : result; |
| } |
| } // namespace int128_internal |
| constexpr int128 operator-(int128 lhs, int128 rhs) { |
| return int128_internal::SignedSubstructResult( |
| MakeInt128(Int128High64(lhs) - Int128High64(rhs), |
| Int128Low64(lhs) - Int128Low64(rhs)), |
| lhs, rhs); |
| } |
| |
| inline int128 operator*(int128 lhs, int128 rhs) { |
| return MakeInt128( |
| int128_internal::BitCastToSigned(Uint128High64(uint128(lhs) * rhs)), |
| Uint128Low64(uint128(lhs) * rhs)); |
| } |
| |
| inline int128 int128::operator++(int) { |
| int128 tmp(*this); |
| *this += 1; |
| return tmp; |
| } |
| |
| inline int128 int128::operator--(int) { |
| int128 tmp(*this); |
| *this -= 1; |
| return tmp; |
| } |
| |
| inline int128& int128::operator++() { |
| *this += 1; |
| return *this; |
| } |
| |
| inline int128& int128::operator--() { |
| *this -= 1; |
| return *this; |
| } |
| |
| constexpr int128 operator|(int128 lhs, int128 rhs) { |
| return MakeInt128(Int128High64(lhs) | Int128High64(rhs), |
| Int128Low64(lhs) | Int128Low64(rhs)); |
| } |
| |
| constexpr int128 operator&(int128 lhs, int128 rhs) { |
| return MakeInt128(Int128High64(lhs) & Int128High64(rhs), |
| Int128Low64(lhs) & Int128Low64(rhs)); |
| } |
| |
| constexpr int128 operator^(int128 lhs, int128 rhs) { |
| return MakeInt128(Int128High64(lhs) ^ Int128High64(rhs), |
| Int128Low64(lhs) ^ Int128Low64(rhs)); |
| } |
| |
| constexpr int128 operator<<(int128 lhs, int amount) { |
| // int64_t shifts of >= 63 are undefined, so we need some special-casing. |
| assert(amount >= 0 && amount < 127); |
| if (amount <= 0) { |
| return lhs; |
| } else if (amount < 63) { |
| return MakeInt128( |
| (Int128High64(lhs) << amount) | |
| static_cast<int64_t>(Int128Low64(lhs) >> (64 - amount)), |
| Int128Low64(lhs) << amount); |
| } else if (amount == 63) { |
| return MakeInt128(((Int128High64(lhs) << 32) << 31) | |
| static_cast<int64_t>(Int128Low64(lhs) >> 1), |
| (Int128Low64(lhs) << 32) << 31); |
| } else if (amount == 127) { |
| return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << 63), 0); |
| } else if (amount > 127) { |
| return MakeInt128(0, 0); |
| } else { |
| // amount >= 64 && amount < 127 |
| return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << (amount - 64)), |
| 0); |
| } |
| } |
| |
| constexpr int128 operator>>(int128 lhs, int amount) { |
| // int64_t shifts of >= 63 are undefined, so we need some special-casing. |
| assert(amount >= 0 && amount < 127); |
| if (amount <= 0) { |
| return lhs; |
| } else if (amount < 63) { |
| return MakeInt128( |
| Int128High64(lhs) >> amount, |
| Int128Low64(lhs) >> amount | static_cast<uint64_t>(Int128High64(lhs)) |
| << (64 - amount)); |
| } else if (amount == 63) { |
| return MakeInt128((Int128High64(lhs) >> 32) >> 31, |
| static_cast<uint64_t>(Int128High64(lhs) << 1) | |
| (Int128Low64(lhs) >> 32) >> 31); |
| |
| } else if (amount >= 127) { |
| return MakeInt128((Int128High64(lhs) >> 32) >> 31, |
| static_cast<uint64_t>((Int128High64(lhs) >> 32) >> 31)); |
| } else { |
| // amount >= 64 && amount < 127 |
| return MakeInt128( |
| (Int128High64(lhs) >> 32) >> 31, |
| static_cast<uint64_t>(Int128High64(lhs) >> (amount - 64))); |
| } |
| } |
| *õ» |
| jsoong/.intermediates/external/abseil-cpp/absl_numeric_int128_hdrs/gen/my_include_dir/absl/numeric/int128.h
»// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: int128.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines 128-bit integer types, `uint128` and `int128`. |
| // |
| // TODO(absl-team): This module is inconsistent as many inline `uint128` methods |
| // are defined in this file, while many inline `int128` methods are defined in |
| // the `int128_*_intrinsic.inc` files. |
| |
| #ifndef ABSL_NUMERIC_INT128_H_ |
| #define ABSL_NUMERIC_INT128_H_ |
| |
| #include <cassert> |
| #include <cmath> |
| #include <cstdint> |
| #include <cstring> |
| #include <iosfwd> |
| #include <limits> |
| #include <string> |
| #include <utility> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/port.h" |
| #include "absl/types/compare.h" |
| |
| #if defined(_MSC_VER) |
| // In very old versions of MSVC and when the /Zc:wchar_t flag is off, wchar_t is |
| // a typedef for unsigned short. Otherwise wchar_t is mapped to the __wchar_t |
| // builtin type. We need to make sure not to define operator wchar_t() |
| // alongside operator unsigned short() in these instances. |
| #define ABSL_INTERNAL_WCHAR_T __wchar_t |
| #if defined(_M_X64) && !defined(_M_ARM64EC) |
| #include <intrin.h> |
| #pragma intrinsic(_umul128) |
| #endif // defined(_M_X64) |
| #else // defined(_MSC_VER) |
| #define ABSL_INTERNAL_WCHAR_T wchar_t |
| #endif // defined(_MSC_VER) |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| class int128; |
| |
| // uint128 |
| // |
| // An unsigned 128-bit integer type. The API is meant to mimic an intrinsic type |
| // as closely as is practical, including exhibiting undefined behavior in |
| // analogous cases (e.g. division by zero). This type is intended to be a |
| // drop-in replacement once C++ supports an intrinsic `uint128_t` type; when |
| // that occurs, existing well-behaved uses of `uint128` will continue to work |
| // using that new type. |
| // |
| // Note: code written with this type will continue to compile once `uint128_t` |
| // is introduced, provided the replacement helper functions |
| // `Uint128(Low|High)64()` and `MakeUint128()` are made. |
| // |
| // A `uint128` supports the following: |
| // |
| // * Implicit construction from integral types |
| // * Explicit conversion to integral types |
| // |
| // Additionally, if your compiler supports `__int128`, `uint128` is |
| // interoperable with that type. (Abseil checks for this compatibility through |
| // the `ABSL_HAVE_INTRINSIC_INT128` macro.) |
| // |
| // However, a `uint128` differs from intrinsic integral types in the following |
| // ways: |
| // |
| // * Errors on implicit conversions that do not preserve value (such as |
| // loss of precision when converting to float values). |
| // * Requires explicit construction from and conversion to floating point |
| // types. |
| // * Conversion to integral types requires an explicit static_cast() to |
| // mimic use of the `-Wnarrowing` compiler flag. |
| // * The alignment requirement of `uint128` may differ from that of an |
| // intrinsic 128-bit integer type depending on platform and build |
| // configuration. |
| // |
| // Example: |
| // |
| // float y = absl::Uint128Max(); // Error. uint128 cannot be implicitly |
| // // converted to float. |
| // |
| // absl::uint128 v; |
| // uint64_t i = v; // Error |
| // uint64_t i = static_cast<uint64_t>(v); // OK |
| // |
| class |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| alignas(unsigned __int128) |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| uint128 { |
| public: |
| uint128() = default; |
| |
| // Constructors from arithmetic types |
| constexpr uint128(int v); // NOLINT(runtime/explicit) |
| constexpr uint128(unsigned int v); // NOLINT(runtime/explicit) |
| constexpr uint128(long v); // NOLINT(runtime/int) |
| constexpr uint128(unsigned long v); // NOLINT(runtime/int) |
| constexpr uint128(long long v); // NOLINT(runtime/int) |
| constexpr uint128(unsigned long long v); // NOLINT(runtime/int) |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| constexpr uint128(__int128 v); // NOLINT(runtime/explicit) |
| constexpr uint128(unsigned __int128 v); // NOLINT(runtime/explicit) |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| constexpr uint128(int128 v); // NOLINT(runtime/explicit) |
| explicit uint128(float v); |
| explicit uint128(double v); |
| explicit uint128(long double v); |
| |
| // Assignment operators from arithmetic types |
| uint128& operator=(int v); |
| uint128& operator=(unsigned int v); |
| uint128& operator=(long v); // NOLINT(runtime/int) |
| uint128& operator=(unsigned long v); // NOLINT(runtime/int) |
| uint128& operator=(long long v); // NOLINT(runtime/int) |
| uint128& operator=(unsigned long long v); // NOLINT(runtime/int) |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| uint128& operator=(__int128 v); |
| uint128& operator=(unsigned __int128 v); |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| uint128& operator=(int128 v); |
| |
| // Conversion operators to other arithmetic types |
| constexpr explicit operator bool() const; |
| constexpr explicit operator char() const; |
| constexpr explicit operator signed char() const; |
| constexpr explicit operator unsigned char() const; |
| constexpr explicit operator char16_t() const; |
| constexpr explicit operator char32_t() const; |
| constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const; |
| constexpr explicit operator short() const; // NOLINT(runtime/int) |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr explicit operator unsigned short() const; |
| constexpr explicit operator int() const; |
| constexpr explicit operator unsigned int() const; |
| constexpr explicit operator long() const; // NOLINT(runtime/int) |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr explicit operator unsigned long() const; |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr explicit operator long long() const; |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr explicit operator unsigned long long() const; |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| constexpr explicit operator __int128() const; |
| constexpr explicit operator unsigned __int128() const; |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| explicit operator float() const; |
| explicit operator double() const; |
| explicit operator long double() const; |
| |
| // Trivial copy constructor, assignment operator and destructor. |
| |
| // Arithmetic operators. |
| uint128& operator+=(uint128 other); |
| uint128& operator-=(uint128 other); |
| uint128& operator*=(uint128 other); |
| // Long division/modulo for uint128. |
| uint128& operator/=(uint128 other); |
| uint128& operator%=(uint128 other); |
| uint128 operator++(int); |
| uint128 operator--(int); |
| uint128& operator<<=(int); |
| uint128& operator>>=(int); |
| uint128& operator&=(uint128 other); |
| uint128& operator|=(uint128 other); |
| uint128& operator^=(uint128 other); |
| uint128& operator++(); |
| uint128& operator--(); |
| |
| // Uint128Low64() |
| // |
| // Returns the lower 64-bit value of a `uint128` value. |
| friend constexpr uint64_t Uint128Low64(uint128 v); |
| |
| // Uint128High64() |
| // |
| // Returns the higher 64-bit value of a `uint128` value. |
| friend constexpr uint64_t Uint128High64(uint128 v); |
| |
| // MakeUInt128() |
| // |
| // Constructs a `uint128` numeric value from two 64-bit unsigned integers. |
| // Note that this factory function is the only way to construct a `uint128` |
| // from integer values greater than 2^64. |
| // |
| // Example: |
| // |
| // absl::uint128 big = absl::MakeUint128(1, 0); |
| friend constexpr uint128 MakeUint128(uint64_t high, uint64_t low); |
| |
| // Uint128Max() |
| // |
| // Returns the highest value for a 128-bit unsigned integer. |
| friend constexpr uint128 Uint128Max(); |
| |
| // Support for absl::Hash. |
| template <typename H> |
| friend H AbslHashValue(H h, uint128 v) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| return H::combine(std::move(h), static_cast<unsigned __int128>(v)); |
| #else |
| return H::combine(std::move(h), Uint128High64(v), Uint128Low64(v)); |
| #endif |
| } |
| |
| // Support for absl::StrCat() etc. |
| template <typename Sink> |
| friend void AbslStringify(Sink& sink, uint128 v) { |
| sink.Append(v.ToString()); |
| } |
| |
| private: |
| constexpr uint128(uint64_t high, uint64_t low); |
| |
| std::string ToString() const; |
| |
| // TODO(strel) Update implementation to use __int128 once all users of |
| // uint128 are fixed to not depend on alignof(uint128) == 8. Also add |
| // alignas(16) to class definition to keep alignment consistent across |
| // platforms. |
| #if defined(ABSL_IS_LITTLE_ENDIAN) |
| uint64_t lo_; |
| uint64_t hi_; |
| #elif defined(ABSL_IS_BIG_ENDIAN) |
| uint64_t hi_; |
| uint64_t lo_; |
| #else // byte order |
| #error "Unsupported byte order: must be little-endian or big-endian." |
| #endif // byte order |
| }; |
| |
| // allow uint128 to be logged |
| std::ostream& operator<<(std::ostream& os, uint128 v); |
| |
| // TODO(strel) add operator>>(std::istream&, uint128) |
| |
| constexpr uint128 Uint128Max() { |
| return uint128((std::numeric_limits<uint64_t>::max)(), |
| (std::numeric_limits<uint64_t>::max)()); |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| // Specialized numeric_limits for uint128. |
| namespace std { |
| template <> |
| class numeric_limits<absl::uint128> { |
| public: |
| static constexpr bool is_specialized = true; |
| static constexpr bool is_signed = false; |
| static constexpr bool is_integer = true; |
| static constexpr bool is_exact = true; |
| static constexpr bool has_infinity = false; |
| static constexpr bool has_quiet_NaN = false; |
| static constexpr bool has_signaling_NaN = false; |
| ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING |
| static constexpr float_denorm_style has_denorm = denorm_absent; |
| ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING |
| static constexpr bool has_denorm_loss = false; |
| static constexpr float_round_style round_style = round_toward_zero; |
| static constexpr bool is_iec559 = false; |
| static constexpr bool is_bounded = true; |
| static constexpr bool is_modulo = true; |
| static constexpr int digits = 128; |
| static constexpr int digits10 = 38; |
| static constexpr int max_digits10 = 0; |
| static constexpr int radix = 2; |
| static constexpr int min_exponent = 0; |
| static constexpr int min_exponent10 = 0; |
| static constexpr int max_exponent = 0; |
| static constexpr int max_exponent10 = 0; |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| static constexpr bool traps = numeric_limits<unsigned __int128>::traps; |
| #else // ABSL_HAVE_INTRINSIC_INT128 |
| static constexpr bool traps = numeric_limits<uint64_t>::traps; |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| static constexpr bool tinyness_before = false; |
| |
| static constexpr absl::uint128(min)() { return 0; } |
| static constexpr absl::uint128 lowest() { return 0; } |
| static constexpr absl::uint128(max)() { return absl::Uint128Max(); } |
| static constexpr absl::uint128 epsilon() { return 0; } |
| static constexpr absl::uint128 round_error() { return 0; } |
| static constexpr absl::uint128 infinity() { return 0; } |
| static constexpr absl::uint128 quiet_NaN() { return 0; } |
| static constexpr absl::uint128 signaling_NaN() { return 0; } |
| static constexpr absl::uint128 denorm_min() { return 0; } |
| }; |
| } // namespace std |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // int128 |
| // |
| // A signed 128-bit integer type. The API is meant to mimic an intrinsic |
| // integral type as closely as is practical, including exhibiting undefined |
| // behavior in analogous cases (e.g. division by zero). |
| // |
| // An `int128` supports the following: |
| // |
| // * Implicit construction from integral types |
| // * Explicit conversion to integral types |
| // |
| // However, an `int128` differs from intrinsic integral types in the following |
| // ways: |
| // |
| // * It is not implicitly convertible to other integral types. |
| // * Requires explicit construction from and conversion to floating point |
| // types. |
| |
| // Additionally, if your compiler supports `__int128`, `int128` is |
| // interoperable with that type. (Abseil checks for this compatibility through |
| // the `ABSL_HAVE_INTRINSIC_INT128` macro.) |
| // |
| // The design goal for `int128` is that it will be compatible with a future |
| // `int128_t`, if that type becomes a part of the standard. |
| // |
| // Example: |
| // |
| // float y = absl::int128(17); // Error. int128 cannot be implicitly |
| // // converted to float. |
| // |
| // absl::int128 v; |
| // int64_t i = v; // Error |
| // int64_t i = static_cast<int64_t>(v); // OK |
| // |
| class int128 { |
| public: |
| int128() = default; |
| |
| // Constructors from arithmetic types |
| constexpr int128(int v); // NOLINT(runtime/explicit) |
| constexpr int128(unsigned int v); // NOLINT(runtime/explicit) |
| constexpr int128(long v); // NOLINT(runtime/int) |
| constexpr int128(unsigned long v); // NOLINT(runtime/int) |
| constexpr int128(long long v); // NOLINT(runtime/int) |
| constexpr int128(unsigned long long v); // NOLINT(runtime/int) |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| constexpr int128(__int128 v); // NOLINT(runtime/explicit) |
| constexpr explicit int128(unsigned __int128 v); |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| constexpr explicit int128(uint128 v); |
| explicit int128(float v); |
| explicit int128(double v); |
| explicit int128(long double v); |
| |
| // Assignment operators from arithmetic types |
| int128& operator=(int v); |
| int128& operator=(unsigned int v); |
| int128& operator=(long v); // NOLINT(runtime/int) |
| int128& operator=(unsigned long v); // NOLINT(runtime/int) |
| int128& operator=(long long v); // NOLINT(runtime/int) |
| int128& operator=(unsigned long long v); // NOLINT(runtime/int) |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| int128& operator=(__int128 v); |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| |
| // Conversion operators to other arithmetic types |
| constexpr explicit operator bool() const; |
| constexpr explicit operator char() const; |
| constexpr explicit operator signed char() const; |
| constexpr explicit operator unsigned char() const; |
| constexpr explicit operator char16_t() const; |
| constexpr explicit operator char32_t() const; |
| constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const; |
| constexpr explicit operator short() const; // NOLINT(runtime/int) |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr explicit operator unsigned short() const; |
| constexpr explicit operator int() const; |
| constexpr explicit operator unsigned int() const; |
| constexpr explicit operator long() const; // NOLINT(runtime/int) |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr explicit operator unsigned long() const; |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr explicit operator long long() const; |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr explicit operator unsigned long long() const; |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| constexpr explicit operator __int128() const; |
| constexpr explicit operator unsigned __int128() const; |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| explicit operator float() const; |
| explicit operator double() const; |
| explicit operator long double() const; |
| |
| // Trivial copy constructor, assignment operator and destructor. |
| |
| // Arithmetic operators |
| int128& operator+=(int128 other); |
| int128& operator-=(int128 other); |
| int128& operator*=(int128 other); |
| int128& operator/=(int128 other); |
| int128& operator%=(int128 other); |
| int128 operator++(int); // postfix increment: i++ |
| int128 operator--(int); // postfix decrement: i-- |
| int128& operator++(); // prefix increment: ++i |
| int128& operator--(); // prefix decrement: --i |
| int128& operator&=(int128 other); |
| int128& operator|=(int128 other); |
| int128& operator^=(int128 other); |
| int128& operator<<=(int amount); |
| int128& operator>>=(int amount); |
| |
| // Int128Low64() |
| // |
| // Returns the lower 64-bit value of a `int128` value. |
| friend constexpr uint64_t Int128Low64(int128 v); |
| |
| // Int128High64() |
| // |
| // Returns the higher 64-bit value of a `int128` value. |
| friend constexpr int64_t Int128High64(int128 v); |
| |
| // MakeInt128() |
| // |
| // Constructs a `int128` numeric value from two 64-bit integers. Note that |
| // signedness is conveyed in the upper `high` value. |
| // |
| // (absl::int128(1) << 64) * high + low |
| // |
| // Note that this factory function is the only way to construct a `int128` |
| // from integer values greater than 2^64 or less than -2^64. |
| // |
| // Example: |
| // |
| // absl::int128 big = absl::MakeInt128(1, 0); |
| // absl::int128 big_n = absl::MakeInt128(-1, 0); |
| friend constexpr int128 MakeInt128(int64_t high, uint64_t low); |
| |
| // Int128Max() |
| // |
| // Returns the maximum value for a 128-bit signed integer. |
| friend constexpr int128 Int128Max(); |
| |
| // Int128Min() |
| // |
| // Returns the minimum value for a 128-bit signed integer. |
| friend constexpr int128 Int128Min(); |
| |
| // Support for absl::Hash. |
| template <typename H> |
| friend H AbslHashValue(H h, int128 v) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| return H::combine(std::move(h), v.v_); |
| #else |
| return H::combine(std::move(h), Int128High64(v), Int128Low64(v)); |
| #endif |
| } |
| |
| // Support for absl::StrCat() etc. |
| template <typename Sink> |
| friend void AbslStringify(Sink& sink, int128 v) { |
| sink.Append(v.ToString()); |
| } |
| |
| private: |
| constexpr int128(int64_t high, uint64_t low); |
| |
| std::string ToString() const; |
| |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| __int128 v_; |
| #else // ABSL_HAVE_INTRINSIC_INT128 |
| #if defined(ABSL_IS_LITTLE_ENDIAN) |
| uint64_t lo_; |
| int64_t hi_; |
| #elif defined(ABSL_IS_BIG_ENDIAN) |
| int64_t hi_; |
| uint64_t lo_; |
| #else // byte order |
| #error "Unsupported byte order: must be little-endian or big-endian." |
| #endif // byte order |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| }; |
| |
| std::ostream& operator<<(std::ostream& os, int128 v); |
| |
| // TODO(absl-team) add operator>>(std::istream&, int128) |
| |
| constexpr int128 Int128Max() { |
| return int128((std::numeric_limits<int64_t>::max)(), |
| (std::numeric_limits<uint64_t>::max)()); |
| } |
| |
| constexpr int128 Int128Min() { |
| return int128((std::numeric_limits<int64_t>::min)(), 0); |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| // Specialized numeric_limits for int128. |
| namespace std { |
| template <> |
| class numeric_limits<absl::int128> { |
| public: |
| static constexpr bool is_specialized = true; |
| static constexpr bool is_signed = true; |
| static constexpr bool is_integer = true; |
| static constexpr bool is_exact = true; |
| static constexpr bool has_infinity = false; |
| static constexpr bool has_quiet_NaN = false; |
| static constexpr bool has_signaling_NaN = false; |
| ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING |
| static constexpr float_denorm_style has_denorm = denorm_absent; |
| ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING |
| static constexpr bool has_denorm_loss = false; |
| static constexpr float_round_style round_style = round_toward_zero; |
| static constexpr bool is_iec559 = false; |
| static constexpr bool is_bounded = true; |
| static constexpr bool is_modulo = false; |
| static constexpr int digits = 127; |
| static constexpr int digits10 = 38; |
| static constexpr int max_digits10 = 0; |
| static constexpr int radix = 2; |
| static constexpr int min_exponent = 0; |
| static constexpr int min_exponent10 = 0; |
| static constexpr int max_exponent = 0; |
| static constexpr int max_exponent10 = 0; |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| static constexpr bool traps = numeric_limits<__int128>::traps; |
| #else // ABSL_HAVE_INTRINSIC_INT128 |
| static constexpr bool traps = numeric_limits<uint64_t>::traps; |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| static constexpr bool tinyness_before = false; |
| |
| static constexpr absl::int128(min)() { return absl::Int128Min(); } |
| static constexpr absl::int128 lowest() { return absl::Int128Min(); } |
| static constexpr absl::int128(max)() { return absl::Int128Max(); } |
| static constexpr absl::int128 epsilon() { return 0; } |
| static constexpr absl::int128 round_error() { return 0; } |
| static constexpr absl::int128 infinity() { return 0; } |
| static constexpr absl::int128 quiet_NaN() { return 0; } |
| static constexpr absl::int128 signaling_NaN() { return 0; } |
| static constexpr absl::int128 denorm_min() { return 0; } |
| }; |
| } // namespace std |
| |
| // -------------------------------------------------------------------------- |
| // Implementation details follow |
| // -------------------------------------------------------------------------- |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| constexpr uint128 MakeUint128(uint64_t high, uint64_t low) { |
| return uint128(high, low); |
| } |
| |
| // Assignment from integer types. |
| |
| inline uint128& uint128::operator=(int v) { return *this = uint128(v); } |
| |
| inline uint128& uint128::operator=(unsigned int v) { |
| return *this = uint128(v); |
| } |
| |
| inline uint128& uint128::operator=(long v) { // NOLINT(runtime/int) |
| return *this = uint128(v); |
| } |
| |
| // NOLINTNEXTLINE(runtime/int) |
| inline uint128& uint128::operator=(unsigned long v) { |
| return *this = uint128(v); |
| } |
| |
| // NOLINTNEXTLINE(runtime/int) |
| inline uint128& uint128::operator=(long long v) { return *this = uint128(v); } |
| |
| // NOLINTNEXTLINE(runtime/int) |
| inline uint128& uint128::operator=(unsigned long long v) { |
| return *this = uint128(v); |
| } |
| |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| inline uint128& uint128::operator=(__int128 v) { return *this = uint128(v); } |
| |
| inline uint128& uint128::operator=(unsigned __int128 v) { |
| return *this = uint128(v); |
| } |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| |
| inline uint128& uint128::operator=(int128 v) { return *this = uint128(v); } |
| |
| // Arithmetic operators. |
| |
| constexpr uint128 operator<<(uint128 lhs, int amount); |
| constexpr uint128 operator>>(uint128 lhs, int amount); |
| constexpr uint128 operator+(uint128 lhs, uint128 rhs); |
| constexpr uint128 operator-(uint128 lhs, uint128 rhs); |
| uint128 operator*(uint128 lhs, uint128 rhs); |
| uint128 operator/(uint128 lhs, uint128 rhs); |
| uint128 operator%(uint128 lhs, uint128 rhs); |
| |
| inline uint128& uint128::operator<<=(int amount) { |
| *this = *this << amount; |
| return *this; |
| } |
| |
| inline uint128& uint128::operator>>=(int amount) { |
| *this = *this >> amount; |
| return *this; |
| } |
| |
| inline uint128& uint128::operator+=(uint128 other) { |
| *this = *this + other; |
| return *this; |
| } |
| |
| inline uint128& uint128::operator-=(uint128 other) { |
| *this = *this - other; |
| return *this; |
| } |
| |
| inline uint128& uint128::operator*=(uint128 other) { |
| *this = *this * other; |
| return *this; |
| } |
| |
| inline uint128& uint128::operator/=(uint128 other) { |
| *this = *this / other; |
| return *this; |
| } |
| |
| inline uint128& uint128::operator%=(uint128 other) { |
| *this = *this % other; |
| return *this; |
| } |
| |
| constexpr uint64_t Uint128Low64(uint128 v) { return v.lo_; } |
| |
| constexpr uint64_t Uint128High64(uint128 v) { return v.hi_; } |
| |
| // Constructors from integer types. |
| |
| #if defined(ABSL_IS_LITTLE_ENDIAN) |
| |
| constexpr uint128::uint128(uint64_t high, uint64_t low) : lo_{low}, hi_{high} {} |
| |
| constexpr uint128::uint128(int v) |
| : lo_{static_cast<uint64_t>(v)}, |
| hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {} |
| constexpr uint128::uint128(long v) // NOLINT(runtime/int) |
| : lo_{static_cast<uint64_t>(v)}, |
| hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {} |
| constexpr uint128::uint128(long long v) // NOLINT(runtime/int) |
| : lo_{static_cast<uint64_t>(v)}, |
| hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {} |
| |
| constexpr uint128::uint128(unsigned int v) : lo_{v}, hi_{0} {} |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr uint128::uint128(unsigned long v) : lo_{v}, hi_{0} {} |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr uint128::uint128(unsigned long long v) : lo_{v}, hi_{0} {} |
| |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| constexpr uint128::uint128(__int128 v) |
| : lo_{static_cast<uint64_t>(v & ~uint64_t{0})}, |
| hi_{static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)} {} |
| constexpr uint128::uint128(unsigned __int128 v) |
| : lo_{static_cast<uint64_t>(v & ~uint64_t{0})}, |
| hi_{static_cast<uint64_t>(v >> 64)} {} |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| |
| constexpr uint128::uint128(int128 v) |
| : lo_{Int128Low64(v)}, hi_{static_cast<uint64_t>(Int128High64(v))} {} |
| |
| #elif defined(ABSL_IS_BIG_ENDIAN) |
| |
| constexpr uint128::uint128(uint64_t high, uint64_t low) : hi_{high}, lo_{low} {} |
| |
| constexpr uint128::uint128(int v) |
| : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0}, |
| lo_{static_cast<uint64_t>(v)} {} |
| constexpr uint128::uint128(long v) // NOLINT(runtime/int) |
| : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0}, |
| lo_{static_cast<uint64_t>(v)} {} |
| constexpr uint128::uint128(long long v) // NOLINT(runtime/int) |
| : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0}, |
| lo_{static_cast<uint64_t>(v)} {} |
| |
| constexpr uint128::uint128(unsigned int v) : hi_{0}, lo_{v} {} |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr uint128::uint128(unsigned long v) : hi_{0}, lo_{v} {} |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr uint128::uint128(unsigned long long v) : hi_{0}, lo_{v} {} |
| |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| constexpr uint128::uint128(__int128 v) |
| : hi_{static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)}, |
| lo_{static_cast<uint64_t>(v & ~uint64_t{0})} {} |
| constexpr uint128::uint128(unsigned __int128 v) |
| : hi_{static_cast<uint64_t>(v >> 64)}, |
| lo_{static_cast<uint64_t>(v & ~uint64_t{0})} {} |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| |
| constexpr uint128::uint128(int128 v) |
| : hi_{static_cast<uint64_t>(Int128High64(v))}, lo_{Int128Low64(v)} {} |
| |
| #else // byte order |
| #error "Unsupported byte order: must be little-endian or big-endian." |
| #endif // byte order |
| |
| // Conversion operators to integer types. |
| |
| constexpr uint128::operator bool() const { return lo_ || hi_; } |
| |
| constexpr uint128::operator char() const { return static_cast<char>(lo_); } |
| |
| constexpr uint128::operator signed char() const { |
| return static_cast<signed char>(lo_); |
| } |
| |
| constexpr uint128::operator unsigned char() const { |
| return static_cast<unsigned char>(lo_); |
| } |
| |
| constexpr uint128::operator char16_t() const { |
| return static_cast<char16_t>(lo_); |
| } |
| |
| constexpr uint128::operator char32_t() const { |
| return static_cast<char32_t>(lo_); |
| } |
| |
| constexpr uint128::operator ABSL_INTERNAL_WCHAR_T() const { |
| return static_cast<ABSL_INTERNAL_WCHAR_T>(lo_); |
| } |
| |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr uint128::operator short() const { return static_cast<short>(lo_); } |
| |
| constexpr uint128::operator unsigned short() const { // NOLINT(runtime/int) |
| return static_cast<unsigned short>(lo_); // NOLINT(runtime/int) |
| } |
| |
| constexpr uint128::operator int() const { return static_cast<int>(lo_); } |
| |
| constexpr uint128::operator unsigned int() const { |
| return static_cast<unsigned int>(lo_); |
| } |
| |
| // NOLINTNEXTLINE(runtime/int) |
| constexpr uint128::operator long() const { return static_cast<long>(lo_); } |
| |
| constexpr uint128::operator unsigned long() const { // NOLINT(runtime/int) |
| return static_cast<unsigned long>(lo_); // NOLINT(runtime/int) |
| } |
| |
| constexpr uint128::operator long long() const { // NOLINT(runtime/int) |
| return static_cast<long long>(lo_); // NOLINT(runtime/int) |
| } |
| |
| constexpr uint128::operator unsigned long long() const { // NOLINT(runtime/int) |
| return static_cast<unsigned long long>(lo_); // NOLINT(runtime/int) |
| } |
| |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| constexpr uint128::operator __int128() const { |
| return (static_cast<__int128>(hi_) << 64) + lo_; |
| } |
| |
| constexpr uint128::operator unsigned __int128() const { |
| return (static_cast<unsigned __int128>(hi_) << 64) + lo_; |
| } |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| |
| // Conversion operators to floating point types. |
| |
| inline uint128::operator float() const { |
| // Note: This method might return Inf. |
| constexpr float pow_2_64 = 18446744073709551616.0f; |
| return static_cast<float>(lo_) + static_cast<float>(hi_) * pow_2_64; |
| } |
| |
| inline uint128::operator double() const { |
| constexpr double pow_2_64 = 18446744073709551616.0; |
| return static_cast<double>(lo_) + static_cast<double>(hi_) * pow_2_64; |
| } |
| |
| inline uint128::operator long double() const { |
| constexpr long double pow_2_64 = 18446744073709551616.0L; |
| return static_cast<long double>(lo_) + |
| static_cast<long double>(hi_) * pow_2_64; |
| } |
| |
| // Comparison operators. |
| |
| constexpr bool operator==(uint128 lhs, uint128 rhs) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| return static_cast<unsigned __int128>(lhs) == |
| static_cast<unsigned __int128>(rhs); |
| #else |
| return (Uint128Low64(lhs) == Uint128Low64(rhs) && |
| Uint128High64(lhs) == Uint128High64(rhs)); |
| #endif |
| } |
| |
| constexpr bool operator!=(uint128 lhs, uint128 rhs) { return !(lhs == rhs); } |
| |
| constexpr bool operator<(uint128 lhs, uint128 rhs) { |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| return static_cast<unsigned __int128>(lhs) < |
| static_cast<unsigned __int128>(rhs); |
| #else |
| return (Uint128High64(lhs) == Uint128High64(rhs)) |
| ? (Uint128Low64(lhs) < Uint128Low64(rhs)) |
| : (Uint128High64(lhs) < Uint128High64(rhs)); |
| #endif |
| } |
| |
| constexpr bool operator>(uint128 lhs, uint128 rhs) { return rhs < lhs; } |
| |
| constexpr bool operator<=(uint128 lhs, uint128 rhs) { return !(rhs < lhs); } |
| |
| constexpr bool operator>=(uint128 lhs, uint128 rhs) { return !(lhs < rhs); } |
| |
| #ifdef __cpp_impl_three_way_comparison |
| constexpr absl::strong_ordering operator<=>(uint128 lhs, uint128 rhs) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| if (auto lhs_128 = static_cast<unsigned __int128>(lhs), |
| rhs_128 = static_cast<unsigned __int128>(rhs); |
| lhs_128 < rhs_128) { |
| return absl::strong_ordering::less; |
| } else if (lhs_128 > rhs_128) { |
| return absl::strong_ordering::greater; |
| } else { |
| return absl::strong_ordering::equal; |
| } |
| #else |
| if (uint64_t lhs_high = Uint128High64(lhs), rhs_high = Uint128High64(rhs); |
| lhs_high < rhs_high) { |
| return absl::strong_ordering::less; |
| } else if (lhs_high > rhs_high) { |
| return absl::strong_ordering::greater; |
| } else if (uint64_t lhs_low = Uint128Low64(lhs), rhs_low = Uint128Low64(rhs); |
| lhs_low < rhs_low) { |
| return absl::strong_ordering::less; |
| } else if (lhs_low > rhs_low) { |
| return absl::strong_ordering::greater; |
| } else { |
| return absl::strong_ordering::equal; |
| } |
| #endif |
| } |
| #endif |
| |
| // Unary operators. |
| |
| constexpr inline uint128 operator+(uint128 val) { return val; } |
| |
| constexpr inline int128 operator+(int128 val) { return val; } |
| |
| constexpr uint128 operator-(uint128 val) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| return -static_cast<unsigned __int128>(val); |
| #else |
| return MakeUint128( |
| ~Uint128High64(val) + static_cast<unsigned long>(Uint128Low64(val) == 0), |
| ~Uint128Low64(val) + 1); |
| #endif |
| } |
| |
| constexpr inline bool operator!(uint128 val) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| return !static_cast<unsigned __int128>(val); |
| #else |
| return !Uint128High64(val) && !Uint128Low64(val); |
| #endif |
| } |
| |
| // Logical operators. |
| |
| constexpr inline uint128 operator~(uint128 val) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| return ~static_cast<unsigned __int128>(val); |
| #else |
| return MakeUint128(~Uint128High64(val), ~Uint128Low64(val)); |
| #endif |
| } |
| |
| constexpr inline uint128 operator|(uint128 lhs, uint128 rhs) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| return static_cast<unsigned __int128>(lhs) | |
| static_cast<unsigned __int128>(rhs); |
| #else |
| return MakeUint128(Uint128High64(lhs) | Uint128High64(rhs), |
| Uint128Low64(lhs) | Uint128Low64(rhs)); |
| #endif |
| } |
| |
| constexpr inline uint128 operator&(uint128 lhs, uint128 rhs) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| return static_cast<unsigned __int128>(lhs) & |
| static_cast<unsigned __int128>(rhs); |
| #else |
| return MakeUint128(Uint128High64(lhs) & Uint128High64(rhs), |
| Uint128Low64(lhs) & Uint128Low64(rhs)); |
| #endif |
| } |
| |
| constexpr inline uint128 operator^(uint128 lhs, uint128 rhs) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| return static_cast<unsigned __int128>(lhs) ^ |
| static_cast<unsigned __int128>(rhs); |
| #else |
| return MakeUint128(Uint128High64(lhs) ^ Uint128High64(rhs), |
| Uint128Low64(lhs) ^ Uint128Low64(rhs)); |
| #endif |
| } |
| |
| inline uint128& uint128::operator|=(uint128 other) { |
| *this = *this | other; |
| return *this; |
| } |
| |
| inline uint128& uint128::operator&=(uint128 other) { |
| *this = *this & other; |
| return *this; |
| } |
| |
| inline uint128& uint128::operator^=(uint128 other) { |
| *this = *this ^ other; |
| return *this; |
| } |
| |
| // Arithmetic operators. |
| |
| constexpr uint128 operator<<(uint128 lhs, int amount) { |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| return static_cast<unsigned __int128>(lhs) << amount; |
| #else |
| // uint64_t shifts of >= 64 are undefined, so we will need some |
| // special-casing. |
| return amount >= 64 ? MakeUint128(Uint128Low64(lhs) << (amount - 64), 0) |
| : amount == 0 ? lhs |
| : MakeUint128((Uint128High64(lhs) << amount) | |
| (Uint128Low64(lhs) >> (64 - amount)), |
| Uint128Low64(lhs) << amount); |
| #endif |
| } |
| |
| constexpr uint128 operator>>(uint128 lhs, int amount) { |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| return static_cast<unsigned __int128>(lhs) >> amount; |
| #else |
| // uint64_t shifts of >= 64 are undefined, so we will need some |
| // special-casing. |
| return amount >= 64 ? MakeUint128(0, Uint128High64(lhs) >> (amount - 64)) |
| : amount == 0 ? lhs |
| : MakeUint128(Uint128High64(lhs) >> amount, |
| (Uint128Low64(lhs) >> amount) | |
| (Uint128High64(lhs) << (64 - amount))); |
| #endif |
| } |
| |
| #if !defined(ABSL_HAVE_INTRINSIC_INT128) |
| namespace int128_internal { |
| constexpr uint128 AddResult(uint128 result, uint128 lhs) { |
| // check for carry |
| return (Uint128Low64(result) < Uint128Low64(lhs)) |
| ? MakeUint128(Uint128High64(result) + 1, Uint128Low64(result)) |
| : result; |
| } |
| } // namespace int128_internal |
| #endif |
| |
| constexpr uint128 operator+(uint128 lhs, uint128 rhs) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| return static_cast<unsigned __int128>(lhs) + |
| static_cast<unsigned __int128>(rhs); |
| #else |
| return int128_internal::AddResult( |
| MakeUint128(Uint128High64(lhs) + Uint128High64(rhs), |
| Uint128Low64(lhs) + Uint128Low64(rhs)), |
| lhs); |
| #endif |
| } |
| |
| #if !defined(ABSL_HAVE_INTRINSIC_INT128) |
| namespace int128_internal { |
| constexpr uint128 SubstructResult(uint128 result, uint128 lhs, uint128 rhs) { |
| // check for carry |
| return (Uint128Low64(lhs) < Uint128Low64(rhs)) |
| ? MakeUint128(Uint128High64(result) - 1, Uint128Low64(result)) |
| : result; |
| } |
| } // namespace int128_internal |
| #endif |
| |
| constexpr uint128 operator-(uint128 lhs, uint128 rhs) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| return static_cast<unsigned __int128>(lhs) - |
| static_cast<unsigned __int128>(rhs); |
| #else |
| return int128_internal::SubstructResult( |
| MakeUint128(Uint128High64(lhs) - Uint128High64(rhs), |
| Uint128Low64(lhs) - Uint128Low64(rhs)), |
| lhs, rhs); |
| #endif |
| } |
| |
| inline uint128 operator*(uint128 lhs, uint128 rhs) { |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| // TODO(strel) Remove once alignment issues are resolved and unsigned __int128 |
| // can be used for uint128 storage. |
| return static_cast<unsigned __int128>(lhs) * |
| static_cast<unsigned __int128>(rhs); |
| #elif defined(_MSC_VER) && defined(_M_X64) && !defined(_M_ARM64EC) |
| uint64_t carry; |
| uint64_t low = _umul128(Uint128Low64(lhs), Uint128Low64(rhs), &carry); |
| return MakeUint128(Uint128Low64(lhs) * Uint128High64(rhs) + |
| Uint128High64(lhs) * Uint128Low64(rhs) + carry, |
| low); |
| #else // ABSL_HAVE_INTRINSIC128 |
| uint64_t a32 = Uint128Low64(lhs) >> 32; |
| uint64_t a00 = Uint128Low64(lhs) & 0xffffffff; |
| uint64_t b32 = Uint128Low64(rhs) >> 32; |
| uint64_t b00 = Uint128Low64(rhs) & 0xffffffff; |
| uint128 result = |
| MakeUint128(Uint128High64(lhs) * Uint128Low64(rhs) + |
| Uint128Low64(lhs) * Uint128High64(rhs) + a32 * b32, |
| a00 * b00); |
| result += uint128(a32 * b00) << 32; |
| result += uint128(a00 * b32) << 32; |
| return result; |
| #endif // ABSL_HAVE_INTRINSIC128 |
| } |
| |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| inline uint128 operator/(uint128 lhs, uint128 rhs) { |
| return static_cast<unsigned __int128>(lhs) / |
| static_cast<unsigned __int128>(rhs); |
| } |
| |
| inline uint128 operator%(uint128 lhs, uint128 rhs) { |
| return static_cast<unsigned __int128>(lhs) % |
| static_cast<unsigned __int128>(rhs); |
| } |
| #endif |
| |
| // Increment/decrement operators. |
| |
| inline uint128 uint128::operator++(int) { |
| uint128 tmp(*this); |
| *this += 1; |
| return tmp; |
| } |
| |
| inline uint128 uint128::operator--(int) { |
| uint128 tmp(*this); |
| *this -= 1; |
| return tmp; |
| } |
| |
| inline uint128& uint128::operator++() { |
| *this += 1; |
| return *this; |
| } |
| |
| inline uint128& uint128::operator--() { |
| *this -= 1; |
| return *this; |
| } |
| |
| constexpr int128 MakeInt128(int64_t high, uint64_t low) { |
| return int128(high, low); |
| } |
| |
| // Assignment from integer types. |
| inline int128& int128::operator=(int v) { return *this = int128(v); } |
| |
| inline int128& int128::operator=(unsigned int v) { return *this = int128(v); } |
| |
| inline int128& int128::operator=(long v) { // NOLINT(runtime/int) |
| return *this = int128(v); |
| } |
| |
| // NOLINTNEXTLINE(runtime/int) |
| inline int128& int128::operator=(unsigned long v) { return *this = int128(v); } |
| |
| // NOLINTNEXTLINE(runtime/int) |
| inline int128& int128::operator=(long long v) { return *this = int128(v); } |
| |
| // NOLINTNEXTLINE(runtime/int) |
| inline int128& int128::operator=(unsigned long long v) { |
| return *this = int128(v); |
| } |
| |
| // Arithmetic operators. |
| constexpr int128 operator-(int128 v); |
| constexpr int128 operator+(int128 lhs, int128 rhs); |
| constexpr int128 operator-(int128 lhs, int128 rhs); |
| int128 operator*(int128 lhs, int128 rhs); |
| int128 operator/(int128 lhs, int128 rhs); |
| int128 operator%(int128 lhs, int128 rhs); |
| constexpr int128 operator|(int128 lhs, int128 rhs); |
| constexpr int128 operator&(int128 lhs, int128 rhs); |
| constexpr int128 operator^(int128 lhs, int128 rhs); |
| constexpr int128 operator<<(int128 lhs, int amount); |
| constexpr int128 operator>>(int128 lhs, int amount); |
| |
| inline int128& int128::operator+=(int128 other) { |
| *this = *this + other; |
| return *this; |
| } |
| |
| inline int128& int128::operator-=(int128 other) { |
| *this = *this - other; |
| return *this; |
| } |
| |
| inline int128& int128::operator*=(int128 other) { |
| *this = *this * other; |
| return *this; |
| } |
| |
| inline int128& int128::operator/=(int128 other) { |
| *this = *this / other; |
| return *this; |
| } |
| |
| inline int128& int128::operator%=(int128 other) { |
| *this = *this % other; |
| return *this; |
| } |
| |
| inline int128& int128::operator|=(int128 other) { |
| *this = *this | other; |
| return *this; |
| } |
| |
| inline int128& int128::operator&=(int128 other) { |
| *this = *this & other; |
| return *this; |
| } |
| |
| inline int128& int128::operator^=(int128 other) { |
| *this = *this ^ other; |
| return *this; |
| } |
| |
| inline int128& int128::operator<<=(int amount) { |
| *this = *this << amount; |
| return *this; |
| } |
| |
| inline int128& int128::operator>>=(int amount) { |
| *this = *this >> amount; |
| return *this; |
| } |
| |
| // Forward declaration for comparison operators. |
| constexpr bool operator!=(int128 lhs, int128 rhs); |
| |
| namespace int128_internal { |
| |
| // Casts from unsigned to signed while preserving the underlying binary |
| // representation. |
| constexpr int64_t BitCastToSigned(uint64_t v) { |
| // Casting an unsigned integer to a signed integer of the same |
| // width is implementation defined behavior if the source value would not fit |
| // in the destination type. We step around it with a roundtrip bitwise not |
| // operation to make sure this function remains constexpr. Clang, GCC, and |
| // MSVC optimize this to a no-op on x86-64. |
| return v & (uint64_t{1} << 63) ? ~static_cast<int64_t>(~v) |
| : static_cast<int64_t>(v); |
| } |
| |
| } // namespace int128_internal |
| |
| #if defined(ABSL_HAVE_INTRINSIC_INT128) |
| #include "absl/numeric/int128_have_intrinsic.inc" // IWYU pragma: export |
| #else // ABSL_HAVE_INTRINSIC_INT128 |
| #include "absl/numeric/int128_no_intrinsic.inc" // IWYU pragma: export |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #undef ABSL_INTERNAL_WCHAR_T |
| |
| #endif // ABSL_NUMERIC_INT128_H_ |
| *í |
| hsoong/.intermediates/external/abseil-cpp/absl_types_compare_hdrs/gen/my_include_dir/absl/types/compare.hÿ// 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. |
| // |
| // ----------------------------------------------------------------------------- |
| // compare.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines the `absl::partial_ordering`, `absl::weak_ordering`, |
| // and `absl::strong_ordering` types for storing the results of three way |
| // comparisons. |
| // |
| // Example: |
| // absl::weak_ordering compare(const std::string& a, const std::string& b); |
| // |
| // These are C++11 compatible versions of the C++20 corresponding types |
| // (`std::partial_ordering`, etc.) and are designed to be drop-in replacements |
| // for code compliant with C++20. |
| |
| #ifndef ABSL_TYPES_COMPARE_H_ |
| #define ABSL_TYPES_COMPARE_H_ |
| |
| #include "absl/base/config.h" |
| |
| #ifdef ABSL_USES_STD_ORDERING |
| |
| #include <compare> // IWYU pragma: export |
| #include <type_traits> |
| |
| #include "absl/meta/type_traits.h" |
| |
| #else |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstdlib> |
| #include <type_traits> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/macros.h" |
| #include "absl/meta/type_traits.h" |
| |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| #ifdef ABSL_USES_STD_ORDERING |
| |
| using std::partial_ordering; |
| using std::strong_ordering; |
| using std::weak_ordering; |
| |
| #else |
| |
| namespace compare_internal { |
| |
| using value_type = int8_t; |
| |
| class OnlyLiteralZero { |
| public: |
| #if ABSL_HAVE_ATTRIBUTE(enable_if) |
| // On clang, we can avoid triggering modernize-use-nullptr by only enabling |
| // this overload when the value is a compile time integer constant equal to 0. |
| // |
| // In c++20, this could be a static_assert in a consteval function. |
| constexpr OnlyLiteralZero(int n) // NOLINT |
| __attribute__((enable_if(n == 0, "Only literal `0` is allowed."))) {} |
| #else // ABSL_HAVE_ATTRIBUTE(enable_if) |
| // Accept only literal zero since it can be implicitly converted to a pointer |
| // to member type. nullptr constants will be caught by the other constructor |
| // which accepts a nullptr_t. |
| // |
| // This constructor is not used for clang since it triggers |
| // modernize-use-nullptr. |
| constexpr OnlyLiteralZero(int OnlyLiteralZero::*) noexcept {} // NOLINT |
| #endif |
| |
| // Fails compilation when `nullptr` or integral type arguments other than |
| // `int` are passed. This constructor doesn't accept `int` because literal `0` |
| // has type `int`. Literal `0` arguments will be implicitly converted to |
| // `std::nullptr_t` and accepted by the above constructor, while other `int` |
| // arguments will fail to be converted and cause compilation failure. |
| template <typename T, typename = typename std::enable_if< |
| std::is_same<T, std::nullptr_t>::value || |
| (std::is_integral<T>::value && |
| !std::is_same<T, int>::value)>::type> |
| OnlyLiteralZero(T) { // NOLINT |
| static_assert(sizeof(T) < 0, "Only literal `0` is allowed."); |
| } |
| }; |
| |
| enum class eq : value_type { |
| equal = 0, |
| equivalent = equal, |
| nonequal = 1, |
| nonequivalent = nonequal, |
| }; |
| |
| enum class ord : value_type { less = -1, greater = 1 }; |
| |
| enum class ncmp : value_type { unordered = -127 }; |
| |
| // Define macros to allow for creation or emulation of C++17 inline variables |
| // based on whether the feature is supported. Note: we can't use |
| // ABSL_INTERNAL_INLINE_CONSTEXPR here because the variables here are of |
| // incomplete types so they need to be defined after the types are complete. |
| #ifdef __cpp_inline_variables |
| |
| // A no-op expansion that can be followed by a semicolon at class level. |
| #define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) static_assert(true, "") |
| |
| #define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) \ |
| static const type name |
| |
| #define ABSL_COMPARE_INLINE_INIT(type, name, init) \ |
| inline constexpr type type::name(init) |
| |
| #else // __cpp_inline_variables |
| |
| #define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) \ |
| ABSL_CONST_INIT static const T name |
| |
| // A no-op expansion that can be followed by a semicolon at class level. |
| #define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) static_assert(true, "") |
| |
| #define ABSL_COMPARE_INLINE_INIT(type, name, init) \ |
| template <typename T> \ |
| const T compare_internal::type##_base<T>::name(init) |
| |
| #endif // __cpp_inline_variables |
| |
| // These template base classes allow for defining the values of the constants |
| // in the header file (for performance) without using inline variables (which |
| // aren't available in C++11). |
| template <typename T> |
| struct partial_ordering_base { |
| ABSL_COMPARE_INLINE_BASECLASS_DECL(less); |
| ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent); |
| ABSL_COMPARE_INLINE_BASECLASS_DECL(greater); |
| ABSL_COMPARE_INLINE_BASECLASS_DECL(unordered); |
| }; |
| |
| template <typename T> |
| struct weak_ordering_base { |
| ABSL_COMPARE_INLINE_BASECLASS_DECL(less); |
| ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent); |
| ABSL_COMPARE_INLINE_BASECLASS_DECL(greater); |
| }; |
| |
| template <typename T> |
| struct strong_ordering_base { |
| ABSL_COMPARE_INLINE_BASECLASS_DECL(less); |
| ABSL_COMPARE_INLINE_BASECLASS_DECL(equal); |
| ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent); |
| ABSL_COMPARE_INLINE_BASECLASS_DECL(greater); |
| }; |
| |
| } // namespace compare_internal |
| |
| class partial_ordering |
| : public compare_internal::partial_ordering_base<partial_ordering> { |
| explicit constexpr partial_ordering(compare_internal::eq v) noexcept |
| : value_(static_cast<compare_internal::value_type>(v)) {} |
| explicit constexpr partial_ordering(compare_internal::ord v) noexcept |
| : value_(static_cast<compare_internal::value_type>(v)) {} |
| explicit constexpr partial_ordering(compare_internal::ncmp v) noexcept |
| : value_(static_cast<compare_internal::value_type>(v)) {} |
| friend struct compare_internal::partial_ordering_base<partial_ordering>; |
| |
| constexpr bool is_ordered() const noexcept { |
| return value_ != |
| compare_internal::value_type(compare_internal::ncmp::unordered); |
| } |
| |
| public: |
| ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, less); |
| ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, equivalent); |
| ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, greater); |
| ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, unordered); |
| |
| // Comparisons |
| friend constexpr bool operator==( |
| partial_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.is_ordered() && v.value_ == 0; |
| } |
| friend constexpr bool operator!=( |
| partial_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return !v.is_ordered() || v.value_ != 0; |
| } |
| friend constexpr bool operator<( |
| partial_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.is_ordered() && v.value_ < 0; |
| } |
| friend constexpr bool operator<=( |
| partial_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.is_ordered() && v.value_ <= 0; |
| } |
| friend constexpr bool operator>( |
| partial_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.is_ordered() && v.value_ > 0; |
| } |
| friend constexpr bool operator>=( |
| partial_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.is_ordered() && v.value_ >= 0; |
| } |
| friend constexpr bool operator==(compare_internal::OnlyLiteralZero, |
| partial_ordering v) noexcept { |
| return v.is_ordered() && 0 == v.value_; |
| } |
| friend constexpr bool operator!=(compare_internal::OnlyLiteralZero, |
| partial_ordering v) noexcept { |
| return !v.is_ordered() || 0 != v.value_; |
| } |
| friend constexpr bool operator<(compare_internal::OnlyLiteralZero, |
| partial_ordering v) noexcept { |
| return v.is_ordered() && 0 < v.value_; |
| } |
| friend constexpr bool operator<=(compare_internal::OnlyLiteralZero, |
| partial_ordering v) noexcept { |
| return v.is_ordered() && 0 <= v.value_; |
| } |
| friend constexpr bool operator>(compare_internal::OnlyLiteralZero, |
| partial_ordering v) noexcept { |
| return v.is_ordered() && 0 > v.value_; |
| } |
| friend constexpr bool operator>=(compare_internal::OnlyLiteralZero, |
| partial_ordering v) noexcept { |
| return v.is_ordered() && 0 >= v.value_; |
| } |
| friend constexpr bool operator==(partial_ordering v1, |
| partial_ordering v2) noexcept { |
| return v1.value_ == v2.value_; |
| } |
| friend constexpr bool operator!=(partial_ordering v1, |
| partial_ordering v2) noexcept { |
| return v1.value_ != v2.value_; |
| } |
| |
| private: |
| compare_internal::value_type value_; |
| }; |
| ABSL_COMPARE_INLINE_INIT(partial_ordering, less, compare_internal::ord::less); |
| ABSL_COMPARE_INLINE_INIT(partial_ordering, equivalent, |
| compare_internal::eq::equivalent); |
| ABSL_COMPARE_INLINE_INIT(partial_ordering, greater, |
| compare_internal::ord::greater); |
| ABSL_COMPARE_INLINE_INIT(partial_ordering, unordered, |
| compare_internal::ncmp::unordered); |
| |
| class weak_ordering |
| : public compare_internal::weak_ordering_base<weak_ordering> { |
| explicit constexpr weak_ordering(compare_internal::eq v) noexcept |
| : value_(static_cast<compare_internal::value_type>(v)) {} |
| explicit constexpr weak_ordering(compare_internal::ord v) noexcept |
| : value_(static_cast<compare_internal::value_type>(v)) {} |
| friend struct compare_internal::weak_ordering_base<weak_ordering>; |
| |
| public: |
| ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, less); |
| ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, equivalent); |
| ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, greater); |
| |
| // Conversions |
| constexpr operator partial_ordering() const noexcept { // NOLINT |
| return value_ == 0 ? partial_ordering::equivalent |
| : (value_ < 0 ? partial_ordering::less |
| : partial_ordering::greater); |
| } |
| // Comparisons |
| friend constexpr bool operator==( |
| weak_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ == 0; |
| } |
| friend constexpr bool operator!=( |
| weak_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ != 0; |
| } |
| friend constexpr bool operator<( |
| weak_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ < 0; |
| } |
| friend constexpr bool operator<=( |
| weak_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ <= 0; |
| } |
| friend constexpr bool operator>( |
| weak_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ > 0; |
| } |
| friend constexpr bool operator>=( |
| weak_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ >= 0; |
| } |
| friend constexpr bool operator==(compare_internal::OnlyLiteralZero, |
| weak_ordering v) noexcept { |
| return 0 == v.value_; |
| } |
| friend constexpr bool operator!=(compare_internal::OnlyLiteralZero, |
| weak_ordering v) noexcept { |
| return 0 != v.value_; |
| } |
| friend constexpr bool operator<(compare_internal::OnlyLiteralZero, |
| weak_ordering v) noexcept { |
| return 0 < v.value_; |
| } |
| friend constexpr bool operator<=(compare_internal::OnlyLiteralZero, |
| weak_ordering v) noexcept { |
| return 0 <= v.value_; |
| } |
| friend constexpr bool operator>(compare_internal::OnlyLiteralZero, |
| weak_ordering v) noexcept { |
| return 0 > v.value_; |
| } |
| friend constexpr bool operator>=(compare_internal::OnlyLiteralZero, |
| weak_ordering v) noexcept { |
| return 0 >= v.value_; |
| } |
| friend constexpr bool operator==(weak_ordering v1, |
| weak_ordering v2) noexcept { |
| return v1.value_ == v2.value_; |
| } |
| friend constexpr bool operator!=(weak_ordering v1, |
| weak_ordering v2) noexcept { |
| return v1.value_ != v2.value_; |
| } |
| |
| private: |
| compare_internal::value_type value_; |
| }; |
| ABSL_COMPARE_INLINE_INIT(weak_ordering, less, compare_internal::ord::less); |
| ABSL_COMPARE_INLINE_INIT(weak_ordering, equivalent, |
| compare_internal::eq::equivalent); |
| ABSL_COMPARE_INLINE_INIT(weak_ordering, greater, |
| compare_internal::ord::greater); |
| |
| class strong_ordering |
| : public compare_internal::strong_ordering_base<strong_ordering> { |
| explicit constexpr strong_ordering(compare_internal::eq v) noexcept |
| : value_(static_cast<compare_internal::value_type>(v)) {} |
| explicit constexpr strong_ordering(compare_internal::ord v) noexcept |
| : value_(static_cast<compare_internal::value_type>(v)) {} |
| friend struct compare_internal::strong_ordering_base<strong_ordering>; |
| |
| public: |
| ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, less); |
| ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equal); |
| ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equivalent); |
| ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, greater); |
| |
| // Conversions |
| constexpr operator partial_ordering() const noexcept { // NOLINT |
| return value_ == 0 ? partial_ordering::equivalent |
| : (value_ < 0 ? partial_ordering::less |
| : partial_ordering::greater); |
| } |
| constexpr operator weak_ordering() const noexcept { // NOLINT |
| return value_ == 0 |
| ? weak_ordering::equivalent |
| : (value_ < 0 ? weak_ordering::less : weak_ordering::greater); |
| } |
| // Comparisons |
| friend constexpr bool operator==( |
| strong_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ == 0; |
| } |
| friend constexpr bool operator!=( |
| strong_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ != 0; |
| } |
| friend constexpr bool operator<( |
| strong_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ < 0; |
| } |
| friend constexpr bool operator<=( |
| strong_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ <= 0; |
| } |
| friend constexpr bool operator>( |
| strong_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ > 0; |
| } |
| friend constexpr bool operator>=( |
| strong_ordering v, compare_internal::OnlyLiteralZero) noexcept { |
| return v.value_ >= 0; |
| } |
| friend constexpr bool operator==(compare_internal::OnlyLiteralZero, |
| strong_ordering v) noexcept { |
| return 0 == v.value_; |
| } |
| friend constexpr bool operator!=(compare_internal::OnlyLiteralZero, |
| strong_ordering v) noexcept { |
| return 0 != v.value_; |
| } |
| friend constexpr bool operator<(compare_internal::OnlyLiteralZero, |
| strong_ordering v) noexcept { |
| return 0 < v.value_; |
| } |
| friend constexpr bool operator<=(compare_internal::OnlyLiteralZero, |
| strong_ordering v) noexcept { |
| return 0 <= v.value_; |
| } |
| friend constexpr bool operator>(compare_internal::OnlyLiteralZero, |
| strong_ordering v) noexcept { |
| return 0 > v.value_; |
| } |
| friend constexpr bool operator>=(compare_internal::OnlyLiteralZero, |
| strong_ordering v) noexcept { |
| return 0 >= v.value_; |
| } |
| friend constexpr bool operator==(strong_ordering v1, |
| strong_ordering v2) noexcept { |
| return v1.value_ == v2.value_; |
| } |
| friend constexpr bool operator!=(strong_ordering v1, |
| strong_ordering v2) noexcept { |
| return v1.value_ != v2.value_; |
| } |
| |
| private: |
| compare_internal::value_type value_; |
| }; |
| ABSL_COMPARE_INLINE_INIT(strong_ordering, less, compare_internal::ord::less); |
| ABSL_COMPARE_INLINE_INIT(strong_ordering, equal, compare_internal::eq::equal); |
| ABSL_COMPARE_INLINE_INIT(strong_ordering, equivalent, |
| compare_internal::eq::equivalent); |
| ABSL_COMPARE_INLINE_INIT(strong_ordering, greater, |
| compare_internal::ord::greater); |
| |
| #undef ABSL_COMPARE_INLINE_BASECLASS_DECL |
| #undef ABSL_COMPARE_INLINE_SUBCLASS_DECL |
| #undef ABSL_COMPARE_INLINE_INIT |
| |
| #endif // ABSL_USES_STD_ORDERING |
| |
| namespace compare_internal { |
| // We also provide these comparator adapter functions for internal absl use. |
| |
| // Helper functions to do a boolean comparison of two keys given a boolean |
| // or three-way comparator. |
| // SFINAE prevents implicit conversions to bool (such as from int). |
| template <typename BoolT, |
| absl::enable_if_t<std::is_same<bool, BoolT>::value, int> = 0> |
| constexpr bool compare_result_as_less_than(const BoolT r) { return r; } |
| constexpr bool compare_result_as_less_than(const absl::weak_ordering r) { |
| return r < 0; |
| } |
| |
| template <typename Compare, typename K, typename LK> |
| constexpr bool do_less_than_comparison(const Compare &compare, const K &x, |
| const LK &y) { |
| return compare_result_as_less_than(compare(x, y)); |
| } |
| |
| // Helper functions to do a three-way comparison of two keys given a boolean or |
| // three-way comparator. |
| // SFINAE prevents implicit conversions to int (such as from bool). |
| template <typename Int, |
| absl::enable_if_t<std::is_same<int, Int>::value, int> = 0> |
| constexpr absl::weak_ordering compare_result_as_ordering(const Int c) { |
| return c < 0 ? absl::weak_ordering::less |
| : c == 0 ? absl::weak_ordering::equivalent |
| : absl::weak_ordering::greater; |
| } |
| constexpr absl::weak_ordering compare_result_as_ordering( |
| const absl::weak_ordering c) { |
| return c; |
| } |
| |
| template < |
| typename Compare, typename K, typename LK, |
| absl::enable_if_t<!std::is_same<bool, absl::result_of_t<Compare( |
| const K &, const LK &)>>::value, |
| int> = 0> |
| constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare, |
| const K &x, const LK &y) { |
| return compare_result_as_ordering(compare(x, y)); |
| } |
| template < |
| typename Compare, typename K, typename LK, |
| absl::enable_if_t<std::is_same<bool, absl::result_of_t<Compare( |
| const K &, const LK &)>>::value, |
| int> = 0> |
| constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare, |
| const K &x, const LK &y) { |
| return compare(x, y) ? absl::weak_ordering::less |
| : compare(y, x) ? absl::weak_ordering::greater |
| : absl::weak_ordering::equivalent; |
| } |
| |
| } // namespace compare_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_TYPES_COMPARE_H_ |
| *C |
| soong/.intermediates/external/abseil-cpp/absl_crc_crc_internal_hdrs/gen/my_include_dir/absl/crc/internal/crc32_x86_arm_combined_simd.hB// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_CRC_INTERNAL_CRC32_X86_ARM_COMBINED_SIMD_H_ |
| #define ABSL_CRC_INTERNAL_CRC32_X86_ARM_COMBINED_SIMD_H_ |
| |
| #include <cstdint> |
| |
| #include "absl/base/config.h" |
| |
| // ------------------------------------------------------------------------- |
| // Many x86 and ARM machines have CRC acceleration hardware. |
| // We can do a faster version of Extend() on such machines. |
| // We define a translation layer for both x86 and ARM for the ease of use and |
| // most performance gains. |
| |
| // This implementation requires 64-bit CRC instructions (part of SSE 4.2) and |
| // PCLMULQDQ instructions. 32-bit builds with SSE 4.2 do exist, so the |
| // __x86_64__ condition is necessary. |
| #if defined(__x86_64__) && defined(__SSE4_2__) && defined(__PCLMUL__) |
| |
| #include <x86intrin.h> |
| #define ABSL_CRC_INTERNAL_HAVE_X86_SIMD |
| |
| #elif defined(_MSC_VER) && !defined(__clang__) && defined(__AVX__) && \ |
| defined(_M_AMD64) |
| |
| // MSVC AVX (/arch:AVX) implies SSE 4.2 and PCLMULQDQ. |
| #include <intrin.h> |
| #define ABSL_CRC_INTERNAL_HAVE_X86_SIMD |
| |
| #elif defined(__aarch64__) && defined(__LITTLE_ENDIAN__) && \ |
| defined(__ARM_FEATURE_CRC32) && defined(ABSL_INTERNAL_HAVE_ARM_NEON) && \ |
| defined(__ARM_FEATURE_CRYPTO) |
| |
| #include <arm_acle.h> |
| #include <arm_neon.h> |
| #define ABSL_CRC_INTERNAL_HAVE_ARM_SIMD |
| |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace crc_internal { |
| |
| #if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) || \ |
| defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) |
| |
| #if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) |
| using V128 = uint64x2_t; |
| #else |
| // Note: Do not use __m128i_u, it is not portable. |
| // Use V128_LoadU() perform an unaligned load from __m128i*. |
| using V128 = __m128i; |
| #endif |
| |
| // Starting with the initial value in |crc|, accumulates a CRC32 value for |
| // unsigned integers of different sizes. |
| uint32_t CRC32_u8(uint32_t crc, uint8_t v); |
| |
| uint32_t CRC32_u16(uint32_t crc, uint16_t v); |
| |
| uint32_t CRC32_u32(uint32_t crc, uint32_t v); |
| |
| uint32_t CRC32_u64(uint32_t crc, uint64_t v); |
| |
| // Loads 128 bits of integer data. |src| must be 16-byte aligned. |
| V128 V128_Load(const V128* src); |
| |
| // Load 128 bits of integer data. |src| does not need to be aligned. |
| V128 V128_LoadU(const V128* src); |
| |
| // Store 128 bits of integer data. |src| must be 16-byte aligned. |
| void V128_Store(V128* dst, V128 data); |
| |
| // Polynomially multiplies the high 64 bits of |l| and |r|. |
| V128 V128_PMulHi(const V128 l, const V128 r); |
| |
| // Polynomially multiplies the low 64 bits of |l| and |r|. |
| V128 V128_PMulLow(const V128 l, const V128 r); |
| |
| // Polynomially multiplies the low 64 bits of |r| and high 64 bits of |l|. |
| V128 V128_PMul01(const V128 l, const V128 r); |
| |
| // Polynomially multiplies the low 64 bits of |l| and high 64 bits of |r|. |
| V128 V128_PMul10(const V128 l, const V128 r); |
| |
| // Produces a XOR operation of |l| and |r|. |
| V128 V128_Xor(const V128 l, const V128 r); |
| |
| // Sets the lower half of a 128 bit register to the given 64-bit value and |
| // zeroes the upper half. |
| // dst[63:0] := |r| |
| // dst[127:64] := |0| |
| V128 V128_From64WithZeroFill(const uint64_t r); |
| |
| // Extracts a 32-bit integer from |l|, selected with |imm|. |
| template <int imm> |
| int V128_Extract32(const V128 l); |
| |
| // Extracts a 64-bit integer from |l|, selected with |imm|. |
| template <int imm> |
| uint64_t V128_Extract64(const V128 l); |
| |
| // Extracts the low 64 bits from V128. |
| int64_t V128_Low64(const V128 l); |
| |
| // Add packed 64-bit integers in |l| and |r|. |
| V128 V128_Add64(const V128 l, const V128 r); |
| |
| #endif |
| |
| #if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) |
| |
| inline uint32_t CRC32_u8(uint32_t crc, uint8_t v) { |
| return _mm_crc32_u8(crc, v); |
| } |
| |
| inline uint32_t CRC32_u16(uint32_t crc, uint16_t v) { |
| return _mm_crc32_u16(crc, v); |
| } |
| |
| inline uint32_t CRC32_u32(uint32_t crc, uint32_t v) { |
| return _mm_crc32_u32(crc, v); |
| } |
| |
| inline uint32_t CRC32_u64(uint32_t crc, uint64_t v) { |
| return static_cast<uint32_t>(_mm_crc32_u64(crc, v)); |
| } |
| |
| inline V128 V128_Load(const V128* src) { return _mm_load_si128(src); } |
| |
| inline V128 V128_LoadU(const V128* src) { return _mm_loadu_si128(src); } |
| |
| inline void V128_Store(V128* dst, V128 data) { _mm_store_si128(dst, data); } |
| |
| inline V128 V128_PMulHi(const V128 l, const V128 r) { |
| return _mm_clmulepi64_si128(l, r, 0x11); |
| } |
| |
| inline V128 V128_PMulLow(const V128 l, const V128 r) { |
| return _mm_clmulepi64_si128(l, r, 0x00); |
| } |
| |
| inline V128 V128_PMul01(const V128 l, const V128 r) { |
| return _mm_clmulepi64_si128(l, r, 0x01); |
| } |
| |
| inline V128 V128_PMul10(const V128 l, const V128 r) { |
| return _mm_clmulepi64_si128(l, r, 0x10); |
| } |
| |
| inline V128 V128_Xor(const V128 l, const V128 r) { return _mm_xor_si128(l, r); } |
| |
| inline V128 V128_From64WithZeroFill(const uint64_t r) { |
| return _mm_set_epi64x(static_cast<int64_t>(0), static_cast<int64_t>(r)); |
| } |
| |
| template <int imm> |
| inline int V128_Extract32(const V128 l) { |
| return _mm_extract_epi32(l, imm); |
| } |
| |
| template <int imm> |
| inline uint64_t V128_Extract64(const V128 l) { |
| return static_cast<uint64_t>(_mm_extract_epi64(l, imm)); |
| } |
| |
| inline int64_t V128_Low64(const V128 l) { return _mm_cvtsi128_si64(l); } |
| |
| inline V128 V128_Add64(const V128 l, const V128 r) { |
| return _mm_add_epi64(l, r); |
| } |
| |
| #elif defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) |
| |
| inline uint32_t CRC32_u8(uint32_t crc, uint8_t v) { return __crc32cb(crc, v); } |
| |
| inline uint32_t CRC32_u16(uint32_t crc, uint16_t v) { |
| return __crc32ch(crc, v); |
| } |
| |
| inline uint32_t CRC32_u32(uint32_t crc, uint32_t v) { |
| return __crc32cw(crc, v); |
| } |
| |
| inline uint32_t CRC32_u64(uint32_t crc, uint64_t v) { |
| return __crc32cd(crc, v); |
| } |
| |
| inline V128 V128_Load(const V128* src) { |
| return vld1q_u64(reinterpret_cast<const uint64_t*>(src)); |
| } |
| |
| inline V128 V128_LoadU(const V128* src) { |
| return vld1q_u64(reinterpret_cast<const uint64_t*>(src)); |
| } |
| |
| inline void V128_Store(V128* dst, V128 data) { |
| vst1q_u64(reinterpret_cast<uint64_t*>(dst), data); |
| } |
| |
| // Using inline assembly as clang does not generate the pmull2 instruction and |
| // performance drops by 15-20%. |
| // TODO(b/193678732): Investigate why there is a slight performance hit when |
| // using intrinsics instead of inline assembly. |
| inline V128 V128_PMulHi(const V128 l, const V128 r) { |
| uint64x2_t res; |
| __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" |
| : "=w"(res) |
| : "w"(l), "w"(r)); |
| return res; |
| } |
| |
| // TODO(b/193678732): Investigate why the compiler decides to move the constant |
| // loop multiplicands from GPR to Neon registers every loop iteration. |
| inline V128 V128_PMulLow(const V128 l, const V128 r) { |
| uint64x2_t res; |
| __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" |
| : "=w"(res) |
| : "w"(l), "w"(r)); |
| return res; |
| } |
| |
| inline V128 V128_PMul01(const V128 l, const V128 r) { |
| return reinterpret_cast<V128>(vmull_p64( |
| reinterpret_cast<poly64_t>(vget_high_p64(vreinterpretq_p64_u64(l))), |
| reinterpret_cast<poly64_t>(vget_low_p64(vreinterpretq_p64_u64(r))))); |
| } |
| |
| inline V128 V128_PMul10(const V128 l, const V128 r) { |
| return reinterpret_cast<V128>(vmull_p64( |
| reinterpret_cast<poly64_t>(vget_low_p64(vreinterpretq_p64_u64(l))), |
| reinterpret_cast<poly64_t>(vget_high_p64(vreinterpretq_p64_u64(r))))); |
| } |
| |
| inline V128 V128_Xor(const V128 l, const V128 r) { return veorq_u64(l, r); } |
| |
| inline V128 V128_From64WithZeroFill(const uint64_t r){ |
| constexpr uint64x2_t kZero = {0, 0}; |
| return vsetq_lane_u64(r, kZero, 0); |
| } |
| |
| |
| template <int imm> |
| inline int V128_Extract32(const V128 l) { |
| return vgetq_lane_s32(vreinterpretq_s32_u64(l), imm); |
| } |
| |
| template <int imm> |
| inline uint64_t V128_Extract64(const V128 l) { |
| return vgetq_lane_u64(l, imm); |
| } |
| |
| inline int64_t V128_Low64(const V128 l) { |
| return vgetq_lane_s64(vreinterpretq_s64_u64(l), 0); |
| } |
| |
| inline V128 V128_Add64(const V128 l, const V128 r) { return vaddq_u64(l, r); } |
| |
| #endif |
| |
| } // namespace crc_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CRC_INTERNAL_CRC32_X86_ARM_COMBINED_SIMD_H_ |
| *³ |
| rsoong/.intermediates/external/abseil-cpp/absl_crc_crc32c_hdrs/gen/my_include_dir/absl/crc/internal/crc32c_inline.h¼// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_CRC_INTERNAL_CRC32C_INLINE_H_ |
| #define ABSL_CRC_INTERNAL_CRC32C_INLINE_H_ |
| |
| #include <cstdint> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/internal/endian.h" |
| #include "absl/crc/internal/crc32_x86_arm_combined_simd.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace crc_internal { |
| |
| // CRC32C implementation optimized for small inputs. |
| // Either computes crc and return true, or if there is |
| // no hardware support does nothing and returns false. |
| inline bool ExtendCrc32cInline(uint32_t* crc, const char* p, size_t n) { |
| #if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) || \ |
| defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) |
| constexpr uint32_t kCrc32Xor = 0xffffffffU; |
| *crc ^= kCrc32Xor; |
| if (n & 1) { |
| *crc = CRC32_u8(*crc, static_cast<uint8_t>(*p)); |
| n--; |
| p++; |
| } |
| if (n & 2) { |
| *crc = CRC32_u16(*crc, absl::little_endian::Load16(p)); |
| n -= 2; |
| p += 2; |
| } |
| if (n & 4) { |
| *crc = CRC32_u32(*crc, absl::little_endian::Load32(p)); |
| n -= 4; |
| p += 4; |
| } |
| while (n) { |
| *crc = CRC32_u64(*crc, absl::little_endian::Load64(p)); |
| n -= 8; |
| p += 8; |
| } |
| *crc ^= kCrc32Xor; |
| return true; |
| #else |
| // No hardware support, signal the need to fallback. |
| static_cast<void>(crc); |
| static_cast<void>(p); |
| static_cast<void>(n); |
| return false; |
| #endif // defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) || |
| // defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) |
| } |
| |
| } // namespace crc_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CRC_INTERNAL_CRC32C_INLINE_H_ |
| *ô9 |
| bsoong/.intermediates/external/abseil-cpp/absl_crc_crc32c_hdrs/gen/my_include_dir/absl/crc/crc32c.h9// Copyright 2022 The Abseil Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: crc32c.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines the API for computing CRC32C values as checksums |
| // for arbitrary sequences of bytes provided as a string buffer. |
| // |
| // The API includes the basic functions for computing such CRC32C values and |
| // some utility functions for performing more efficient mathematical |
| // computations using an existing checksum. |
| #ifndef ABSL_CRC_CRC32C_H_ |
| #define ABSL_CRC_CRC32C_H_ |
| |
| #include <cstdint> |
| #include <ostream> |
| |
| #include "absl/crc/internal/crc32c_inline.h" |
| #include "absl/strings/str_format.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| //----------------------------------------------------------------------------- |
| // crc32c_t |
| //----------------------------------------------------------------------------- |
| |
| // `crc32c_t` defines a strongly-typed integer for holding a CRC32C value. |
| // |
| // Some operators are intentionally omitted. Only equality operators are defined |
| // so that `crc32c_t` can be directly compared. Methods for putting `crc32c_t` |
| // directly into a set are omitted because this is bug-prone due to checksum |
| // collisions. Use an explicit conversion to the `uint32_t` space for operations |
| // that treat `crc32c_t` as an integer. |
| class crc32c_t final { |
| public: |
| crc32c_t() = default; |
| constexpr explicit crc32c_t(uint32_t crc) : crc_(crc) {} |
| |
| crc32c_t(const crc32c_t&) = default; |
| crc32c_t& operator=(const crc32c_t&) = default; |
| |
| explicit operator uint32_t() const { return crc_; } |
| |
| friend bool operator==(crc32c_t lhs, crc32c_t rhs) { |
| return static_cast<uint32_t>(lhs) == static_cast<uint32_t>(rhs); |
| } |
| |
| friend bool operator!=(crc32c_t lhs, crc32c_t rhs) { return !(lhs == rhs); } |
| |
| template <typename Sink> |
| friend void AbslStringify(Sink& sink, crc32c_t crc) { |
| absl::Format(&sink, "%08x", static_cast<uint32_t>(crc)); |
| } |
| |
| private: |
| uint32_t crc_; |
| }; |
| |
| |
| namespace crc_internal { |
| // Non-inline code path for `absl::ExtendCrc32c()`. Do not call directly. |
| // Call `absl::ExtendCrc32c()` (defined below) instead. |
| crc32c_t ExtendCrc32cInternal(crc32c_t initial_crc, |
| absl::string_view buf_to_add); |
| } // namespace crc_internal |
| |
| // ----------------------------------------------------------------------------- |
| // CRC32C Computation Functions |
| // ----------------------------------------------------------------------------- |
| |
| // ExtendCrc32c() |
| // |
| // Computes a CRC32C value from an `initial_crc` CRC32C value including the |
| // `buf_to_add` bytes of an additional buffer. Using this function is more |
| // efficient than computing a CRC32C value for the combined buffer from |
| // scratch. |
| // |
| // Note: `ExtendCrc32c` with an initial_crc of 0 is equivalent to |
| // `ComputeCrc32c`. |
| // |
| // This operation has a runtime cost of O(`buf_to_add.size()`) |
| inline crc32c_t ExtendCrc32c(crc32c_t initial_crc, |
| absl::string_view buf_to_add) { |
| // Approximately 75% of calls have size <= 64. |
| if (buf_to_add.size() <= 64) { |
| uint32_t crc = static_cast<uint32_t>(initial_crc); |
| if (crc_internal::ExtendCrc32cInline(&crc, buf_to_add.data(), |
| buf_to_add.size())) { |
| return crc32c_t{crc}; |
| } |
| } |
| return crc_internal::ExtendCrc32cInternal(initial_crc, buf_to_add); |
| } |
| |
| // ComputeCrc32c() |
| // |
| // Returns the CRC32C value of the provided string. |
| inline crc32c_t ComputeCrc32c(absl::string_view buf) { |
| return ExtendCrc32c(crc32c_t{0}, buf); |
| } |
| |
| // ExtendCrc32cByZeroes() |
| // |
| // Computes a CRC32C value for a buffer with an `initial_crc` CRC32C value, |
| // where `length` bytes with a value of 0 are appended to the buffer. Using this |
| // function is more efficient than computing a CRC32C value for the combined |
| // buffer from scratch. |
| // |
| // This operation has a runtime cost of O(log(`length`)) |
| crc32c_t ExtendCrc32cByZeroes(crc32c_t initial_crc, size_t length); |
| |
| // MemcpyCrc32c() |
| // |
| // Copies `src` to `dest` using `memcpy()` semantics, returning the CRC32C |
| // value of the copied buffer. |
| // |
| // Using `MemcpyCrc32c()` is potentially faster than performing the `memcpy()` |
| // and `ComputeCrc32c()` operations separately. |
| crc32c_t MemcpyCrc32c(void* dest, const void* src, size_t count, |
| crc32c_t initial_crc = crc32c_t{0}); |
| |
| // ----------------------------------------------------------------------------- |
| // CRC32C Arithmetic Functions |
| // ----------------------------------------------------------------------------- |
| |
| // The following functions perform arithmetic on CRC32C values, which are |
| // generally more efficient than recalculating any given result's CRC32C value. |
| |
| // ConcatCrc32c() |
| // |
| // Calculates the CRC32C value of two buffers with known CRC32C values |
| // concatenated together. |
| // |
| // Given a buffer with CRC32C value `crc1` and a buffer with |
| // CRC32C value `crc2` and length, `crc2_length`, returns the CRC32C value of |
| // the concatenation of these two buffers. |
| // |
| // This operation has a runtime cost of O(log(`crc2_length`)). |
| crc32c_t ConcatCrc32c(crc32c_t crc1, crc32c_t crc2, size_t crc2_length); |
| |
| // RemoveCrc32cPrefix() |
| // |
| // Calculates the CRC32C value of an existing buffer with a series of bytes |
| // (the prefix) removed from the beginning of that buffer. |
| // |
| // Given the CRC32C value of an existing buffer, `full_string_crc`; The CRC32C |
| // value of a prefix of that buffer, `prefix_crc`; and the length of the buffer |
| // with the prefix removed, `remaining_string_length` , return the CRC32C |
| // value of the buffer with the prefix removed. |
| // |
| // This operation has a runtime cost of O(log(`remaining_string_length`)). |
| crc32c_t RemoveCrc32cPrefix(crc32c_t prefix_crc, crc32c_t full_string_crc, |
| size_t remaining_string_length); |
| // RemoveCrc32cSuffix() |
| // |
| // Calculates the CRC32C value of an existing buffer with a series of bytes |
| // (the suffix) removed from the end of that buffer. |
| // |
| // Given a CRC32C value of an existing buffer `full_string_crc`, the CRC32C |
| // value of the suffix to remove `suffix_crc`, and the length of that suffix |
| // `suffix_len`, returns the CRC32C value of the buffer with suffix removed. |
| // |
| // This operation has a runtime cost of O(log(`suffix_len`)) |
| crc32c_t RemoveCrc32cSuffix(crc32c_t full_string_crc, crc32c_t suffix_crc, |
| size_t suffix_length); |
| |
| // operator<< |
| // |
| // Streams the CRC32C value `crc` to the stream `os`. |
| inline std::ostream& operator<<(std::ostream& os, crc32c_t crc) { |
| return os << absl::StreamFormat("%08x", static_cast<uint32_t>(crc)); |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CRC_CRC32C_H_ |
| *ñ. |
| {soong/.intermediates/external/abseil-cpp/absl_crc_crc_cord_state_hdrs/gen/my_include_dir/absl/crc/internal/crc_cord_state.hñ-// Copyright 2022 The Abseil Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_CRC_INTERNAL_CRC_CORD_STATE_H_ |
| #define ABSL_CRC_INTERNAL_CRC_CORD_STATE_H_ |
| |
| #include <atomic> |
| #include <cstddef> |
| #include <deque> |
| |
| #include "absl/base/config.h" |
| #include "absl/crc/crc32c.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace crc_internal { |
| |
| // CrcCordState is a copy-on-write class that holds the chunked CRC32C data |
| // that allows CrcCord to perform efficient substring operations. CrcCordState |
| // is used as a member variable in CrcCord. When a CrcCord is converted to a |
| // Cord, the CrcCordState is shallow-copied into the root node of the Cord. If |
| // the converted Cord is modified outside of CrcCord, the CrcCordState is |
| // discarded from the Cord. If the Cord is converted back to a CrcCord, and the |
| // Cord is still carrying the CrcCordState in its root node, the CrcCord can |
| // re-use the CrcCordState, making the construction of the CrcCord cheap. |
| // |
| // CrcCordState does not try to encapsulate the CRC32C state (CrcCord requires |
| // knowledge of how CrcCordState represents the CRC32C state). It does |
| // encapsulate the copy-on-write nature of the state. |
| class CrcCordState { |
| public: |
| // Constructors. |
| CrcCordState(); |
| CrcCordState(const CrcCordState&); |
| CrcCordState(CrcCordState&&); |
| |
| // Destructor. Atomically unreferences the data. |
| ~CrcCordState(); |
| |
| // Copy and move operators. |
| CrcCordState& operator=(const CrcCordState&); |
| CrcCordState& operator=(CrcCordState&&); |
| |
| // A (length, crc) pair. |
| struct PrefixCrc { |
| PrefixCrc() = default; |
| PrefixCrc(size_t length_arg, absl::crc32c_t crc_arg) |
| : length(length_arg), crc(crc_arg) {} |
| |
| size_t length = 0; |
| |
| // TODO(absl-team): Memory stomping often zeros out memory. If this struct |
| // gets overwritten, we could end up with {0, 0}, which is the correct CRC |
| // for a string of length 0. Consider storing a scrambled value and |
| // unscrambling it before verifying it. |
| absl::crc32c_t crc = absl::crc32c_t{0}; |
| }; |
| |
| // The representation of the chunked CRC32C data. |
| struct Rep { |
| // `removed_prefix` is the crc and length of any prefix that has been |
| // removed from the Cord (for example, by calling |
| // `CrcCord::RemovePrefix()`). To get the checksum of any prefix of the |
| // cord, this value must be subtracted from `prefix_crc`. See `Checksum()` |
| // for an example. |
| // |
| // CrcCordState is said to be "normalized" if removed_prefix.length == 0. |
| PrefixCrc removed_prefix; |
| |
| // A deque of (length, crc) pairs, representing length and crc of a prefix |
| // of the Cord, before removed_prefix has been subtracted. The lengths of |
| // the prefixes are stored in increasing order. If the Cord is not empty, |
| // the last value in deque is the contains the CRC32C of the entire Cord |
| // when removed_prefix is subtracted from it. |
| std::deque<PrefixCrc> prefix_crc; |
| }; |
| |
| // Returns a reference to the representation of the chunked CRC32C data. |
| const Rep& rep() const { return refcounted_rep_->rep; } |
| |
| // Returns a mutable reference to the representation of the chunked CRC32C |
| // data. Calling this function will copy the data if another instance also |
| // holds a reference to the data, so it is important to call rep() instead if |
| // the data may not be mutated. |
| Rep* mutable_rep() { |
| if (refcounted_rep_->count.load(std::memory_order_acquire) != 1) { |
| RefcountedRep* copy = new RefcountedRep; |
| copy->rep = refcounted_rep_->rep; |
| Unref(refcounted_rep_); |
| refcounted_rep_ = copy; |
| } |
| return &refcounted_rep_->rep; |
| } |
| |
| // Returns the CRC32C of the entire Cord. |
| absl::crc32c_t Checksum() const; |
| |
| // Returns true if the chunked CRC32C cached is normalized. |
| bool IsNormalized() const { return rep().removed_prefix.length == 0; } |
| |
| // Normalizes the chunked CRC32C checksum cache by subtracting any removed |
| // prefix from the chunks. |
| void Normalize(); |
| |
| // Returns the number of cached chunks. |
| size_t NumChunks() const { return rep().prefix_crc.size(); } |
| |
| // Helper that returns the (length, crc) of the `n`-th cached chunked. |
| PrefixCrc NormalizedPrefixCrcAtNthChunk(size_t n) const; |
| |
| // Poisons all chunks to so that Checksum() will likely be incorrect with high |
| // probability. |
| void Poison(); |
| |
| private: |
| struct RefcountedRep { |
| std::atomic<int32_t> count{1}; |
| Rep rep; |
| }; |
| |
| // Adds a reference to the shared global empty `RefcountedRep`, and returns a |
| // pointer to the `RefcountedRep`. This is an optimization to avoid unneeded |
| // allocations when the allocation is unlikely to ever be used. The returned |
| // pointer can be `Unref()`ed when it is no longer needed. Since the returned |
| // instance will always have a reference counter greater than 1, attempts to |
| // modify it (by calling `mutable_rep()`) will create a new unshared copy. |
| static RefcountedRep* RefSharedEmptyRep(); |
| |
| static void Ref(RefcountedRep* r) { |
| assert(r != nullptr); |
| r->count.fetch_add(1, std::memory_order_relaxed); |
| } |
| |
| static void Unref(RefcountedRep* r) { |
| assert(r != nullptr); |
| if (r->count.fetch_sub(1, std::memory_order_acq_rel) == 1) { |
| delete r; |
| } |
| } |
| |
| RefcountedRep* refcounted_rep_; |
| }; |
| |
| } // namespace crc_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CRC_INTERNAL_CRC_CORD_STATE_H_ |
| *Ì |
| fsoong/.intermediates/external/abseil-cpp/absl_strings_cord_hdrs/gen/my_include_dir/absl/strings/cord.hà// 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. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: cord.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This file defines the `absl::Cord` data structure and operations on that data |
| // structure. A Cord is a string-like sequence of characters optimized for |
| // specific use cases. Unlike a `std::string`, which stores an array of |
| // contiguous characters, Cord data is stored in a structure consisting of |
| // separate, reference-counted "chunks." |
| // |
| // Because a Cord consists of these chunks, data can be added to or removed from |
| // a Cord during its lifetime. Chunks may also be shared between Cords. Unlike a |
| // `std::string`, a Cord can therefore accommodate data that changes over its |
| // lifetime, though it's not quite "mutable"; it can change only in the |
| // attachment, detachment, or rearrangement of chunks of its constituent data. |
| // |
| // A Cord provides some benefit over `std::string` under the following (albeit |
| // narrow) circumstances: |
| // |
| // * Cord data is designed to grow and shrink over a Cord's lifetime. Cord |
| // provides efficient insertions and deletions at the start and end of the |
| // character sequences, avoiding copies in those cases. Static data should |
| // generally be stored as strings. |
| // * External memory consisting of string-like data can be directly added to |
| // a Cord without requiring copies or allocations. |
| // * Cord data may be shared and copied cheaply. Cord provides a copy-on-write |
| // implementation and cheap sub-Cord operations. Copying a Cord is an O(1) |
| // operation. |
| // |
| // As a consequence to the above, Cord data is generally large. Small data |
| // should generally use strings, as construction of a Cord requires some |
| // overhead. Small Cords (<= 15 bytes) are represented inline, but most small |
| // Cords are expected to grow over their lifetimes. |
| // |
| // Note that because a Cord is made up of separate chunked data, random access |
| // to character data within a Cord is slower than within a `std::string`. |
| // |
| // Thread Safety |
| // |
| // Cord has the same thread-safety properties as many other types like |
| // std::string, std::vector<>, int, etc -- it is thread-compatible. In |
| // particular, if threads do not call non-const methods, then it is safe to call |
| // const methods without synchronization. Copying a Cord produces a new instance |
| // that can be used concurrently with the original in arbitrary ways. |
| |
| #ifndef ABSL_STRINGS_CORD_H_ |
| #define ABSL_STRINGS_CORD_H_ |
| |
| #include <algorithm> |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <iosfwd> |
| #include <iterator> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/endian.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/optimization.h" |
| #include "absl/crc/internal/crc_cord_state.h" |
| #include "absl/functional/function_ref.h" |
| #include "absl/hash/internal/weakly_mixed_integer.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/strings/cord_analysis.h" |
| #include "absl/strings/cord_buffer.h" |
| #include "absl/strings/internal/cord_data_edge.h" |
| #include "absl/strings/internal/cord_internal.h" |
| #include "absl/strings/internal/cord_rep_btree.h" |
| #include "absl/strings/internal/cord_rep_btree_reader.h" |
| #include "absl/strings/internal/cord_rep_crc.h" |
| #include "absl/strings/internal/cord_rep_flat.h" |
| #include "absl/strings/internal/cordz_info.h" |
| #include "absl/strings/internal/cordz_update_scope.h" |
| #include "absl/strings/internal/cordz_update_tracker.h" |
| #include "absl/strings/internal/string_constant.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/types/compare.h" |
| #include "absl/types/optional.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| class Cord; |
| class CordTestPeer; |
| template <typename Releaser> |
| Cord MakeCordFromExternal(absl::string_view, Releaser&&); |
| void CopyCordToString(const Cord& src, std::string* absl_nonnull dst); |
| void AppendCordToString(const Cord& src, std::string* absl_nonnull dst); |
| |
| // Cord memory accounting modes |
| enum class CordMemoryAccounting { |
| // Counts the *approximate* number of bytes held in full or in part by this |
| // Cord (which may not remain the same between invocations). Cords that share |
| // memory could each be "charged" independently for the same shared memory. |
| // See also comment on `kTotalMorePrecise` on internally shared memory. |
| kTotal, |
| |
| // Counts the *approximate* number of bytes held in full or in part by this |
| // Cord for the distinct memory held by this cord. This option is similar |
| // to `kTotal`, except that if the cord has multiple references to the same |
| // memory, that memory is only counted once. |
| // |
| // For example: |
| // absl::Cord cord; |
| // cord.Append(some_other_cord); |
| // cord.Append(some_other_cord); |
| // // Counts `some_other_cord` twice: |
| // cord.EstimatedMemoryUsage(kTotal); |
| // // Counts `some_other_cord` once: |
| // cord.EstimatedMemoryUsage(kTotalMorePrecise); |
| // |
| // The `kTotalMorePrecise` number is more expensive to compute as it requires |
| // deduplicating all memory references. Applications should prefer to use |
| // `kFairShare` or `kTotal` unless they really need a more precise estimate |
| // on "how much memory is potentially held / kept alive by this cord?" |
| kTotalMorePrecise, |
| |
| // Counts the *approximate* number of bytes held in full or in part by this |
| // Cord weighted by the sharing ratio of that data. For example, if some data |
| // edge is shared by 4 different Cords, then each cord is attributed 1/4th of |
| // the total memory usage as a 'fair share' of the total memory usage. |
| kFairShare, |
| }; |
| |
| // Cord |
| // |
| // A Cord is a sequence of characters, designed to be more efficient than a |
| // `std::string` in certain circumstances: namely, large string data that needs |
| // to change over its lifetime or shared, especially when such data is shared |
| // across API boundaries. |
| // |
| // A Cord stores its character data in a structure that allows efficient prepend |
| // and append operations. This makes a Cord useful for large string data sent |
| // over in a wire format that may need to be prepended or appended at some point |
| // during the data exchange (e.g. HTTP, protocol buffers). For example, a |
| // Cord is useful for storing an HTTP request, and prepending an HTTP header to |
| // such a request. |
| // |
| // Cords should not be used for storing general string data, however. They |
| // require overhead to construct and are slower than strings for random access. |
| // |
| // The Cord API provides the following common API operations: |
| // |
| // * Create or assign Cords out of existing string data, memory, or other Cords |
| // * Append and prepend data to an existing Cord |
| // * Create new Sub-Cords from existing Cord data |
| // * Swap Cord data and compare Cord equality |
| // * Write out Cord data by constructing a `std::string` |
| // |
| // Additionally, the API provides iterator utilities to iterate through Cord |
| // data via chunks or character bytes. |
| // |
| class Cord { |
| private: |
| template <typename T> |
| using EnableIfString = |
| absl::enable_if_t<std::is_same<T, std::string>::value, int>; |
| |
| public: |
| // Cord::Cord() Constructors. |
| |
| // Creates an empty Cord. |
| constexpr Cord() noexcept; |
| |
| // Creates a Cord from an existing Cord. Cord is copyable and efficiently |
| // movable. The moved-from state is valid but unspecified. |
| Cord(const Cord& src); |
| Cord(Cord&& src) noexcept; |
| Cord& operator=(const Cord& x); |
| Cord& operator=(Cord&& x) noexcept; |
| |
| // Creates a Cord from a `src` string. This constructor is marked explicit to |
| // prevent implicit Cord constructions from arguments convertible to an |
| // `absl::string_view`. |
| explicit Cord(absl::string_view src); |
| Cord& operator=(absl::string_view src); |
| |
| // Creates a Cord from a `std::string&&` rvalue. These constructors are |
| // templated to avoid ambiguities for types that are convertible to both |
| // `absl::string_view` and `std::string`, such as `const char*`. |
| template <typename T, EnableIfString<T> = 0> |
| explicit Cord(T&& src); |
| template <typename T, EnableIfString<T> = 0> |
| Cord& operator=(T&& src); |
| |
| // Cord::~Cord() |
| // |
| // Destructs the Cord. |
| ~Cord() { |
| if (contents_.is_tree()) DestroyCordSlow(); |
| } |
| |
| // MakeCordFromExternal() |
| // |
| // Creates a Cord that takes ownership of external string memory. The |
| // contents of `data` are not copied to the Cord; instead, the external |
| // memory is added to the Cord and reference-counted. This data may not be |
| // changed for the life of the Cord, though it may be prepended or appended |
| // to. |
| // |
| // `MakeCordFromExternal()` takes a callable "releaser" that is invoked when |
| // the reference count for `data` reaches zero. As noted above, this data must |
| // remain live until the releaser is invoked. The callable releaser also must: |
| // |
| // * be move constructible |
| // * support `void operator()(absl::string_view) const` or `void operator()` |
| // |
| // Example: |
| // |
| // Cord MakeCord(BlockPool* pool) { |
| // Block* block = pool->NewBlock(); |
| // FillBlock(block); |
| // return absl::MakeCordFromExternal( |
| // block->ToStringView(), |
| // [pool, block](absl::string_view v) { |
| // pool->FreeBlock(block, v); |
| // }); |
| // } |
| // |
| // WARNING: Because a Cord can be reference-counted, it's likely a bug if your |
| // releaser doesn't do anything. For example, consider the following: |
| // |
| // void Foo(const char* buffer, int len) { |
| // auto c = absl::MakeCordFromExternal(absl::string_view(buffer, len), |
| // [](absl::string_view) {}); |
| // |
| // // BUG: If Bar() copies its cord for any reason, including keeping a |
| // // substring of it, the lifetime of buffer might be extended beyond |
| // // when Foo() returns. |
| // Bar(c); |
| // } |
| template <typename Releaser> |
| friend Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser); |
| |
| // Cord::Clear() |
| // |
| // Releases the Cord data. Any nodes that share data with other Cords, if |
| // applicable, will have their reference counts reduced by 1. |
| ABSL_ATTRIBUTE_REINITIALIZES void Clear(); |
| |
| // Cord::Append() |
| // |
| // Appends data to the Cord, which may come from another Cord or other string |
| // data. |
| void Append(const Cord& src); |
| void Append(Cord&& src); |
| void Append(absl::string_view src); |
| template <typename T, EnableIfString<T> = 0> |
| void Append(T&& src); |
| |
| // Appends `buffer` to this cord, unless `buffer` has a zero length in which |
| // case this method has no effect on this cord instance. |
| // This method is guaranteed to consume `buffer`. |
| void Append(CordBuffer buffer); |
| |
| // Returns a CordBuffer, re-using potential existing capacity in this cord. |
| // |
| // Cord instances may have additional unused capacity in the last (or first) |
| // nodes of the underlying tree to facilitate amortized growth. This method |
| // allows applications to explicitly use this spare capacity if available, |
| // or create a new CordBuffer instance otherwise. |
| // If this cord has a final non-shared node with at least `min_capacity` |
| // available, then this method will return that buffer including its data |
| // contents. I.e.; the returned buffer will have a non-zero length, and |
| // a capacity of at least `buffer.length + min_capacity`. Otherwise, this |
| // method will return `CordBuffer::CreateWithDefaultLimit(capacity)`. |
| // |
| // Below an example of using GetAppendBuffer. Notice that in this example we |
| // use `GetAppendBuffer()` only on the first iteration. As we know nothing |
| // about any initial extra capacity in `cord`, we may be able to use the extra |
| // capacity. But as we add new buffers with fully utilized contents after that |
| // we avoid calling `GetAppendBuffer()` on subsequent iterations: while this |
| // works fine, it results in an unnecessary inspection of cord contents: |
| // |
| // void AppendRandomDataToCord(absl::Cord &cord, size_t n) { |
| // bool first = true; |
| // while (n > 0) { |
| // CordBuffer buffer = first ? cord.GetAppendBuffer(n) |
| // : CordBuffer::CreateWithDefaultLimit(n); |
| // absl::Span<char> data = buffer.available_up_to(n); |
| // FillRandomValues(data.data(), data.size()); |
| // buffer.IncreaseLengthBy(data.size()); |
| // cord.Append(std::move(buffer)); |
| // n -= data.size(); |
| // first = false; |
| // } |
| // } |
| CordBuffer GetAppendBuffer(size_t capacity, size_t min_capacity = 16); |
| |
| // Returns a CordBuffer, re-using potential existing capacity in this cord. |
| // |
| // This function is identical to `GetAppendBuffer`, except that in the case |
| // where a new `CordBuffer` is allocated, it is allocated using the provided |
| // custom limit instead of the default limit. `GetAppendBuffer` will default |
| // to `CordBuffer::CreateWithDefaultLimit(capacity)` whereas this method |
| // will default to `CordBuffer::CreateWithCustomLimit(block_size, capacity)`. |
| // This method is equivalent to `GetAppendBuffer` if `block_size` is zero. |
| // See the documentation for `CreateWithCustomLimit` for more details on the |
| // restrictions and legal values for `block_size`. |
| CordBuffer GetCustomAppendBuffer(size_t block_size, size_t capacity, |
| size_t min_capacity = 16); |
| |
| // Cord::Prepend() |
| // |
| // Prepends data to the Cord, which may come from another Cord or other string |
| // data. |
| void Prepend(const Cord& src); |
| void Prepend(absl::string_view src); |
| template <typename T, EnableIfString<T> = 0> |
| void Prepend(T&& src); |
| |
| // Prepends `buffer` to this cord, unless `buffer` has a zero length in which |
| // case this method has no effect on this cord instance. |
| // This method is guaranteed to consume `buffer`. |
| void Prepend(CordBuffer buffer); |
| |
| // Cord::RemovePrefix() |
| // |
| // Removes the first `n` bytes of a Cord. |
| void RemovePrefix(size_t n); |
| void RemoveSuffix(size_t n); |
| |
| // Cord::Subcord() |
| // |
| // Returns a new Cord representing the subrange [pos, pos + new_size) of |
| // *this. If pos >= size(), the result is empty(). If |
| // (pos + new_size) >= size(), the result is the subrange [pos, size()). |
| Cord Subcord(size_t pos, size_t new_size) const; |
| |
| // Cord::swap() |
| // |
| // Swaps the contents of the Cord with `other`. |
| void swap(Cord& other) noexcept; |
| |
| // swap() |
| // |
| // Swaps the contents of two Cords. |
| friend void swap(Cord& x, Cord& y) noexcept { x.swap(y); } |
| |
| // Cord::size() |
| // |
| // Returns the size of the Cord. |
| size_t size() const; |
| |
| // Cord::empty() |
| // |
| // Determines whether the given Cord is empty, returning `true` if so. |
| bool empty() const; |
| |
| // Cord::EstimatedMemoryUsage() |
| // |
| // Returns the *approximate* number of bytes held by this cord. |
| // See CordMemoryAccounting for more information on the accounting method. |
| size_t EstimatedMemoryUsage(CordMemoryAccounting accounting_method = |
| CordMemoryAccounting::kTotal) const; |
| |
| // Cord::Compare() |
| // |
| // Compares 'this' Cord with rhs. This function and its relatives treat Cords |
| // as sequences of unsigned bytes. The comparison is a straightforward |
| // lexicographic comparison. `Cord::Compare()` returns values as follows: |
| // |
| // -1 'this' Cord is smaller |
| // 0 two Cords are equal |
| // 1 'this' Cord is larger |
| int Compare(absl::string_view rhs) const; |
| int Compare(const Cord& rhs) const; |
| |
| // Cord::StartsWith() |
| // |
| // Determines whether the Cord starts with the passed string data `rhs`. |
| bool StartsWith(const Cord& rhs) const; |
| bool StartsWith(absl::string_view rhs) const; |
| |
| // Cord::EndsWith() |
| // |
| // Determines whether the Cord ends with the passed string data `rhs`. |
| bool EndsWith(absl::string_view rhs) const; |
| bool EndsWith(const Cord& rhs) const; |
| |
| // Cord::Contains() |
| // |
| // Determines whether the Cord contains the passed string data `rhs`. |
| bool Contains(absl::string_view rhs) const; |
| bool Contains(const Cord& rhs) const; |
| |
| // Cord::operator std::string() |
| // |
| // Converts a Cord into a `std::string()`. This operator is marked explicit to |
| // prevent unintended Cord usage in functions that take a string. |
| explicit operator std::string() const; |
| |
| // CopyCordToString() |
| // |
| // Copies the contents of a `src` Cord into a `*dst` string. |
| // |
| // This function optimizes the case of reusing the destination string since it |
| // can reuse previously allocated capacity. However, this function does not |
| // guarantee that pointers previously returned by `dst->data()` remain valid |
| // even if `*dst` had enough capacity to hold `src`. If `*dst` is a new |
| // object, prefer to simply use the conversion operator to `std::string`. |
| friend void CopyCordToString(const Cord& src, std::string* absl_nonnull dst); |
| |
| // AppendCordToString() |
| // |
| // Appends the contents of a `src` Cord to a `*dst` string. |
| // |
| // This function optimizes the case of appending to a non-empty destination |
| // string. If `*dst` already has capacity to store the contents of the cord, |
| // this function does not invalidate pointers previously returned by |
| // `dst->data()`. If `*dst` is a new object, prefer to simply use the |
| // conversion operator to `std::string`. |
| friend void AppendCordToString(const Cord& src, |
| std::string* absl_nonnull dst); |
| |
| class CharIterator; |
| |
| //---------------------------------------------------------------------------- |
| // Cord::ChunkIterator |
| //---------------------------------------------------------------------------- |
| // |
| // A `Cord::ChunkIterator` allows iteration over the constituent chunks of its |
| // Cord. Such iteration allows you to perform non-const operations on the data |
| // of a Cord without modifying it. |
| // |
| // Generally, you do not instantiate a `Cord::ChunkIterator` directly; |
| // instead, you create one implicitly through use of the `Cord::Chunks()` |
| // member function. |
| // |
| // The `Cord::ChunkIterator` has the following properties: |
| // |
| // * The iterator is invalidated after any non-const operation on the |
| // Cord object over which it iterates. |
| // * The `string_view` returned by dereferencing a valid, non-`end()` |
| // iterator is guaranteed to be non-empty. |
| // * Two `ChunkIterator` objects can be compared equal if and only if they |
| // remain valid and iterate over the same Cord. |
| // * The iterator in this case is a proxy iterator; the `string_view` |
| // returned by the iterator does not live inside the Cord, and its |
| // lifetime is limited to the lifetime of the iterator itself. To help |
| // prevent lifetime issues, `ChunkIterator::reference` is not a true |
| // reference type and is equivalent to `value_type`. |
| // * The iterator keeps state that can grow for Cords that contain many |
| // nodes and are imbalanced due to sharing. Prefer to pass this type by |
| // const reference instead of by value. |
| class ChunkIterator { |
| public: |
| using iterator_category = std::input_iterator_tag; |
| using value_type = absl::string_view; |
| using difference_type = ptrdiff_t; |
| using pointer = const value_type* absl_nonnull; |
| using reference = value_type; |
| |
| ChunkIterator() = default; |
| |
| ChunkIterator& operator++(); |
| ChunkIterator operator++(int); |
| bool operator==(const ChunkIterator& other) const; |
| bool operator!=(const ChunkIterator& other) const; |
| reference operator*() const; |
| pointer operator->() const; |
| |
| friend class Cord; |
| friend class CharIterator; |
| |
| private: |
| using CordRep = absl::cord_internal::CordRep; |
| using CordRepBtree = absl::cord_internal::CordRepBtree; |
| using CordRepBtreeReader = absl::cord_internal::CordRepBtreeReader; |
| |
| // Constructs a `begin()` iterator from `tree`. |
| explicit ChunkIterator(cord_internal::CordRep* absl_nonnull tree); |
| |
| // Constructs a `begin()` iterator from `cord`. |
| explicit ChunkIterator(const Cord* absl_nonnull cord); |
| |
| // Initializes this instance from a tree. Invoked by constructors. |
| void InitTree(cord_internal::CordRep* absl_nonnull tree); |
| |
| // Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than |
| // `current_chunk_.size()`. |
| void RemoveChunkPrefix(size_t n); |
| Cord AdvanceAndReadBytes(size_t n); |
| void AdvanceBytes(size_t n); |
| |
| // Btree specific operator++ |
| ChunkIterator& AdvanceBtree(); |
| void AdvanceBytesBtree(size_t n); |
| |
| // A view into bytes of the current `CordRep`. It may only be a view to a |
| // suffix of bytes if this is being used by `CharIterator`. |
| absl::string_view current_chunk_; |
| // The current leaf, or `nullptr` if the iterator points to short data. |
| // If the current chunk is a substring node, current_leaf_ points to the |
| // underlying flat or external node. |
| absl::cord_internal::CordRep* absl_nullable current_leaf_ = nullptr; |
| // The number of bytes left in the `Cord` over which we are iterating. |
| size_t bytes_remaining_ = 0; |
| |
| // Cord reader for cord btrees. Empty if not traversing a btree. |
| CordRepBtreeReader btree_reader_; |
| }; |
| |
| // Cord::chunk_begin() |
| // |
| // Returns an iterator to the first chunk of the `Cord`. |
| // |
| // Generally, prefer using `Cord::Chunks()` within a range-based for loop for |
| // iterating over the chunks of a Cord. This method may be useful for getting |
| // a `ChunkIterator` where range-based for-loops are not useful. |
| // |
| // Example: |
| // |
| // absl::Cord::ChunkIterator FindAsChunk(const absl::Cord& c, |
| // absl::string_view s) { |
| // return std::find(c.chunk_begin(), c.chunk_end(), s); |
| // } |
| ChunkIterator chunk_begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND; |
| |
| // Cord::chunk_end() |
| // |
| // Returns an iterator one increment past the last chunk of the `Cord`. |
| // |
| // Generally, prefer using `Cord::Chunks()` within a range-based for loop for |
| // iterating over the chunks of a Cord. This method may be useful for getting |
| // a `ChunkIterator` where range-based for-loops may not be available. |
| ChunkIterator chunk_end() const ABSL_ATTRIBUTE_LIFETIME_BOUND; |
| |
| //---------------------------------------------------------------------------- |
| // Cord::ChunkRange |
| //---------------------------------------------------------------------------- |
| // |
| // `ChunkRange` is a helper class for iterating over the chunks of the `Cord`, |
| // producing an iterator which can be used within a range-based for loop. |
| // Construction of a `ChunkRange` will return an iterator pointing to the |
| // first chunk of the Cord. Generally, do not construct a `ChunkRange` |
| // directly; instead, prefer to use the `Cord::Chunks()` method. |
| // |
| // Implementation note: `ChunkRange` is simply a convenience wrapper over |
| // `Cord::chunk_begin()` and `Cord::chunk_end()`. |
| class ChunkRange { |
| public: |
| // Fulfill minimum c++ container requirements [container.requirements] |
| // These (partial) container type definitions allow ChunkRange to be used |
| // in various utilities expecting a subset of [container.requirements]. |
| // For example, the below enables using `::testing::ElementsAre(...)` |
| using value_type = absl::string_view; |
| using reference = value_type&; |
| using const_reference = const value_type&; |
| using iterator = ChunkIterator; |
| using const_iterator = ChunkIterator; |
| |
| explicit ChunkRange(const Cord* absl_nonnull cord) : cord_(cord) {} |
| |
| ChunkIterator begin() const; |
| ChunkIterator end() const; |
| |
| private: |
| const Cord* absl_nonnull cord_; |
| }; |
| |
| // Cord::Chunks() |
| // |
| // Returns a `Cord::ChunkRange` for iterating over the chunks of a `Cord` with |
| // a range-based for-loop. For most iteration tasks on a Cord, use |
| // `Cord::Chunks()` to retrieve this iterator. |
| // |
| // Example: |
| // |
| // void ProcessChunks(const Cord& cord) { |
| // for (absl::string_view chunk : cord.Chunks()) { ... } |
| // } |
| // |
| // Note that the ordinary caveats of temporary lifetime extension apply: |
| // |
| // void Process() { |
| // for (absl::string_view chunk : CordFactory().Chunks()) { |
| // // The temporary Cord returned by CordFactory has been destroyed! |
| // } |
| // } |
| ChunkRange Chunks() const ABSL_ATTRIBUTE_LIFETIME_BOUND; |
| |
| //---------------------------------------------------------------------------- |
| // Cord::CharIterator |
| //---------------------------------------------------------------------------- |
| // |
| // A `Cord::CharIterator` allows iteration over the constituent characters of |
| // a `Cord`. |
| // |
| // Generally, you do not instantiate a `Cord::CharIterator` directly; instead, |
| // you create one implicitly through use of the `Cord::Chars()` member |
| // function. |
| // |
| // A `Cord::CharIterator` has the following properties: |
| // |
| // * The iterator is invalidated after any non-const operation on the |
| // Cord object over which it iterates. |
| // * Two `CharIterator` objects can be compared equal if and only if they |
| // remain valid and iterate over the same Cord. |
| // * The iterator keeps state that can grow for Cords that contain many |
| // nodes and are imbalanced due to sharing. Prefer to pass this type by |
| // const reference instead of by value. |
| // * This type cannot act as a forward iterator because a `Cord` can reuse |
| // sections of memory. This fact violates the requirement for forward |
| // iterators to compare equal if dereferencing them returns the same |
| // object. |
| class CharIterator { |
| public: |
| using iterator_category = std::input_iterator_tag; |
| using value_type = char; |
| using difference_type = ptrdiff_t; |
| using pointer = const char* absl_nonnull; |
| using reference = const char&; |
| |
| CharIterator() = default; |
| |
| CharIterator& operator++(); |
| CharIterator operator++(int); |
| bool operator==(const CharIterator& other) const; |
| bool operator!=(const CharIterator& other) const; |
| reference operator*() const; |
| |
| friend Cord; |
| |
| private: |
| explicit CharIterator(const Cord* absl_nonnull cord) |
| : chunk_iterator_(cord) {} |
| |
| ChunkIterator chunk_iterator_; |
| }; |
| |
| // Cord::AdvanceAndRead() |
| // |
| // Advances the `Cord::CharIterator` by `n_bytes` and returns the bytes |
| // advanced as a separate `Cord`. `n_bytes` must be less than or equal to the |
| // number of bytes within the Cord; otherwise, behavior is undefined. It is |
| // valid to pass `char_end()` and `0`. |
| static Cord AdvanceAndRead(CharIterator* absl_nonnull it, size_t n_bytes); |
| |
| // Cord::Advance() |
| // |
| // Advances the `Cord::CharIterator` by `n_bytes`. `n_bytes` must be less than |
| // or equal to the number of bytes remaining within the Cord; otherwise, |
| // behavior is undefined. It is valid to pass `char_end()` and `0`. |
| static void Advance(CharIterator* absl_nonnull it, size_t n_bytes); |
| |
| // Cord::ChunkRemaining() |
| // |
| // Returns the longest contiguous view starting at the iterator's position. |
| // |
| // `it` must be dereferenceable. |
| static absl::string_view ChunkRemaining(const CharIterator& it); |
| |
| // Cord::Distance() |
| // |
| // Returns the distance between `first` and `last`, as if |
| // `std::distance(first, last)` was called. |
| static ptrdiff_t Distance(const CharIterator& first, |
| const CharIterator& last); |
| |
| // Cord::char_begin() |
| // |
| // Returns an iterator to the first character of the `Cord`. |
| // |
| // Generally, prefer using `Cord::Chars()` within a range-based for loop for |
| // iterating over the chunks of a Cord. This method may be useful for getting |
| // a `CharIterator` where range-based for-loops may not be available. |
| CharIterator char_begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND; |
| |
| // Cord::char_end() |
| // |
| // Returns an iterator to one past the last character of the `Cord`. |
| // |
| // Generally, prefer using `Cord::Chars()` within a range-based for loop for |
| // iterating over the chunks of a Cord. This method may be useful for getting |
| // a `CharIterator` where range-based for-loops are not useful. |
| CharIterator char_end() const ABSL_ATTRIBUTE_LIFETIME_BOUND; |
| |
| // Cord::CharRange |
| // |
| // `CharRange` is a helper class for iterating over the characters of a |
| // producing an iterator which can be used within a range-based for loop. |
| // Construction of a `CharRange` will return an iterator pointing to the first |
| // character of the Cord. Generally, do not construct a `CharRange` directly; |
| // instead, prefer to use the `Cord::Chars()` method shown below. |
| // |
| // Implementation note: `CharRange` is simply a convenience wrapper over |
| // `Cord::char_begin()` and `Cord::char_end()`. |
| class CharRange { |
| public: |
| // Fulfill minimum c++ container requirements [container.requirements] |
| // These (partial) container type definitions allow CharRange to be used |
| // in various utilities expecting a subset of [container.requirements]. |
| // For example, the below enables using `::testing::ElementsAre(...)` |
| using value_type = char; |
| using reference = value_type&; |
| using const_reference = const value_type&; |
| using iterator = CharIterator; |
| using const_iterator = CharIterator; |
| |
| explicit CharRange(const Cord* absl_nonnull cord) : cord_(cord) {} |
| |
| CharIterator begin() const; |
| CharIterator end() const; |
| |
| private: |
| const Cord* absl_nonnull cord_; |
| }; |
| |
| // Cord::Chars() |
| // |
| // Returns a `Cord::CharRange` for iterating over the characters of a `Cord` |
| // with a range-based for-loop. For most character-based iteration tasks on a |
| // Cord, use `Cord::Chars()` to retrieve this iterator. |
| // |
| // Example: |
| // |
| // void ProcessCord(const Cord& cord) { |
| // for (char c : cord.Chars()) { ... } |
| // } |
| // |
| // Note that the ordinary caveats of temporary lifetime extension apply: |
| // |
| // void Process() { |
| // for (char c : CordFactory().Chars()) { |
| // // The temporary Cord returned by CordFactory has been destroyed! |
| // } |
| // } |
| CharRange Chars() const ABSL_ATTRIBUTE_LIFETIME_BOUND; |
| |
| // Cord::operator[] |
| // |
| // Gets the "i"th character of the Cord and returns it, provided that |
| // 0 <= i < Cord.size(). |
| // |
| // NOTE: This routine is reasonably efficient. It is roughly |
| // logarithmic based on the number of chunks that make up the cord. Still, |
| // if you need to iterate over the contents of a cord, you should |
| // use a CharIterator/ChunkIterator rather than call operator[] or Get() |
| // repeatedly in a loop. |
| char operator[](size_t i) const; |
| |
| // Cord::TryFlat() |
| // |
| // If this cord's representation is a single flat array, returns a |
| // string_view referencing that array. Otherwise returns nullopt. |
| absl::optional<absl::string_view> TryFlat() const |
| ABSL_ATTRIBUTE_LIFETIME_BOUND; |
| |
| // Cord::Flatten() |
| // |
| // Flattens the cord into a single array and returns a view of the data. |
| // |
| // If the cord was already flat, the contents are not modified. |
| absl::string_view Flatten() ABSL_ATTRIBUTE_LIFETIME_BOUND; |
| |
| // Cord::Find() |
| // |
| // Returns an iterator to the first occurrence of the substring `needle`. |
| // |
| // If the substring `needle` does not occur, `Cord::char_end()` is returned. |
| CharIterator Find(absl::string_view needle) const; |
| CharIterator Find(const absl::Cord& needle) const; |
| |
| // Supports absl::Cord as a sink object for absl::Format(). |
| friend void AbslFormatFlush(absl::Cord* absl_nonnull cord, |
| absl::string_view part) { |
| cord->Append(part); |
| } |
| |
| // Support automatic stringification with absl::StrCat and absl::StrFormat. |
| template <typename Sink> |
| friend void AbslStringify(Sink& sink, const absl::Cord& cord) { |
| for (absl::string_view chunk : cord.Chunks()) { |
| sink.Append(chunk); |
| } |
| } |
| |
| // Cord::SetExpectedChecksum() |
| // |
| // Stores a checksum value with this non-empty cord instance, for later |
| // retrieval. |
| // |
| // The expected checksum is a number stored out-of-band, alongside the data. |
| // It is preserved across copies and assignments, but any mutations to a cord |
| // will cause it to lose its expected checksum. |
| // |
| // The expected checksum is not part of a Cord's value, and does not affect |
| // operations such as equality or hashing. |
| // |
| // This field is intended to store a CRC32C checksum for later validation, to |
| // help support end-to-end checksum workflows. However, the Cord API itself |
| // does no CRC validation, and assigns no meaning to this number. |
| // |
| // This call has no effect if this cord is empty. |
| void SetExpectedChecksum(uint32_t crc); |
| |
| // Returns this cord's expected checksum, if it has one. Otherwise, returns |
| // nullopt. |
| absl::optional<uint32_t> ExpectedChecksum() const; |
| |
| template <typename H> |
| friend H AbslHashValue(H hash_state, const absl::Cord& c) { |
| absl::optional<absl::string_view> maybe_flat = c.TryFlat(); |
| if (maybe_flat.has_value()) { |
| return H::combine(std::move(hash_state), *maybe_flat); |
| } |
| return c.HashFragmented(std::move(hash_state)); |
| } |
| |
| // Create a Cord with the contents of StringConstant<T>::value. |
| // No allocations will be done and no data will be copied. |
| // This is an INTERNAL API and subject to change or removal. This API can only |
| // be used by spelling absl::strings_internal::MakeStringConstant, which is |
| // also an internal API. |
| template <typename T> |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| constexpr Cord(strings_internal::StringConstant<T>); |
| |
| private: |
| using CordRep = absl::cord_internal::CordRep; |
| using CordRepFlat = absl::cord_internal::CordRepFlat; |
| using CordzInfo = cord_internal::CordzInfo; |
| using CordzUpdateScope = cord_internal::CordzUpdateScope; |
| using CordzUpdateTracker = cord_internal::CordzUpdateTracker; |
| using InlineData = cord_internal::InlineData; |
| using MethodIdentifier = CordzUpdateTracker::MethodIdentifier; |
| |
| // Creates a cord instance with `method` representing the originating |
| // public API call causing the cord to be created. |
| explicit Cord(absl::string_view src, MethodIdentifier method); |
| |
| friend class CordTestPeer; |
| friend bool operator==(const Cord& lhs, const Cord& rhs); |
| friend bool operator==(const Cord& lhs, absl::string_view rhs); |
| |
| #ifdef __cpp_impl_three_way_comparison |
| |
| // Cords support comparison with other Cords and string_views via operator< |
| // and others; here we provide a wrapper for the C++20 three-way comparison |
| // <=> operator. |
| |
| static inline std::strong_ordering ConvertCompareResultToStrongOrdering( |
| int c) { |
| if (c == 0) { |
| return std::strong_ordering::equal; |
| } else if (c < 0) { |
| return std::strong_ordering::less; |
| } else { |
| return std::strong_ordering::greater; |
| } |
| } |
| |
| friend inline std::strong_ordering operator<=>(const Cord& x, const Cord& y) { |
| return ConvertCompareResultToStrongOrdering(x.Compare(y)); |
| } |
| |
| friend inline std::strong_ordering operator<=>(const Cord& lhs, |
| absl::string_view rhs) { |
| return ConvertCompareResultToStrongOrdering(lhs.Compare(rhs)); |
| } |
| |
| friend inline std::strong_ordering operator<=>(absl::string_view lhs, |
| const Cord& rhs) { |
| return ConvertCompareResultToStrongOrdering(-rhs.Compare(lhs)); |
| } |
| #endif |
| |
| friend const CordzInfo* absl_nullable GetCordzInfoForTesting( |
| const Cord& cord); |
| |
| // Calls the provided function once for each cord chunk, in order. Unlike |
| // Chunks(), this API will not allocate memory. |
| void ForEachChunk(absl::FunctionRef<void(absl::string_view)>) const; |
| |
| // Allocates new contiguous storage for the contents of the cord. This is |
| // called by Flatten() when the cord was not already flat. |
| absl::string_view FlattenSlowPath(); |
| |
| // Actual cord contents are hidden inside the following simple |
| // class so that we can isolate the bulk of cord.cc from changes |
| // to the representation. |
| // |
| // InlineRep holds either a tree pointer, or an array of kMaxInline bytes. |
| class InlineRep { |
| public: |
| static constexpr unsigned char kMaxInline = cord_internal::kMaxInline; |
| static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), ""); |
| |
| constexpr InlineRep() : data_() {} |
| explicit InlineRep(InlineData::DefaultInitType init) : data_(init) {} |
| InlineRep(const InlineRep& src); |
| InlineRep(InlineRep&& src); |
| InlineRep& operator=(const InlineRep& src); |
| InlineRep& operator=(InlineRep&& src) noexcept; |
| |
| explicit constexpr InlineRep(absl::string_view sv, |
| CordRep* absl_nullable rep); |
| |
| void Swap(InlineRep* absl_nonnull rhs); |
| size_t size() const; |
| // Returns nullptr if holding pointer |
| const char* absl_nullable data() const; |
| // Discards pointer, if any |
| void set_data(const char* absl_nonnull data, size_t n); |
| char* absl_nonnull set_data(size_t n); // Write data to the result |
| // Returns nullptr if holding bytes |
| absl::cord_internal::CordRep* absl_nullable tree() const; |
| absl::cord_internal::CordRep* absl_nonnull as_tree() const; |
| const char* absl_nonnull as_chars() const; |
| // Returns non-null iff was holding a pointer |
| absl::cord_internal::CordRep* absl_nullable clear(); |
| // Converts to pointer if necessary. |
| void reduce_size(size_t n); // REQUIRES: holding data |
| void remove_prefix(size_t n); // REQUIRES: holding data |
| void AppendArray(absl::string_view src, MethodIdentifier method); |
| absl::string_view FindFlatStartPiece() const; |
| |
| // Creates a CordRepFlat instance from the current inlined data with `extra' |
| // bytes of desired additional capacity. |
| CordRepFlat* absl_nonnull MakeFlatWithExtraCapacity(size_t extra); |
| |
| // Sets the tree value for this instance. `rep` must not be null. |
| // Requires the current instance to hold a tree, and a lock to be held on |
| // any CordzInfo referenced by this instance. The latter is enforced through |
| // the CordzUpdateScope argument. If the current instance is sampled, then |
| // the CordzInfo instance is updated to reference the new `rep` value. |
| void SetTree(CordRep* absl_nonnull rep, const CordzUpdateScope& scope); |
| |
| // Identical to SetTree(), except that `rep` is allowed to be null, in |
| // which case the current instance is reset to an empty value. |
| void SetTreeOrEmpty(CordRep* absl_nullable rep, |
| const CordzUpdateScope& scope); |
| |
| // Sets the tree value for this instance, and randomly samples this cord. |
| // This function disregards existing contents in `data_`, and should be |
| // called when a Cord is 'promoted' from an 'uninitialized' or 'inlined' |
| // value to a non-inlined (tree / ring) value. |
| void EmplaceTree(CordRep* absl_nonnull rep, MethodIdentifier method); |
| |
| // Identical to EmplaceTree, except that it copies the parent stack from |
| // the provided `parent` data if the parent is sampled. |
| void EmplaceTree(CordRep* absl_nonnull rep, const InlineData& parent, |
| MethodIdentifier method); |
| |
| // Commits the change of a newly created, or updated `rep` root value into |
| // this cord. `old_rep` indicates the old (inlined or tree) value of the |
| // cord, and determines if the commit invokes SetTree() or EmplaceTree(). |
| void CommitTree(const CordRep* absl_nullable old_rep, |
| CordRep* absl_nonnull rep, const CordzUpdateScope& scope, |
| MethodIdentifier method); |
| |
| void AppendTreeToInlined(CordRep* absl_nonnull tree, |
| MethodIdentifier method); |
| void AppendTreeToTree(CordRep* absl_nonnull tree, MethodIdentifier method); |
| void AppendTree(CordRep* absl_nonnull tree, MethodIdentifier method); |
| void PrependTreeToInlined(CordRep* absl_nonnull tree, |
| MethodIdentifier method); |
| void PrependTreeToTree(CordRep* absl_nonnull tree, MethodIdentifier method); |
| void PrependTree(CordRep* absl_nonnull tree, MethodIdentifier method); |
| |
| bool IsSame(const InlineRep& other) const { return data_ == other.data_; } |
| |
| // Copies the inline contents into `dst`. Assumes the cord is not empty. |
| void CopyTo(std::string* absl_nonnull dst) const { |
| data_.CopyInlineToString(dst); |
| } |
| |
| // Copies the inline contents into `dst`. Assumes the cord is not empty. |
| void CopyToArray(char* absl_nonnull dst) const; |
| |
| bool is_tree() const { return data_.is_tree(); } |
| |
| // Returns true if the Cord is being profiled by cordz. |
| bool is_profiled() const { return data_.is_tree() && data_.is_profiled(); } |
| |
| // Returns the available inlined capacity, or 0 if is_tree() == true. |
| size_t remaining_inline_capacity() const { |
| return data_.is_tree() ? 0 : kMaxInline - data_.inline_size(); |
| } |
| |
| // Returns the profiled CordzInfo, or nullptr if not sampled. |
| absl::cord_internal::CordzInfo* absl_nullable cordz_info() const { |
| return data_.cordz_info(); |
| } |
| |
| // Sets the profiled CordzInfo. |
| void set_cordz_info(cord_internal::CordzInfo* absl_nonnull cordz_info) { |
| assert(cordz_info != nullptr); |
| data_.set_cordz_info(cordz_info); |
| } |
| |
| // Resets the current cordz_info to null / empty. |
| void clear_cordz_info() { data_.clear_cordz_info(); } |
| |
| private: |
| friend class Cord; |
| |
| void AssignSlow(const InlineRep& src); |
| // Unrefs the tree and stops profiling. |
| void UnrefTree(); |
| |
| void ResetToEmpty() { data_ = {}; } |
| |
| void set_inline_size(size_t size) { data_.set_inline_size(size); } |
| size_t inline_size() const { return data_.inline_size(); } |
| |
| // Empty cords that carry a checksum have a CordRepCrc node with a null |
| // child node. The code can avoid lots of special cases where it would |
| // otherwise transition from tree to inline storage if we just remove the |
| // CordRepCrc node before mutations. Must never be called inside a |
| // CordzUpdateScope since it untracks the cordz info. |
| void MaybeRemoveEmptyCrcNode(); |
| |
| cord_internal::InlineData data_; |
| }; |
| InlineRep contents_; |
| |
| // Helper for GetFlat() and TryFlat(). |
| static bool GetFlatAux(absl::cord_internal::CordRep* absl_nonnull rep, |
| absl::string_view* absl_nonnull fragment); |
| |
| // Helper for ForEachChunk(). |
| static void ForEachChunkAux( |
| absl::cord_internal::CordRep* absl_nonnull rep, |
| absl::FunctionRef<void(absl::string_view)> callback); |
| |
| // The destructor for non-empty Cords. |
| void DestroyCordSlow(); |
| |
| // Out-of-line implementation of slower parts of logic. |
| void CopyToArraySlowPath(char* absl_nonnull dst) const; |
| int CompareSlowPath(absl::string_view rhs, size_t compared_size, |
| size_t size_to_compare) const; |
| int CompareSlowPath(const Cord& rhs, size_t compared_size, |
| size_t size_to_compare) const; |
| bool EqualsImpl(absl::string_view rhs, size_t size_to_compare) const; |
| bool EqualsImpl(const Cord& rhs, size_t size_to_compare) const; |
| int CompareImpl(const Cord& rhs) const; |
| |
| template <typename ResultType, typename RHS> |
| friend ResultType GenericCompare(const Cord& lhs, const RHS& rhs, |
| size_t size_to_compare); |
| static absl::string_view GetFirstChunk(const Cord& c); |
| static absl::string_view GetFirstChunk(absl::string_view sv); |
| |
| // Returns a new reference to contents_.tree(), or steals an existing |
| // reference if called on an rvalue. |
| absl::cord_internal::CordRep* absl_nonnull TakeRep() const&; |
| absl::cord_internal::CordRep* absl_nonnull TakeRep() &&; |
| |
| // Helper for Append(). |
| template <typename C> |
| void AppendImpl(C&& src); |
| |
| // Appends / Prepends `src` to this instance, using precise sizing. |
| // This method does explicitly not attempt to use any spare capacity |
| // in any pending last added private owned flat. |
| // Requires `src` to be <= kMaxFlatLength. |
| void AppendPrecise(absl::string_view src, MethodIdentifier method); |
| void PrependPrecise(absl::string_view src, MethodIdentifier method); |
| |
| CordBuffer GetAppendBufferSlowPath(size_t block_size, size_t capacity, |
| size_t min_capacity); |
| |
| // Prepends the provided data to this instance. `method` contains the public |
| // API method for this action which is tracked for Cordz sampling purposes. |
| void PrependArray(absl::string_view src, MethodIdentifier method); |
| |
| // Assigns the value in 'src' to this instance, 'stealing' its contents. |
| // Requires src.length() > kMaxBytesToCopy. |
| Cord& AssignLargeString(std::string&& src); |
| |
| // Helper for AbslHashValue(). |
| template <typename H> |
| H HashFragmented(H hash_state) const { |
| typename H::AbslInternalPiecewiseCombiner combiner; |
| ForEachChunk([&combiner, &hash_state](absl::string_view chunk) { |
| hash_state = combiner.add_buffer(std::move(hash_state), chunk.data(), |
| chunk.size()); |
| }); |
| return H::combine(combiner.finalize(std::move(hash_state)), |
| hash_internal::WeaklyMixedInteger{size()}); |
| } |
| |
| friend class CrcCord; |
| void SetCrcCordState(crc_internal::CrcCordState state); |
| const crc_internal::CrcCordState* absl_nullable MaybeGetCrcCordState() const; |
| |
| CharIterator FindImpl(CharIterator it, absl::string_view needle) const; |
| |
| void CopyToArrayImpl(char* absl_nonnull dst) const; |
| }; |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // allow a Cord to be logged |
| extern std::ostream& operator<<(std::ostream& out, const Cord& cord); |
| |
| // ------------------------------------------------------------------ |
| // Internal details follow. Clients should ignore. |
| |
| namespace cord_internal { |
| |
| // Does non-template-specific `CordRepExternal` initialization. |
| // Requires `data` to be non-empty. |
| void InitializeCordRepExternal(absl::string_view data, |
| CordRepExternal* absl_nonnull rep); |
| |
| // Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer |
| // to it. Requires `data` to be non-empty. |
| template <typename Releaser> |
| // NOLINTNEXTLINE - suppress clang-tidy raw pointer return. |
| CordRep* absl_nonnull NewExternalRep(absl::string_view data, |
| Releaser&& releaser) { |
| assert(!data.empty()); |
| using ReleaserType = absl::decay_t<Releaser>; |
| CordRepExternal* rep = new CordRepExternalImpl<ReleaserType>( |
| std::forward<Releaser>(releaser), 0); |
| InitializeCordRepExternal(data, rep); |
| return rep; |
| } |
| |
| // Overload for function reference types that dispatches using a function |
| // pointer because there are no `alignof()` or `sizeof()` a function reference. |
| // NOLINTNEXTLINE - suppress clang-tidy raw pointer return. |
| inline CordRep* absl_nonnull NewExternalRep( |
| absl::string_view data, void (&releaser)(absl::string_view)) { |
| return NewExternalRep(data, &releaser); |
| } |
| |
| } // namespace cord_internal |
| |
| template <typename Releaser> |
| Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) { |
| Cord cord; |
| if (ABSL_PREDICT_TRUE(!data.empty())) { |
| cord.contents_.EmplaceTree(::absl::cord_internal::NewExternalRep( |
| data, std::forward<Releaser>(releaser)), |
| Cord::MethodIdentifier::kMakeCordFromExternal); |
| } else { |
| using ReleaserType = absl::decay_t<Releaser>; |
| cord_internal::InvokeReleaser( |
| cord_internal::Rank1{}, ReleaserType(std::forward<Releaser>(releaser)), |
| data); |
| } |
| return cord; |
| } |
| |
| constexpr Cord::InlineRep::InlineRep(absl::string_view sv, |
| CordRep* absl_nullable rep) |
| : data_(sv, rep) {} |
| |
| inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) |
| : data_(InlineData::kDefaultInit) { |
| if (CordRep* tree = src.tree()) { |
| EmplaceTree(CordRep::Ref(tree), src.data_, |
| CordzUpdateTracker::kConstructorCord); |
| } else { |
| data_ = src.data_; |
| } |
| } |
| |
| inline Cord::InlineRep::InlineRep(Cord::InlineRep&& src) : data_(src.data_) { |
| src.ResetToEmpty(); |
| } |
| |
| inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) { |
| if (this == &src) { |
| return *this; |
| } |
| if (!is_tree() && !src.is_tree()) { |
| data_ = src.data_; |
| return *this; |
| } |
| AssignSlow(src); |
| return *this; |
| } |
| |
| inline Cord::InlineRep& Cord::InlineRep::operator=( |
| Cord::InlineRep&& src) noexcept { |
| if (is_tree()) { |
| UnrefTree(); |
| } |
| data_ = src.data_; |
| src.ResetToEmpty(); |
| return *this; |
| } |
| |
| inline void Cord::InlineRep::Swap(Cord::InlineRep* absl_nonnull rhs) { |
| if (rhs == this) { |
| return; |
| } |
| using std::swap; |
| swap(data_, rhs->data_); |
| } |
| |
| inline const char* absl_nullable Cord::InlineRep::data() const { |
| return is_tree() ? nullptr : data_.as_chars(); |
| } |
| |
| inline const char* absl_nonnull Cord::InlineRep::as_chars() const { |
| assert(!data_.is_tree()); |
| return data_.as_chars(); |
| } |
| |
| inline absl::cord_internal::CordRep* absl_nonnull Cord::InlineRep::as_tree() |
| const { |
| assert(data_.is_tree()); |
| return data_.as_tree(); |
| } |
| |
| inline absl::cord_internal::CordRep* absl_nullable Cord::InlineRep::tree() |
| const { |
| if (is_tree()) { |
| return as_tree(); |
| } else { |
| return nullptr; |
| } |
| } |
| |
| inline size_t Cord::InlineRep::size() const { |
| return is_tree() ? as_tree()->length : inline_size(); |
| } |
| |
| inline cord_internal::CordRepFlat* absl_nonnull |
| Cord::InlineRep::MakeFlatWithExtraCapacity(size_t extra) { |
| static_assert(cord_internal::kMinFlatLength >= sizeof(data_), ""); |
| size_t len = data_.inline_size(); |
| auto* result = CordRepFlat::New(len + extra); |
| result->length = len; |
| data_.copy_max_inline_to(result->Data()); |
| return result; |
| } |
| |
| inline void Cord::InlineRep::EmplaceTree(CordRep* absl_nonnull rep, |
| MethodIdentifier method) { |
| assert(rep); |
| data_.make_tree(rep); |
| CordzInfo::MaybeTrackCord(data_, method); |
| } |
| |
| inline void Cord::InlineRep::EmplaceTree(CordRep* absl_nonnull rep, |
| const InlineData& parent, |
| MethodIdentifier method) { |
| data_.make_tree(rep); |
| CordzInfo::MaybeTrackCord(data_, parent, method); |
| } |
| |
| inline void Cord::InlineRep::SetTree(CordRep* absl_nonnull rep, |
| const CordzUpdateScope& scope) { |
| assert(rep); |
| assert(data_.is_tree()); |
| data_.set_tree(rep); |
| scope.SetCordRep(rep); |
| } |
| |
| inline void Cord::InlineRep::SetTreeOrEmpty(CordRep* absl_nullable rep, |
| const CordzUpdateScope& scope) { |
| assert(data_.is_tree()); |
| if (rep) { |
| data_.set_tree(rep); |
| } else { |
| data_ = {}; |
| } |
| scope.SetCordRep(rep); |
| } |
| |
| inline void Cord::InlineRep::CommitTree(const CordRep* absl_nullable old_rep, |
| CordRep* absl_nonnull rep, |
| const CordzUpdateScope& scope, |
| MethodIdentifier method) { |
| if (old_rep) { |
| SetTree(rep, scope); |
| } else { |
| EmplaceTree(rep, method); |
| } |
| } |
| |
| inline absl::cord_internal::CordRep* absl_nullable Cord::InlineRep::clear() { |
| if (is_tree()) { |
| CordzInfo::MaybeUntrackCord(cordz_info()); |
| } |
| absl::cord_internal::CordRep* result = tree(); |
| ResetToEmpty(); |
| return result; |
| } |
| |
| inline void Cord::InlineRep::CopyToArray(char* absl_nonnull dst) const { |
| assert(!is_tree()); |
| size_t n = inline_size(); |
| assert(n != 0); |
| cord_internal::SmallMemmove(dst, data_.as_chars(), n); |
| } |
| |
| inline void Cord::InlineRep::MaybeRemoveEmptyCrcNode() { |
| CordRep* rep = tree(); |
| if (rep == nullptr || ABSL_PREDICT_TRUE(rep->length > 0)) { |
| return; |
| } |
| assert(rep->IsCrc()); |
| assert(rep->crc()->child == nullptr); |
| CordzInfo::MaybeUntrackCord(cordz_info()); |
| CordRep::Unref(rep); |
| ResetToEmpty(); |
| } |
| |
| constexpr inline Cord::Cord() noexcept {} |
| |
| inline Cord::Cord(absl::string_view src) |
| : Cord(src, CordzUpdateTracker::kConstructorString) {} |
| |
| template <typename T> |
| constexpr Cord::Cord(strings_internal::StringConstant<T>) |
| : contents_(strings_internal::StringConstant<T>::value, |
| strings_internal::StringConstant<T>::value.size() <= |
| cord_internal::kMaxInline |
| ? nullptr |
| : &cord_internal::ConstInitExternalStorage< |
| strings_internal::StringConstant<T>>::value) {} |
| |
| inline Cord& Cord::operator=(const Cord& x) { |
| contents_ = x.contents_; |
| return *this; |
| } |
| |
| template <typename T, Cord::EnableIfString<T>> |
| Cord& Cord::operator=(T&& src) { |
| if (src.size() <= cord_internal::kMaxBytesToCopy) { |
| return operator=(absl::string_view(src)); |
| } else { |
| return AssignLargeString(std::forward<T>(src)); |
| } |
| } |
| |
| inline Cord::Cord(const Cord& src) : contents_(src.contents_) {} |
| |
| inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {} |
| |
| inline void Cord::swap(Cord& other) noexcept { |
| contents_.Swap(&other.contents_); |
| } |
| |
| inline Cord& Cord::operator=(Cord&& x) noexcept { |
| contents_ = std::move(x.contents_); |
| return *this; |
| } |
| |
| extern template Cord::Cord(std::string&& src); |
| |
| inline size_t Cord::size() const { |
| // Length is 1st field in str.rep_ |
| return contents_.size(); |
| } |
| |
| inline bool Cord::empty() const { return size() == 0; } |
| |
| inline size_t Cord::EstimatedMemoryUsage( |
| CordMemoryAccounting accounting_method) const { |
| size_t result = sizeof(Cord); |
| if (const absl::cord_internal::CordRep* rep = contents_.tree()) { |
| switch (accounting_method) { |
| case CordMemoryAccounting::kFairShare: |
| result += cord_internal::GetEstimatedFairShareMemoryUsage(rep); |
| break; |
| case CordMemoryAccounting::kTotalMorePrecise: |
| result += cord_internal::GetMorePreciseMemoryUsage(rep); |
| break; |
| case CordMemoryAccounting::kTotal: |
| result += cord_internal::GetEstimatedMemoryUsage(rep); |
| break; |
| } |
| } |
| return result; |
| } |
| |
| inline absl::optional<absl::string_view> Cord::TryFlat() const |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| absl::cord_internal::CordRep* rep = contents_.tree(); |
| if (rep == nullptr) { |
| return absl::string_view(contents_.data(), contents_.size()); |
| } |
| absl::string_view fragment; |
| if (GetFlatAux(rep, &fragment)) { |
| return fragment; |
| } |
| return absl::nullopt; |
| } |
| |
| inline absl::string_view Cord::Flatten() ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| absl::cord_internal::CordRep* rep = contents_.tree(); |
| if (rep == nullptr) { |
| return absl::string_view(contents_.data(), contents_.size()); |
| } else { |
| absl::string_view already_flat_contents; |
| if (GetFlatAux(rep, &already_flat_contents)) { |
| return already_flat_contents; |
| } |
| } |
| return FlattenSlowPath(); |
| } |
| |
| inline void Cord::Append(absl::string_view src) { |
| contents_.AppendArray(src, CordzUpdateTracker::kAppendString); |
| } |
| |
| inline void Cord::Prepend(absl::string_view src) { |
| PrependArray(src, CordzUpdateTracker::kPrependString); |
| } |
| |
| inline void Cord::Append(CordBuffer buffer) { |
| if (ABSL_PREDICT_FALSE(buffer.length() == 0)) return; |
| contents_.MaybeRemoveEmptyCrcNode(); |
| absl::string_view short_value; |
| if (CordRep* rep = buffer.ConsumeValue(short_value)) { |
| contents_.AppendTree(rep, CordzUpdateTracker::kAppendCordBuffer); |
| } else { |
| AppendPrecise(short_value, CordzUpdateTracker::kAppendCordBuffer); |
| } |
| } |
| |
| inline void Cord::Prepend(CordBuffer buffer) { |
| if (ABSL_PREDICT_FALSE(buffer.length() == 0)) return; |
| contents_.MaybeRemoveEmptyCrcNode(); |
| absl::string_view short_value; |
| if (CordRep* rep = buffer.ConsumeValue(short_value)) { |
| contents_.PrependTree(rep, CordzUpdateTracker::kPrependCordBuffer); |
| } else { |
| PrependPrecise(short_value, CordzUpdateTracker::kPrependCordBuffer); |
| } |
| } |
| |
| inline CordBuffer Cord::GetAppendBuffer(size_t capacity, size_t min_capacity) { |
| if (empty()) return CordBuffer::CreateWithDefaultLimit(capacity); |
| return GetAppendBufferSlowPath(0, capacity, min_capacity); |
| } |
| |
| inline CordBuffer Cord::GetCustomAppendBuffer(size_t block_size, |
| size_t capacity, |
| size_t min_capacity) { |
| if (empty()) { |
| return block_size ? CordBuffer::CreateWithCustomLimit(block_size, capacity) |
| : CordBuffer::CreateWithDefaultLimit(capacity); |
| } |
| return GetAppendBufferSlowPath(block_size, capacity, min_capacity); |
| } |
| |
| extern template void Cord::Append(std::string&& src); |
| extern template void Cord::Prepend(std::string&& src); |
| |
| inline int Cord::Compare(const Cord& rhs) const { |
| if (!contents_.is_tree() && !rhs.contents_.is_tree()) { |
| return contents_.data_.Compare(rhs.contents_.data_); |
| } |
| |
| return CompareImpl(rhs); |
| } |
| |
| // Does 'this' cord start/end with rhs |
| inline bool Cord::StartsWith(const Cord& rhs) const { |
| if (contents_.IsSame(rhs.contents_)) return true; |
| size_t rhs_size = rhs.size(); |
| if (size() < rhs_size) return false; |
| return EqualsImpl(rhs, rhs_size); |
| } |
| |
| inline bool Cord::StartsWith(absl::string_view rhs) const { |
| size_t rhs_size = rhs.size(); |
| if (size() < rhs_size) return false; |
| return EqualsImpl(rhs, rhs_size); |
| } |
| |
| inline void Cord::CopyToArrayImpl(char* absl_nonnull dst) const { |
| if (!contents_.is_tree()) { |
| if (!empty()) contents_.CopyToArray(dst); |
| } else { |
| CopyToArraySlowPath(dst); |
| } |
| } |
| |
| inline void Cord::ChunkIterator::InitTree( |
| cord_internal::CordRep* absl_nonnull tree) { |
| tree = cord_internal::SkipCrcNode(tree); |
| if (tree->tag == cord_internal::BTREE) { |
| current_chunk_ = btree_reader_.Init(tree->btree()); |
| } else { |
| current_leaf_ = tree; |
| current_chunk_ = cord_internal::EdgeData(tree); |
| } |
| } |
| |
| inline Cord::ChunkIterator::ChunkIterator( |
| cord_internal::CordRep* absl_nonnull tree) { |
| bytes_remaining_ = tree->length; |
| InitTree(tree); |
| } |
| |
| inline Cord::ChunkIterator::ChunkIterator(const Cord* absl_nonnull cord) { |
| if (CordRep* tree = cord->contents_.tree()) { |
| bytes_remaining_ = tree->length; |
| if (ABSL_PREDICT_TRUE(bytes_remaining_ != 0)) { |
| InitTree(tree); |
| } else { |
| current_chunk_ = {}; |
| } |
| } else { |
| bytes_remaining_ = cord->contents_.inline_size(); |
| current_chunk_ = {cord->contents_.data(), bytes_remaining_}; |
| } |
| } |
| |
| inline Cord::ChunkIterator& Cord::ChunkIterator::AdvanceBtree() { |
| current_chunk_ = btree_reader_.Next(); |
| return *this; |
| } |
| |
| inline void Cord::ChunkIterator::AdvanceBytesBtree(size_t n) { |
| assert(n >= current_chunk_.size()); |
| bytes_remaining_ -= n; |
| if (bytes_remaining_) { |
| if (n == current_chunk_.size()) { |
| current_chunk_ = btree_reader_.Next(); |
| } else { |
| size_t offset = btree_reader_.length() - bytes_remaining_; |
| current_chunk_ = btree_reader_.Seek(offset); |
| } |
| } else { |
| current_chunk_ = {}; |
| } |
| } |
| |
| inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() { |
| ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 && |
| "Attempted to iterate past `end()`"); |
| assert(bytes_remaining_ >= current_chunk_.size()); |
| bytes_remaining_ -= current_chunk_.size(); |
| if (bytes_remaining_ > 0) { |
| if (btree_reader_) { |
| return AdvanceBtree(); |
| } else { |
| assert(!current_chunk_.empty()); // Called on invalid iterator. |
| } |
| current_chunk_ = {}; |
| } |
| return *this; |
| } |
| |
| inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) { |
| ChunkIterator tmp(*this); |
| operator++(); |
| return tmp; |
| } |
| |
| inline bool Cord::ChunkIterator::operator==(const ChunkIterator& other) const { |
| return bytes_remaining_ == other.bytes_remaining_; |
| } |
| |
| inline bool Cord::ChunkIterator::operator!=(const ChunkIterator& other) const { |
| return !(*this == other); |
| } |
| |
| inline Cord::ChunkIterator::reference Cord::ChunkIterator::operator*() const { |
| ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); |
| return current_chunk_; |
| } |
| |
| inline Cord::ChunkIterator::pointer Cord::ChunkIterator::operator->() const { |
| ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); |
| return ¤t_chunk_; |
| } |
| |
| inline void Cord::ChunkIterator::RemoveChunkPrefix(size_t n) { |
| assert(n < current_chunk_.size()); |
| current_chunk_.remove_prefix(n); |
| bytes_remaining_ -= n; |
| } |
| |
| inline void Cord::ChunkIterator::AdvanceBytes(size_t n) { |
| assert(bytes_remaining_ >= n); |
| if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) { |
| RemoveChunkPrefix(n); |
| } else if (n != 0) { |
| if (btree_reader_) { |
| AdvanceBytesBtree(n); |
| } else { |
| bytes_remaining_ = 0; |
| } |
| } |
| } |
| |
| inline Cord::ChunkIterator Cord::chunk_begin() const { |
| return ChunkIterator(this); |
| } |
| |
| inline Cord::ChunkIterator Cord::chunk_end() const { return ChunkIterator(); } |
| |
| inline Cord::ChunkIterator Cord::ChunkRange::begin() const { |
| return cord_->chunk_begin(); |
| } |
| |
| inline Cord::ChunkIterator Cord::ChunkRange::end() const { |
| return cord_->chunk_end(); |
| } |
| |
| inline Cord::ChunkRange Cord::Chunks() const { return ChunkRange(this); } |
| |
| inline Cord::CharIterator& Cord::CharIterator::operator++() { |
| if (ABSL_PREDICT_TRUE(chunk_iterator_->size() > 1)) { |
| chunk_iterator_.RemoveChunkPrefix(1); |
| } else { |
| ++chunk_iterator_; |
| } |
| return *this; |
| } |
| |
| inline Cord::CharIterator Cord::CharIterator::operator++(int) { |
| CharIterator tmp(*this); |
| operator++(); |
| return tmp; |
| } |
| |
| inline bool Cord::CharIterator::operator==(const CharIterator& other) const { |
| return chunk_iterator_ == other.chunk_iterator_; |
| } |
| |
| inline bool Cord::CharIterator::operator!=(const CharIterator& other) const { |
| return !(*this == other); |
| } |
| |
| inline Cord::CharIterator::reference Cord::CharIterator::operator*() const { |
| return *chunk_iterator_->data(); |
| } |
| |
| inline Cord Cord::AdvanceAndRead(CharIterator* absl_nonnull it, |
| size_t n_bytes) { |
| assert(it != nullptr); |
| return it->chunk_iterator_.AdvanceAndReadBytes(n_bytes); |
| } |
| |
| inline void Cord::Advance(CharIterator* absl_nonnull it, size_t n_bytes) { |
| assert(it != nullptr); |
| it->chunk_iterator_.AdvanceBytes(n_bytes); |
| } |
| |
| inline absl::string_view Cord::ChunkRemaining(const CharIterator& it) { |
| return *it.chunk_iterator_; |
| } |
| |
| inline ptrdiff_t Cord::Distance(const CharIterator& first, |
| const CharIterator& last) { |
| return static_cast<ptrdiff_t>(first.chunk_iterator_.bytes_remaining_ - |
| last.chunk_iterator_.bytes_remaining_); |
| } |
| |
| inline Cord::CharIterator Cord::char_begin() const { |
| return CharIterator(this); |
| } |
| |
| inline Cord::CharIterator Cord::char_end() const { return CharIterator(); } |
| |
| inline Cord::CharIterator Cord::CharRange::begin() const { |
| return cord_->char_begin(); |
| } |
| |
| inline Cord::CharIterator Cord::CharRange::end() const { |
| return cord_->char_end(); |
| } |
| |
| inline Cord::CharRange Cord::Chars() const { return CharRange(this); } |
| |
| inline void Cord::ForEachChunk( |
| absl::FunctionRef<void(absl::string_view)> callback) const { |
| absl::cord_internal::CordRep* rep = contents_.tree(); |
| if (rep == nullptr) { |
| callback(absl::string_view(contents_.data(), contents_.size())); |
| } else { |
| ForEachChunkAux(rep, callback); |
| } |
| } |
| |
| // Nonmember Cord-to-Cord relational operators. |
| inline bool operator==(const Cord& lhs, const Cord& rhs) { |
| if (lhs.contents_.IsSame(rhs.contents_)) return true; |
| size_t rhs_size = rhs.size(); |
| if (lhs.size() != rhs_size) return false; |
| return lhs.EqualsImpl(rhs, rhs_size); |
| } |
| |
| inline bool operator!=(const Cord& x, const Cord& y) { return !(x == y); } |
| inline bool operator<(const Cord& x, const Cord& y) { return x.Compare(y) < 0; } |
| inline bool operator>(const Cord& x, const Cord& y) { return x.Compare(y) > 0; } |
| inline bool operator<=(const Cord& x, const Cord& y) { |
| return x.Compare(y) <= 0; |
| } |
| inline bool operator>=(const Cord& x, const Cord& y) { |
| return x.Compare(y) >= 0; |
| } |
| |
| // Nonmember Cord-to-absl::string_view relational operators. |
| // |
| // Due to implicit conversions, these also enable comparisons of Cord with |
| // std::string and const char*. |
| inline bool operator==(const Cord& lhs, absl::string_view rhs) { |
| size_t lhs_size = lhs.size(); |
| size_t rhs_size = rhs.size(); |
| if (lhs_size != rhs_size) return false; |
| return lhs.EqualsImpl(rhs, rhs_size); |
| } |
| |
| inline bool operator==(absl::string_view x, const Cord& y) { return y == x; } |
| inline bool operator!=(const Cord& x, absl::string_view y) { return !(x == y); } |
| inline bool operator!=(absl::string_view x, const Cord& y) { return !(x == y); } |
| inline bool operator<(const Cord& x, absl::string_view y) { |
| return x.Compare(y) < 0; |
| } |
| inline bool operator<(absl::string_view x, const Cord& y) { |
| return y.Compare(x) > 0; |
| } |
| inline bool operator>(const Cord& x, absl::string_view y) { return y < x; } |
| inline bool operator>(absl::string_view x, const Cord& y) { return y < x; } |
| inline bool operator<=(const Cord& x, absl::string_view y) { return !(y < x); } |
| inline bool operator<=(absl::string_view x, const Cord& y) { return !(y < x); } |
| inline bool operator>=(const Cord& x, absl::string_view y) { return !(x < y); } |
| inline bool operator>=(absl::string_view x, const Cord& y) { return !(x < y); } |
| |
| // Some internals exposed to test code. |
| namespace strings_internal { |
| class CordTestAccess { |
| public: |
| static size_t FlatOverhead(); |
| static size_t MaxFlatLength(); |
| static size_t SizeofCordRepExternal(); |
| static size_t SizeofCordRepSubstring(); |
| static size_t FlatTagToLength(uint8_t tag); |
| static uint8_t LengthToTag(size_t s); |
| }; |
| } // namespace strings_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_CORD_H_ |
| *Âd |
| osoong/.intermediates/external/abseil-cpp/absl_numeric_bits_hdrs/gen/my_include_dir/absl/numeric/internal/bits.hÎc// Copyright 2020 The Abseil Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_NUMERIC_INTERNAL_BITS_H_ |
| #define ABSL_NUMERIC_INTERNAL_BITS_H_ |
| |
| #include <cstdint> |
| #include <limits> |
| #include <type_traits> |
| |
| // Clang on Windows has __builtin_clzll; otherwise we need to use the |
| // windows intrinsic functions. |
| #if defined(_MSC_VER) && !defined(__clang__) |
| #include <intrin.h> |
| #endif |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| |
| #if defined(__GNUC__) && !defined(__clang__) |
| // GCC |
| #define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) 1 |
| #else |
| #define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) ABSL_HAVE_BUILTIN(x) |
| #endif |
| |
| #if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountl) && \ |
| ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll) |
| #define ABSL_INTERNAL_CONSTEXPR_POPCOUNT constexpr |
| #define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 1 |
| #else |
| #define ABSL_INTERNAL_CONSTEXPR_POPCOUNT |
| #define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 0 |
| #endif |
| |
| #if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz) && \ |
| ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll) |
| #define ABSL_INTERNAL_CONSTEXPR_CLZ constexpr |
| #define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 1 |
| #else |
| #define ABSL_INTERNAL_CONSTEXPR_CLZ |
| #define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 0 |
| #endif |
| |
| #if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz) && \ |
| ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll) |
| #define ABSL_INTERNAL_CONSTEXPR_CTZ constexpr |
| #define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 1 |
| #else |
| #define ABSL_INTERNAL_CONSTEXPR_CTZ |
| #define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 0 |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace numeric_internal { |
| |
| constexpr bool IsPowerOf2(unsigned int x) noexcept { |
| return x != 0 && (x & (x - 1)) == 0; |
| } |
| |
| template <class T> |
| [[nodiscard]] ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateRight( |
| T x, int s) noexcept { |
| static_assert(std::is_unsigned<T>::value, "T must be unsigned"); |
| static_assert(IsPowerOf2(std::numeric_limits<T>::digits), |
| "T must have a power-of-2 size"); |
| |
| return static_cast<T>(x >> (s & (std::numeric_limits<T>::digits - 1))) | |
| static_cast<T>(x << ((-s) & (std::numeric_limits<T>::digits - 1))); |
| } |
| |
| template <class T> |
| [[nodiscard]] ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateLeft( |
| T x, int s) noexcept { |
| static_assert(std::is_unsigned<T>::value, "T must be unsigned"); |
| static_assert(IsPowerOf2(std::numeric_limits<T>::digits), |
| "T must have a power-of-2 size"); |
| |
| return static_cast<T>(x << (s & (std::numeric_limits<T>::digits - 1))) | |
| static_cast<T>(x >> ((-s) & (std::numeric_limits<T>::digits - 1))); |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int |
| Popcount32(uint32_t x) noexcept { |
| #if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcount) |
| static_assert(sizeof(unsigned int) == sizeof(x), |
| "__builtin_popcount does not take 32-bit arg"); |
| return __builtin_popcount(x); |
| #else |
| x -= ((x >> 1) & 0x55555555); |
| x = ((x >> 2) & 0x33333333) + (x & 0x33333333); |
| return static_cast<int>((((x + (x >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24); |
| #endif |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int |
| Popcount64(uint64_t x) noexcept { |
| #if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll) |
| static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int) |
| "__builtin_popcount does not take 64-bit arg"); |
| return __builtin_popcountll(x); |
| #else |
| x -= (x >> 1) & 0x5555555555555555ULL; |
| x = ((x >> 2) & 0x3333333333333333ULL) + (x & 0x3333333333333333ULL); |
| return static_cast<int>( |
| (((x + (x >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56); |
| #endif |
| } |
| |
| template <class T> |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int |
| Popcount(T x) noexcept { |
| static_assert(std::is_unsigned<T>::value, "T must be unsigned"); |
| static_assert(IsPowerOf2(std::numeric_limits<T>::digits), |
| "T must have a power-of-2 size"); |
| static_assert(sizeof(x) <= sizeof(uint64_t), "T is too large"); |
| if constexpr (sizeof(x) <= sizeof(uint32_t)) { |
| return Popcount32(x); |
| } else { |
| return Popcount64(x); |
| } |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int |
| CountLeadingZeroes32(uint32_t x) { |
| #if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz) |
| // Use __builtin_clz, which uses the following instructions: |
| // x86: bsr, lzcnt |
| // ARM64: clz |
| // PPC: cntlzd |
| |
| static_assert(sizeof(unsigned int) == sizeof(x), |
| "__builtin_clz does not take 32-bit arg"); |
| // Handle 0 as a special case because __builtin_clz(0) is undefined. |
| return x == 0 ? 32 : __builtin_clz(x); |
| #elif defined(_MSC_VER) && !defined(__clang__) |
| unsigned long result = 0; // NOLINT(runtime/int) |
| if (_BitScanReverse(&result, x)) { |
| return 31 - result; |
| } |
| return 32; |
| #else |
| int zeroes = 28; |
| if (x >> 16) { |
| zeroes -= 16; |
| x >>= 16; |
| } |
| if (x >> 8) { |
| zeroes -= 8; |
| x >>= 8; |
| } |
| if (x >> 4) { |
| zeroes -= 4; |
| x >>= 4; |
| } |
| return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes; |
| #endif |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int |
| CountLeadingZeroes16(uint16_t x) { |
| #if ABSL_HAVE_BUILTIN(__builtin_clzg) |
| return x == 0 ? 16 : __builtin_clzg(x); |
| #elif ABSL_HAVE_BUILTIN(__builtin_clzs) |
| static_assert(sizeof(unsigned short) == sizeof(x), // NOLINT(runtime/int) |
| "__builtin_clzs does not take 16-bit arg"); |
| return x == 0 ? 16 : __builtin_clzs(x); |
| #else |
| return CountLeadingZeroes32(x) - 16; |
| #endif |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int |
| CountLeadingZeroes64(uint64_t x) { |
| #if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll) |
| // Use __builtin_clzll, which uses the following instructions: |
| // x86: bsr, lzcnt |
| // ARM64: clz |
| // PPC: cntlzd |
| static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int) |
| "__builtin_clzll does not take 64-bit arg"); |
| |
| // Handle 0 as a special case because __builtin_clzll(0) is undefined. |
| return x == 0 ? 64 : __builtin_clzll(x); |
| #elif defined(_MSC_VER) && !defined(__clang__) && \ |
| (defined(_M_X64) || defined(_M_ARM64)) |
| // MSVC does not have __buitin_clzll. Use _BitScanReverse64. |
| unsigned long result = 0; // NOLINT(runtime/int) |
| if (_BitScanReverse64(&result, x)) { |
| 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 ((x >> 32) && |
| _BitScanReverse(&result, static_cast<unsigned long>(x >> 32))) { |
| return 31 - result; |
| } |
| if (_BitScanReverse(&result, static_cast<unsigned long>(x))) { |
| return 63 - result; |
| } |
| return 64; |
| #else |
| int zeroes = 60; |
| if (x >> 32) { |
| zeroes -= 32; |
| x >>= 32; |
| } |
| if (x >> 16) { |
| zeroes -= 16; |
| x >>= 16; |
| } |
| if (x >> 8) { |
| zeroes -= 8; |
| x >>= 8; |
| } |
| if (x >> 4) { |
| zeroes -= 4; |
| x >>= 4; |
| } |
| return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes; |
| #endif |
| } |
| |
| template <typename T> |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int |
| CountLeadingZeroes(T x) { |
| static_assert(std::is_unsigned<T>::value, "T must be unsigned"); |
| static_assert(IsPowerOf2(std::numeric_limits<T>::digits), |
| "T must have a power-of-2 size"); |
| static_assert(sizeof(T) <= sizeof(uint64_t), "T too large"); |
| return sizeof(T) <= sizeof(uint16_t) |
| ? CountLeadingZeroes16(static_cast<uint16_t>(x)) - |
| (std::numeric_limits<uint16_t>::digits - |
| std::numeric_limits<T>::digits) |
| : (sizeof(T) <= sizeof(uint32_t) |
| ? CountLeadingZeroes32(static_cast<uint32_t>(x)) - |
| (std::numeric_limits<uint32_t>::digits - |
| std::numeric_limits<T>::digits) |
| : CountLeadingZeroes64(x)); |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int |
| CountTrailingZeroesNonzero32(uint32_t x) { |
| #if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz) |
| static_assert(sizeof(unsigned int) == sizeof(x), |
| "__builtin_ctz does not take 32-bit arg"); |
| return __builtin_ctz(x); |
| #elif defined(_MSC_VER) && !defined(__clang__) |
| unsigned long result = 0; // NOLINT(runtime/int) |
| _BitScanForward(&result, x); |
| return result; |
| #else |
| int c = 31; |
| x &= ~x + 1; |
| if (x & 0x0000FFFF) c -= 16; |
| if (x & 0x00FF00FF) c -= 8; |
| if (x & 0x0F0F0F0F) c -= 4; |
| if (x & 0x33333333) c -= 2; |
| if (x & 0x55555555) c -= 1; |
| return c; |
| #endif |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int |
| CountTrailingZeroesNonzero64(uint64_t x) { |
| #if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll) |
| static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int) |
| "__builtin_ctzll does not take 64-bit arg"); |
| return __builtin_ctzll(x); |
| #elif defined(_MSC_VER) && !defined(__clang__) && \ |
| (defined(_M_X64) || defined(_M_ARM64)) |
| unsigned long result = 0; // NOLINT(runtime/int) |
| _BitScanForward64(&result, x); |
| return result; |
| #elif defined(_MSC_VER) && !defined(__clang__) |
| unsigned long result = 0; // NOLINT(runtime/int) |
| if (static_cast<uint32_t>(x) == 0) { |
| _BitScanForward(&result, static_cast<unsigned long>(x >> 32)); |
| return result + 32; |
| } |
| _BitScanForward(&result, static_cast<unsigned long>(x)); |
| return result; |
| #else |
| int c = 63; |
| x &= ~x + 1; |
| if (x & 0x00000000FFFFFFFF) c -= 32; |
| if (x & 0x0000FFFF0000FFFF) c -= 16; |
| if (x & 0x00FF00FF00FF00FF) c -= 8; |
| if (x & 0x0F0F0F0F0F0F0F0F) c -= 4; |
| if (x & 0x3333333333333333) c -= 2; |
| if (x & 0x5555555555555555) c -= 1; |
| return c; |
| #endif |
| } |
| |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int |
| CountTrailingZeroesNonzero16(uint16_t x) { |
| #if ABSL_HAVE_BUILTIN(__builtin_ctzg) |
| return __builtin_ctzg(x); |
| #elif ABSL_HAVE_BUILTIN(__builtin_ctzs) |
| static_assert(sizeof(unsigned short) == sizeof(x), // NOLINT(runtime/int) |
| "__builtin_ctzs does not take 16-bit arg"); |
| return __builtin_ctzs(x); |
| #else |
| return CountTrailingZeroesNonzero32(x); |
| #endif |
| } |
| |
| template <class T> |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int |
| CountTrailingZeroes(T x) noexcept { |
| static_assert(std::is_unsigned<T>::value, "T must be unsigned"); |
| static_assert(IsPowerOf2(std::numeric_limits<T>::digits), |
| "T must have a power-of-2 size"); |
| static_assert(sizeof(T) <= sizeof(uint64_t), "T too large"); |
| return x == 0 ? std::numeric_limits<T>::digits |
| : (sizeof(T) <= sizeof(uint16_t) |
| ? CountTrailingZeroesNonzero16(static_cast<uint16_t>(x)) |
| : (sizeof(T) <= sizeof(uint32_t) |
| ? CountTrailingZeroesNonzero32( |
| static_cast<uint32_t>(x)) |
| : CountTrailingZeroesNonzero64(x))); |
| } |
| |
| // If T is narrower than unsigned, T{1} << bit_width will be promoted. We |
| // want to force it to wraparound so that bit_ceil of an invalid value are not |
| // core constant expressions. |
| template <class T> |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline |
| typename std::enable_if<std::is_unsigned<T>::value, T>::type |
| BitCeilPromotionHelper(T x, T promotion) { |
| return (T{1} << (x + promotion)) >> promotion; |
| } |
| |
| template <class T> |
| ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline |
| typename std::enable_if<std::is_unsigned<T>::value, T>::type |
| BitCeilNonPowerOf2(T x) { |
| // If T is narrower than unsigned, it undergoes promotion to unsigned when we |
| // shift. We calculate the number of bits added by the wider type. |
| return BitCeilPromotionHelper( |
| static_cast<T>(std::numeric_limits<T>::digits - CountLeadingZeroes(x)), |
| T{sizeof(T) >= sizeof(unsigned) ? 0 |
| : std::numeric_limits<unsigned>::digits - |
| std::numeric_limits<T>::digits}); |
| } |
| |
| } // namespace numeric_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_NUMERIC_INTERNAL_BITS_H_ |
| *ë |
| wsoong/.intermediates/external/abseil-cpp/absl_base_endian_hdrs/gen/my_include_dir/absl/base/internal/unaligned_access.hï// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #ifndef ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ |
| #define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ |
| |
| #include <string.h> |
| |
| #include <cstdint> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/nullability.h" |
| |
| // unaligned APIs |
| |
| // Portable handling of unaligned loads, stores, and copies. |
| |
| // The unaligned API is C++ only. The declarations use C++ features |
| // (namespaces, inline) which are absent or incompatible in C. |
| #if defined(__cplusplus) |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace base_internal { |
| |
| inline uint16_t UnalignedLoad16(const void* absl_nonnull p) { |
| uint16_t t; |
| memcpy(&t, p, sizeof t); |
| return t; |
| } |
| |
| inline uint32_t UnalignedLoad32(const void* absl_nonnull p) { |
| uint32_t t; |
| memcpy(&t, p, sizeof t); |
| return t; |
| } |
| |
| inline uint64_t UnalignedLoad64(const void* absl_nonnull p) { |
| uint64_t t; |
| memcpy(&t, p, sizeof t); |
| return t; |
| } |
| |
| inline void UnalignedStore16(void* absl_nonnull p, uint16_t v) { |
| memcpy(p, &v, sizeof v); |
| } |
| |
| inline void UnalignedStore32(void* absl_nonnull p, uint32_t v) { |
| memcpy(p, &v, sizeof v); |
| } |
| |
| inline void UnalignedStore64(void* absl_nonnull p, uint64_t v) { |
| memcpy(p, &v, sizeof v); |
| } |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ |
| (absl::base_internal::UnalignedLoad16(_p)) |
| #define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ |
| (absl::base_internal::UnalignedLoad32(_p)) |
| #define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ |
| (absl::base_internal::UnalignedLoad64(_p)) |
| |
| #define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ |
| (absl::base_internal::UnalignedStore16(_p, _val)) |
| #define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ |
| (absl::base_internal::UnalignedStore32(_p, _val)) |
| #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ |
| (absl::base_internal::UnalignedStore64(_p, _val)) |
| |
| #endif // defined(__cplusplus), end of unaligned API |
| |
| #endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ |
| * I |
| msoong/.intermediates/external/abseil-cpp/absl_base_endian_hdrs/gen/my_include_dir/absl/base/internal/endian.h®H// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // This file is for Abseil internal use only. |
| // See //absl/numeric/bits.h for supported functions related to endian-ness. |
| |
| #ifndef ABSL_BASE_INTERNAL_ENDIAN_H_ |
| #define ABSL_BASE_INTERNAL_ENDIAN_H_ |
| |
| #include <cstdint> |
| #include <cstdlib> |
| |
| #include "absl/base/casts.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/unaligned_access.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/port.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| constexpr uint64_t gbswap_64(uint64_t x) { |
| #if ABSL_HAVE_BUILTIN(__builtin_bswap64) || defined(__GNUC__) |
| return __builtin_bswap64(x); |
| #else |
| return (((x & uint64_t{0xFF}) << 56) | |
| ((x & uint64_t{0xFF00}) << 40) | |
| ((x & uint64_t{0xFF0000}) << 24) | |
| ((x & uint64_t{0xFF000000}) << 8) | |
| ((x & uint64_t{0xFF00000000}) >> 8) | |
| ((x & uint64_t{0xFF0000000000}) >> 24) | |
| ((x & uint64_t{0xFF000000000000}) >> 40) | |
| ((x & uint64_t{0xFF00000000000000}) >> 56)); |
| #endif |
| } |
| |
| constexpr uint32_t gbswap_32(uint32_t x) { |
| #if ABSL_HAVE_BUILTIN(__builtin_bswap32) || defined(__GNUC__) |
| return __builtin_bswap32(x); |
| #else |
| return (((x & uint32_t{0xFF}) << 24) | |
| ((x & uint32_t{0xFF00}) << 8) | |
| ((x & uint32_t{0xFF0000}) >> 8) | |
| ((x & uint32_t{0xFF000000}) >> 24)); |
| #endif |
| } |
| |
| constexpr uint16_t gbswap_16(uint16_t x) { |
| #if ABSL_HAVE_BUILTIN(__builtin_bswap16) || defined(__GNUC__) |
| return __builtin_bswap16(x); |
| #else |
| return (((x & uint16_t{0xFF}) << 8) | |
| ((x & uint16_t{0xFF00}) >> 8)); |
| #endif |
| } |
| |
| #ifdef ABSL_IS_LITTLE_ENDIAN |
| |
| // Portable definitions for htonl (host-to-network) and friends on little-endian |
| // architectures. |
| inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); } |
| inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); } |
| inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); } |
| |
| #elif defined ABSL_IS_BIG_ENDIAN |
| |
| // Portable definitions for htonl (host-to-network) etc on big-endian |
| // architectures. These definitions are simpler since the host byte order is the |
| // same as network byte order. |
| inline uint16_t ghtons(uint16_t x) { return x; } |
| inline uint32_t ghtonl(uint32_t x) { return x; } |
| inline uint64_t ghtonll(uint64_t x) { return x; } |
| |
| #else |
| #error \ |
| "Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \ |
| "ABSL_IS_LITTLE_ENDIAN must be defined" |
| #endif // byte order |
| |
| inline uint16_t gntohs(uint16_t x) { return ghtons(x); } |
| inline uint32_t gntohl(uint32_t x) { return ghtonl(x); } |
| inline uint64_t gntohll(uint64_t x) { return ghtonll(x); } |
| |
| // Utilities to convert numbers between the current hosts's native byte |
| // order and little-endian byte order |
| // |
| // Load/Store methods are alignment safe |
| namespace little_endian { |
| // Conversion functions. |
| #ifdef ABSL_IS_LITTLE_ENDIAN |
| |
| inline uint16_t FromHost16(uint16_t x) { return x; } |
| inline uint16_t ToHost16(uint16_t x) { return x; } |
| |
| inline uint32_t FromHost32(uint32_t x) { return x; } |
| inline uint32_t ToHost32(uint32_t x) { return x; } |
| |
| inline uint64_t FromHost64(uint64_t x) { return x; } |
| inline uint64_t ToHost64(uint64_t x) { return x; } |
| |
| inline constexpr bool IsLittleEndian() { return true; } |
| |
| #elif defined ABSL_IS_BIG_ENDIAN |
| |
| inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); } |
| inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); } |
| |
| inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); } |
| inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); } |
| |
| inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); } |
| inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); } |
| |
| inline constexpr bool IsLittleEndian() { return false; } |
| |
| #endif /* ENDIAN */ |
| |
| inline uint8_t FromHost(uint8_t x) { return x; } |
| inline uint16_t FromHost(uint16_t x) { return FromHost16(x); } |
| inline uint32_t FromHost(uint32_t x) { return FromHost32(x); } |
| inline uint64_t FromHost(uint64_t x) { return FromHost64(x); } |
| inline uint8_t ToHost(uint8_t x) { return x; } |
| inline uint16_t ToHost(uint16_t x) { return ToHost16(x); } |
| inline uint32_t ToHost(uint32_t x) { return ToHost32(x); } |
| inline uint64_t ToHost(uint64_t x) { return ToHost64(x); } |
| |
| inline int8_t FromHost(int8_t x) { return x; } |
| inline int16_t FromHost(int16_t x) { |
| return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x))); |
| } |
| inline int32_t FromHost(int32_t x) { |
| return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x))); |
| } |
| inline int64_t FromHost(int64_t x) { |
| return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x))); |
| } |
| inline int8_t ToHost(int8_t x) { return x; } |
| inline int16_t ToHost(int16_t x) { |
| return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x))); |
| } |
| inline int32_t ToHost(int32_t x) { |
| return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x))); |
| } |
| inline int64_t ToHost(int64_t x) { |
| return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x))); |
| } |
| |
| // Functions to do unaligned loads and stores in little-endian order. |
| inline uint16_t Load16(const void* absl_nonnull p) { |
| return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); |
| } |
| |
| inline void Store16(void* absl_nonnull p, uint16_t v) { |
| ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v)); |
| } |
| |
| inline uint32_t Load32(const void* absl_nonnull p) { |
| return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p)); |
| } |
| |
| inline void Store32(void* absl_nonnull p, uint32_t v) { |
| ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v)); |
| } |
| |
| inline uint64_t Load64(const void* absl_nonnull p) { |
| return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p)); |
| } |
| |
| inline void Store64(void* absl_nonnull p, uint64_t v) { |
| ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v)); |
| } |
| |
| } // namespace little_endian |
| |
| // Utilities to convert numbers between the current hosts's native byte |
| // order and big-endian byte order (same as network byte order) |
| // |
| // Load/Store methods are alignment safe |
| namespace big_endian { |
| #ifdef ABSL_IS_LITTLE_ENDIAN |
| |
| inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); } |
| inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); } |
| |
| inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); } |
| inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); } |
| |
| inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); } |
| inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); } |
| |
| inline constexpr bool IsLittleEndian() { return true; } |
| |
| #elif defined ABSL_IS_BIG_ENDIAN |
| |
| inline uint16_t FromHost16(uint16_t x) { return x; } |
| inline uint16_t ToHost16(uint16_t x) { return x; } |
| |
| inline uint32_t FromHost32(uint32_t x) { return x; } |
| inline uint32_t ToHost32(uint32_t x) { return x; } |
| |
| inline uint64_t FromHost64(uint64_t x) { return x; } |
| inline uint64_t ToHost64(uint64_t x) { return x; } |
| |
| inline constexpr bool IsLittleEndian() { return false; } |
| |
| #endif /* ENDIAN */ |
| |
| inline uint8_t FromHost(uint8_t x) { return x; } |
| inline uint16_t FromHost(uint16_t x) { return FromHost16(x); } |
| inline uint32_t FromHost(uint32_t x) { return FromHost32(x); } |
| inline uint64_t FromHost(uint64_t x) { return FromHost64(x); } |
| inline uint8_t ToHost(uint8_t x) { return x; } |
| inline uint16_t ToHost(uint16_t x) { return ToHost16(x); } |
| inline uint32_t ToHost(uint32_t x) { return ToHost32(x); } |
| inline uint64_t ToHost(uint64_t x) { return ToHost64(x); } |
| |
| inline int8_t FromHost(int8_t x) { return x; } |
| inline int16_t FromHost(int16_t x) { |
| return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x))); |
| } |
| inline int32_t FromHost(int32_t x) { |
| return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x))); |
| } |
| inline int64_t FromHost(int64_t x) { |
| return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x))); |
| } |
| inline int8_t ToHost(int8_t x) { return x; } |
| inline int16_t ToHost(int16_t x) { |
| return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x))); |
| } |
| inline int32_t ToHost(int32_t x) { |
| return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x))); |
| } |
| inline int64_t ToHost(int64_t x) { |
| return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x))); |
| } |
| |
| // Functions to do unaligned loads and stores in big-endian order. |
| inline uint16_t Load16(const void* absl_nonnull p) { |
| return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); |
| } |
| |
| inline void Store16(void* absl_nonnull p, uint16_t v) { |
| ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v)); |
| } |
| |
| inline uint32_t Load32(const void* absl_nonnull p) { |
| return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p)); |
| } |
| |
| inline void Store32(void* absl_nonnull p, uint32_t v) { |
| ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v)); |
| } |
| |
| inline uint64_t Load64(const void* absl_nonnull p) { |
| return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p)); |
| } |
| |
| inline void Store64(void* absl_nonnull p, uint64_t v) { |
| ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v)); |
| } |
| |
| } // namespace big_endian |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_ENDIAN_H_ |
| *Á+ |
| jsoong/.intermediates/external/abseil-cpp/absl_log_absl_check_hdrs/gen/my_include_dir/absl/log/absl_check.hÒ*// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/absl_check.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header declares a family of `ABSL_CHECK` macros as alternative spellings |
| // for `CHECK` macros in `check.h`. |
| // |
| // Except for those whose names begin with `ABSL_DCHECK`, these macros are not |
| // controlled by `NDEBUG` (cf. `assert`), so the check will be executed |
| // regardless of compilation mode. `ABSL_CHECK` and friends are thus useful for |
| // confirming invariants in situations where continuing to run would be worse |
| // than terminating, e.g., due to risk of data corruption or security |
| // compromise. It is also more robust and portable to deliberately terminate |
| // at a particular place with a useful message and backtrace than to assume some |
| // ultimately unspecified and unreliable crashing behavior (such as a |
| // "segmentation fault"). |
| // |
| // For full documentation of each macro, see comments in `check.h`, which has an |
| // identical set of macros without the ABSL_* prefix. |
| |
| #ifndef ABSL_LOG_ABSL_CHECK_H_ |
| #define ABSL_LOG_ABSL_CHECK_H_ |
| |
| #include "absl/log/internal/check_impl.h" |
| |
| #define ABSL_CHECK(condition) \ |
| ABSL_LOG_INTERNAL_CHECK_IMPL((condition), #condition) |
| #define ABSL_QCHECK(condition) \ |
| ABSL_LOG_INTERNAL_QCHECK_IMPL((condition), #condition) |
| #define ABSL_PCHECK(condition) \ |
| ABSL_LOG_INTERNAL_PCHECK_IMPL((condition), #condition) |
| #define ABSL_DCHECK(condition) \ |
| ABSL_LOG_INTERNAL_DCHECK_IMPL((condition), #condition) |
| |
| #define ABSL_CHECK_EQ(val1, val2) \ |
| ABSL_LOG_INTERNAL_CHECK_EQ_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_CHECK_NE(val1, val2) \ |
| ABSL_LOG_INTERNAL_CHECK_NE_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_CHECK_LE(val1, val2) \ |
| ABSL_LOG_INTERNAL_CHECK_LE_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_CHECK_LT(val1, val2) \ |
| ABSL_LOG_INTERNAL_CHECK_LT_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_CHECK_GE(val1, val2) \ |
| ABSL_LOG_INTERNAL_CHECK_GE_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_CHECK_GT(val1, val2) \ |
| ABSL_LOG_INTERNAL_CHECK_GT_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_QCHECK_EQ(val1, val2) \ |
| ABSL_LOG_INTERNAL_QCHECK_EQ_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_QCHECK_NE(val1, val2) \ |
| ABSL_LOG_INTERNAL_QCHECK_NE_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_QCHECK_LE(val1, val2) \ |
| ABSL_LOG_INTERNAL_QCHECK_LE_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_QCHECK_LT(val1, val2) \ |
| ABSL_LOG_INTERNAL_QCHECK_LT_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_QCHECK_GE(val1, val2) \ |
| ABSL_LOG_INTERNAL_QCHECK_GE_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_QCHECK_GT(val1, val2) \ |
| ABSL_LOG_INTERNAL_QCHECK_GT_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_DCHECK_EQ(val1, val2) \ |
| ABSL_LOG_INTERNAL_DCHECK_EQ_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_DCHECK_NE(val1, val2) \ |
| ABSL_LOG_INTERNAL_DCHECK_NE_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_DCHECK_LE(val1, val2) \ |
| ABSL_LOG_INTERNAL_DCHECK_LE_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_DCHECK_LT(val1, val2) \ |
| ABSL_LOG_INTERNAL_DCHECK_LT_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_DCHECK_GE(val1, val2) \ |
| ABSL_LOG_INTERNAL_DCHECK_GE_IMPL((val1), #val1, (val2), #val2) |
| #define ABSL_DCHECK_GT(val1, val2) \ |
| ABSL_LOG_INTERNAL_DCHECK_GT_IMPL((val1), #val1, (val2), #val2) |
| |
| #define ABSL_CHECK_OK(status) ABSL_LOG_INTERNAL_CHECK_OK_IMPL((status), #status) |
| #define ABSL_QCHECK_OK(status) \ |
| ABSL_LOG_INTERNAL_QCHECK_OK_IMPL((status), #status) |
| #define ABSL_DCHECK_OK(status) \ |
| ABSL_LOG_INTERNAL_DCHECK_OK_IMPL((status), #status) |
| |
| #define ABSL_CHECK_STREQ(s1, s2) \ |
| ABSL_LOG_INTERNAL_CHECK_STREQ_IMPL((s1), #s1, (s2), #s2) |
| #define ABSL_CHECK_STRNE(s1, s2) \ |
| ABSL_LOG_INTERNAL_CHECK_STRNE_IMPL((s1), #s1, (s2), #s2) |
| #define ABSL_CHECK_STRCASEEQ(s1, s2) \ |
| ABSL_LOG_INTERNAL_CHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) |
| #define ABSL_CHECK_STRCASENE(s1, s2) \ |
| ABSL_LOG_INTERNAL_CHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) |
| #define ABSL_QCHECK_STREQ(s1, s2) \ |
| ABSL_LOG_INTERNAL_QCHECK_STREQ_IMPL((s1), #s1, (s2), #s2) |
| #define ABSL_QCHECK_STRNE(s1, s2) \ |
| ABSL_LOG_INTERNAL_QCHECK_STRNE_IMPL((s1), #s1, (s2), #s2) |
| #define ABSL_QCHECK_STRCASEEQ(s1, s2) \ |
| ABSL_LOG_INTERNAL_QCHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) |
| #define ABSL_QCHECK_STRCASENE(s1, s2) \ |
| ABSL_LOG_INTERNAL_QCHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) |
| #define ABSL_DCHECK_STREQ(s1, s2) \ |
| ABSL_LOG_INTERNAL_DCHECK_STREQ_IMPL((s1), #s1, (s2), #s2) |
| #define ABSL_DCHECK_STRNE(s1, s2) \ |
| ABSL_LOG_INTERNAL_DCHECK_STRNE_IMPL((s1), #s1, (s2), #s2) |
| #define ABSL_DCHECK_STRCASEEQ(s1, s2) \ |
| ABSL_LOG_INTERNAL_DCHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) |
| #define ABSL_DCHECK_STRCASENE(s1, s2) \ |
| ABSL_LOG_INTERNAL_DCHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) |
| |
| #endif // ABSL_LOG_ABSL_CHECK_H_ |
| *¢ |
|
soong/.intermediates/external/abseil-cpp/absl_strings_cordz_functions_hdrs/gen/my_include_dir/absl/strings/internal/cordz_functions.h// Copyright 2019 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_CORDZ_FUNCTIONS_H_ |
| #define ABSL_STRINGS_INTERNAL_CORDZ_FUNCTIONS_H_ |
| |
| #include <stdint.h> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/optimization.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // Returns the current sample rate. This represents the average interval |
| // between samples. |
| int32_t get_cordz_mean_interval(); |
| |
| // Sets the sample rate with the average interval between samples. |
| void set_cordz_mean_interval(int32_t mean_interval); |
| |
| // Cordz is only enabled on Linux with thread_local support. |
| #if defined(ABSL_INTERNAL_CORDZ_ENABLED) |
| #error ABSL_INTERNAL_CORDZ_ENABLED cannot be set directly |
| #elif defined(__linux__) && defined(ABSL_HAVE_THREAD_LOCAL) |
| #define ABSL_INTERNAL_CORDZ_ENABLED 1 |
| #endif |
| |
| #ifdef ABSL_INTERNAL_CORDZ_ENABLED |
| |
| struct SamplingState { |
| int64_t next_sample; |
| int64_t sample_stride; |
| }; |
| |
| // cordz_next_sample is the number of events until the next sample event. If |
| // the value is 1 or less, the code will check on the next event if cordz is |
| // enabled, and if so, will sample the Cord. cordz is only enabled when we can |
| // use thread locals. |
| ABSL_CONST_INIT extern thread_local SamplingState cordz_next_sample; |
| |
| // Determines if the next sample should be profiled. |
| // Returns: |
| // 0: Do not sample |
| // >0: Sample with the stride of the last sampling period |
| int64_t cordz_should_profile_slow(SamplingState& state); |
| |
| // Determines if the next sample should be profiled. |
| // Returns: |
| // 0: Do not sample |
| // >0: Sample with the stride of the last sampling period |
| inline int64_t cordz_should_profile() { |
| if (ABSL_PREDICT_TRUE(cordz_next_sample.next_sample > 1)) { |
| cordz_next_sample.next_sample--; |
| return 0; |
| } |
| return cordz_should_profile_slow(cordz_next_sample); |
| } |
| |
| // Sets the interval until the next sample (for testing only) |
| void cordz_set_next_sample_for_testing(int64_t next_sample); |
| |
| #else // ABSL_INTERNAL_CORDZ_ENABLED |
| |
| inline int64_t cordz_should_profile() { return 0; } |
| inline void cordz_set_next_sample_for_testing(int64_t) {} |
| |
| #endif // ABSL_INTERNAL_CORDZ_ENABLED |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORDZ_FUNCTIONS_H_ |
| *· |
| |soong/.intermediates/external/abseil-cpp/absl_log_internal_nullstream_hdrs/gen/my_include_dir/absl/log/internal/nullstream.h¶// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/internal/nullstream.h |
| // ----------------------------------------------------------------------------- |
| // |
| // Classes `NullStream`, `NullStreamMaybeFatal ` and `NullStreamFatal` |
| // implement a subset of the `LogMessage` API and are used instead when logging |
| // of messages has been disabled. |
| |
| #ifndef ABSL_LOG_INTERNAL_NULLSTREAM_H_ |
| #define ABSL_LOG_INTERNAL_NULLSTREAM_H_ |
| |
| #ifdef _WIN32 |
| #include <cstdlib> |
| #else |
| #include <unistd.h> |
| #endif |
| #include <ios> |
| #include <ostream> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/log_severity.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace log_internal { |
| |
| // A `NullStream` implements the API of `LogMessage` (a few methods and |
| // `operator<<`) but does nothing. All methods are defined inline so the |
| // compiler can eliminate the whole instance and discard anything that's |
| // streamed in. |
| class NullStream { |
| public: |
| NullStream& AtLocation(absl::string_view, int) { return *this; } |
| template <typename SourceLocationType> |
| NullStream& AtLocation(SourceLocationType) { |
| return *this; |
| } |
| NullStream& NoPrefix() { return *this; } |
| NullStream& WithVerbosity(int) { return *this; } |
| template <typename TimeType> |
| NullStream& WithTimestamp(TimeType) { |
| return *this; |
| } |
| template <typename Tid> |
| NullStream& WithThreadID(Tid) { |
| return *this; |
| } |
| template <typename LogEntryType> |
| NullStream& WithMetadataFrom(const LogEntryType&) { |
| return *this; |
| } |
| NullStream& WithPerror() { return *this; } |
| template <typename LogSinkType> |
| NullStream& ToSinkAlso(LogSinkType*) { |
| return *this; |
| } |
| template <typename LogSinkType> |
| NullStream& ToSinkOnly(LogSinkType*) { |
| return *this; |
| } |
| template <typename LogSinkType> |
| NullStream& OutputToSink(LogSinkType*, bool) { |
| return *this; |
| } |
| NullStream& InternalStream() { return *this; } |
| void Flush() {} |
| }; |
| template <typename T> |
| inline NullStream& operator<<(NullStream& str, const T&) { |
| return str; |
| } |
| inline NullStream& operator<<(NullStream& str, |
| std::ostream& (*)(std::ostream& os)) { |
| return str; |
| } |
| inline NullStream& operator<<(NullStream& str, |
| std::ios_base& (*)(std::ios_base& os)) { |
| return str; |
| } |
| |
| // `NullStreamMaybeFatal` implements the process termination semantics of |
| // `LogMessage`, which is used for `DFATAL` severity and expression-defined |
| // severity e.g. `LOG(LEVEL(HowBadIsIt()))`. Like `LogMessage`, it terminates |
| // the process when destroyed if the passed-in severity equals `FATAL`. |
| class NullStreamMaybeFatal final : public NullStream { |
| public: |
| explicit NullStreamMaybeFatal(absl::LogSeverity severity) |
| : fatal_(severity == absl::LogSeverity::kFatal) {} |
| ~NullStreamMaybeFatal() { |
| if (fatal_) { |
| _exit(1); |
| } |
| } |
| |
| private: |
| bool fatal_; |
| }; |
| |
| // `NullStreamFatal` implements the process termination semantics of |
| // `LogMessageFatal`, which means it always terminates the process. `DFATAL` |
| // and expression-defined severity use `NullStreamMaybeFatal` above. |
| class NullStreamFatal final : public NullStream { |
| public: |
| NullStreamFatal() = default; |
| [[noreturn]] ~NullStreamFatal() { _exit(1); } |
| }; |
| |
| } // namespace log_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_LOG_INTERNAL_GLOBALS_H_ |
| *Ô' |
| rsoong/.intermediates/external/abseil-cpp/absl_log_internal_strip_hdrs/gen/my_include_dir/absl/log/internal/strip.hÝ&// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/internal/strip.h |
| // ----------------------------------------------------------------------------- |
| |
| // SKIP_ABSL_INLINE_NAMESPACE_CHECK |
| |
| #ifndef ABSL_LOG_INTERNAL_STRIP_H_ |
| #define ABSL_LOG_INTERNAL_STRIP_H_ |
| |
| #include "absl/base/attributes.h" // IWYU pragma: keep |
| #include "absl/base/log_severity.h" |
| #include "absl/log/internal/log_message.h" |
| #include "absl/log/internal/nullstream.h" |
| |
| // `ABSL_LOGGING_INTERNAL_LOG_*` evaluates to a temporary `LogMessage` object or |
| // to a related object with a compatible API but different behavior. This set |
| // of defines comes in three flavors: vanilla, plus two variants that strip some |
| // logging in subtly different ways for subtly different reasons (see below). |
| #if defined(STRIP_LOG) && STRIP_LOG |
| |
| #define ABSL_LOGGING_INTERNAL_LOG_INFO ::absl::log_internal::NullStream() |
| #define ABSL_LOGGING_INTERNAL_LOG_WARNING ::absl::log_internal::NullStream() |
| #define ABSL_LOGGING_INTERNAL_LOG_ERROR ::absl::log_internal::NullStream() |
| #define ABSL_LOGGING_INTERNAL_LOG_FATAL ::absl::log_internal::NullStreamFatal() |
| #define ABSL_LOGGING_INTERNAL_LOG_QFATAL ::absl::log_internal::NullStreamFatal() |
| #define ABSL_LOGGING_INTERNAL_LOG_DFATAL \ |
| ::absl::log_internal::NullStreamMaybeFatal(::absl::kLogDebugFatal) |
| #define ABSL_LOGGING_INTERNAL_LOG_LEVEL(severity) \ |
| ::absl::log_internal::NullStreamMaybeFatal(absl_log_internal_severity) |
| |
| // Fatal `DLOG`s expand a little differently to avoid being `[[noreturn]]`. |
| #define ABSL_LOGGING_INTERNAL_DLOG_FATAL \ |
| ::absl::log_internal::NullStreamMaybeFatal(::absl::LogSeverity::kFatal) |
| #define ABSL_LOGGING_INTERNAL_DLOG_QFATAL \ |
| ::absl::log_internal::NullStreamMaybeFatal(::absl::LogSeverity::kFatal) |
| |
| #define ABSL_LOG_INTERNAL_CHECK(failure_message) ABSL_LOGGING_INTERNAL_LOG_FATAL |
| #define ABSL_LOG_INTERNAL_QCHECK(failure_message) \ |
| ABSL_LOGGING_INTERNAL_LOG_QFATAL |
| |
| #else // !defined(STRIP_LOG) || !STRIP_LOG |
| |
| #define ABSL_LOGGING_INTERNAL_LOG_INFO \ |
| ::absl::log_internal::LogMessage( \ |
| __FILE__, __LINE__, ::absl::log_internal::LogMessage::InfoTag{}) |
| #define ABSL_LOGGING_INTERNAL_LOG_WARNING \ |
| ::absl::log_internal::LogMessage( \ |
| __FILE__, __LINE__, ::absl::log_internal::LogMessage::WarningTag{}) |
| #define ABSL_LOGGING_INTERNAL_LOG_ERROR \ |
| ::absl::log_internal::LogMessage( \ |
| __FILE__, __LINE__, ::absl::log_internal::LogMessage::ErrorTag{}) |
| #define ABSL_LOGGING_INTERNAL_LOG_FATAL \ |
| ::absl::log_internal::LogMessageFatal(__FILE__, __LINE__) |
| #define ABSL_LOGGING_INTERNAL_LOG_QFATAL \ |
| ::absl::log_internal::LogMessageQuietlyFatal(__FILE__, __LINE__) |
| #define ABSL_LOGGING_INTERNAL_LOG_DFATAL \ |
| ::absl::log_internal::LogMessage(__FILE__, __LINE__, ::absl::kLogDebugFatal) |
| #define ABSL_LOGGING_INTERNAL_LOG_LEVEL(severity) \ |
| ::absl::log_internal::LogMessage(__FILE__, __LINE__, \ |
| absl_log_internal_severity) |
| |
| // Fatal `DLOG`s expand a little differently to avoid being `[[noreturn]]`. |
| #define ABSL_LOGGING_INTERNAL_DLOG_FATAL \ |
| ::absl::log_internal::LogMessageDebugFatal(__FILE__, __LINE__) |
| #define ABSL_LOGGING_INTERNAL_DLOG_QFATAL \ |
| ::absl::log_internal::LogMessageQuietlyDebugFatal(__FILE__, __LINE__) |
| |
| // These special cases dispatch to special-case constructors that allow us to |
| // avoid an extra function call and shrink non-LTO binaries by a percent or so. |
| #define ABSL_LOG_INTERNAL_CHECK(failure_message) \ |
| ::absl::log_internal::LogMessageFatal(__FILE__, __LINE__, failure_message) |
| #define ABSL_LOG_INTERNAL_QCHECK(failure_message) \ |
| ::absl::log_internal::LogMessageQuietlyFatal(__FILE__, __LINE__, \ |
| failure_message) |
| #endif // !defined(STRIP_LOG) || !STRIP_LOG |
| |
| // This part of a non-fatal `DLOG`s expands the same as `LOG`. |
| #define ABSL_LOGGING_INTERNAL_DLOG_INFO ABSL_LOGGING_INTERNAL_LOG_INFO |
| #define ABSL_LOGGING_INTERNAL_DLOG_WARNING ABSL_LOGGING_INTERNAL_LOG_WARNING |
| #define ABSL_LOGGING_INTERNAL_DLOG_ERROR ABSL_LOGGING_INTERNAL_LOG_ERROR |
| #define ABSL_LOGGING_INTERNAL_DLOG_DFATAL ABSL_LOGGING_INTERNAL_LOG_DFATAL |
| #define ABSL_LOGGING_INTERNAL_DLOG_LEVEL ABSL_LOGGING_INTERNAL_LOG_LEVEL |
| |
| #define ABSL_LOGGING_INTERNAL_LOG_DO_NOT_SUBMIT ABSL_LOGGING_INTERNAL_LOG_ERROR |
| |
| #endif // ABSL_LOG_INTERNAL_STRIP_H_ |
| *ÿ |
| osoong/.intermediates/external/abseil-cpp/absl_strings_hdrs/gen/my_include_dir/absl/strings/has_absl_stringify.h// Copyright 2022 The Abseil Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_HAS_ABSL_STRINGIFY_H_ |
| #define ABSL_STRINGS_HAS_ABSL_STRINGIFY_H_ |
| |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/config.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| namespace strings_internal { |
| |
| // This is an empty class not intended to be used. It exists so that |
| // `HasAbslStringify` can reference a universal class rather than needing to be |
| // copied for each new sink. |
| class UnimplementedSink { |
| public: |
| void Append(size_t count, char ch); |
| |
| void Append(string_view v); |
| |
| // Support `absl::Format(&sink, format, args...)`. |
| friend void AbslFormatFlush(UnimplementedSink* sink, absl::string_view v); |
| }; |
| |
| } // namespace strings_internal |
| |
| // `HasAbslStringify<T>` detects if type `T` supports the `AbslStringify()` |
| // customization point (see |
| // https://abseil.io/docs/cpp/guides/format#abslstringify for the |
| // documentation). |
| // |
| // Note that there are types that can be `StrCat`-ed that do not use the |
| // `AbslStringify` customization point (for example, `int`). |
| |
| template <typename T, typename = void> |
| struct HasAbslStringify : std::false_type {}; |
| |
| template <typename T> |
| struct HasAbslStringify< |
| T, std::enable_if_t<std::is_void<decltype(AbslStringify( |
| std::declval<strings_internal::UnimplementedSink&>(), |
| std::declval<const T&>()))>::value>> : std::true_type {}; |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_HAS_ABSL_STRINGIFY_H_ |
| *⪠|
| soong/.intermediates/external/abseil-cpp/absl_time_internal_cctz_civil_time_hdrs/gen/my_include_dir/absl/time/internal/cctz/include/cctz/civil_time_detail.h¿©// Copyright 2016 Google Inc. All Rights Reserved. |
| // |
| // 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_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_ |
| #define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_ |
| |
| #include <cstdint> |
| #include <limits> |
| #include <ostream> |
| #include <type_traits> |
| |
| #include "absl/base/config.h" |
| |
| // Disable constexpr support unless we are in C++14 mode. |
| #if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910) |
| #define CONSTEXPR_D constexpr // data |
| #define CONSTEXPR_F constexpr // function |
| #define CONSTEXPR_M constexpr // member |
| #else |
| #define CONSTEXPR_D const |
| #define CONSTEXPR_F inline |
| #define CONSTEXPR_M |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace time_internal { |
| namespace cctz { |
| |
| // Support years that at least span the range of 64-bit time_t values. |
| using year_t = std::int_fast64_t; |
| |
| // Type alias that indicates an argument is not normalized (e.g., the |
| // constructor parameters and operands/results of addition/subtraction). |
| using diff_t = std::int_fast64_t; |
| |
| namespace detail { |
| |
| // Type aliases that indicate normalized argument values. |
| using month_t = std::int_fast8_t; // [1:12] |
| using day_t = std::int_fast8_t; // [1:31] |
| using hour_t = std::int_fast8_t; // [0:23] |
| using minute_t = std::int_fast8_t; // [0:59] |
| using second_t = std::int_fast8_t; // [0:59] |
| |
| // Normalized civil-time fields: Y-M-D HH:MM:SS. |
| struct fields { |
| CONSTEXPR_M fields(year_t year, month_t month, day_t day, hour_t hour, |
| minute_t minute, second_t second) |
| : y(year), m(month), d(day), hh(hour), mm(minute), ss(second) {} |
| std::int_least64_t y; |
| std::int_least8_t m; |
| std::int_least8_t d; |
| std::int_least8_t hh; |
| std::int_least8_t mm; |
| std::int_least8_t ss; |
| }; |
| |
| struct second_tag {}; |
| struct minute_tag : second_tag {}; |
| struct hour_tag : minute_tag {}; |
| struct day_tag : hour_tag {}; |
| struct month_tag : day_tag {}; |
| struct year_tag : month_tag {}; |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| // Field normalization (without avoidable overflow). |
| |
| namespace impl { |
| |
| CONSTEXPR_F bool is_leap_year(year_t y) noexcept { |
| return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); |
| } |
| CONSTEXPR_F int year_index(year_t y, month_t m) noexcept { |
| const int yi = static_cast<int>((y + (m > 2)) % 400); |
| return yi < 0 ? yi + 400 : yi; |
| } |
| CONSTEXPR_F int days_per_century(int yi) noexcept { |
| return 36524 + (yi == 0 || yi > 300); |
| } |
| CONSTEXPR_F int days_per_4years(int yi) noexcept { |
| return 1460 + (yi == 0 || yi > 300 || (yi - 1) % 100 < 96); |
| } |
| CONSTEXPR_F int days_per_year(year_t y, month_t m) noexcept { |
| return is_leap_year(y + (m > 2)) ? 366 : 365; |
| } |
| CONSTEXPR_F int days_per_month(year_t y, month_t m) noexcept { |
| CONSTEXPR_D int k_days_per_month[1 + 12] = { |
| -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 // non leap year |
| }; |
| return k_days_per_month[m] + (m == 2 && is_leap_year(y)); |
| } |
| |
| CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd, hour_t hh, |
| minute_t mm, second_t ss) noexcept { |
| year_t ey = y % 400; |
| const year_t oey = ey; |
| ey += (cd / 146097) * 400; |
| cd %= 146097; |
| if (cd < 0) { |
| ey -= 400; |
| cd += 146097; |
| } |
| ey += (d / 146097) * 400; |
| d = d % 146097 + cd; |
| if (d > 0) { |
| if (d > 146097) { |
| ey += 400; |
| d -= 146097; |
| } |
| } else { |
| if (d > -365) { |
| // We often hit the previous year when stepping a civil time backwards, |
| // so special case it to avoid counting up by 100/4/1-year chunks. |
| ey -= 1; |
| d += days_per_year(ey, m); |
| } else { |
| ey -= 400; |
| d += 146097; |
| } |
| } |
| if (d > 365) { |
| int yi = year_index(ey, m); // Index into Gregorian 400 year cycle. |
| for (;;) { |
| int n = days_per_century(yi); |
| if (d <= n) break; |
| d -= n; |
| ey += 100; |
| yi += 100; |
| if (yi >= 400) yi -= 400; |
| } |
| for (;;) { |
| int n = days_per_4years(yi); |
| if (d <= n) break; |
| d -= n; |
| ey += 4; |
| yi += 4; |
| if (yi >= 400) yi -= 400; |
| } |
| for (;;) { |
| int n = days_per_year(ey, m); |
| if (d <= n) break; |
| d -= n; |
| ++ey; |
| } |
| } |
| if (d > 28) { |
| for (;;) { |
| int n = days_per_month(ey, m); |
| if (d <= n) break; |
| d -= n; |
| if (++m > 12) { |
| ++ey; |
| m = 1; |
| } |
| } |
| } |
| return fields(y + (ey - oey), m, static_cast<day_t>(d), hh, mm, ss); |
| } |
| CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd, hour_t hh, |
| minute_t mm, second_t ss) noexcept { |
| if (m != 12) { |
| y += m / 12; |
| m %= 12; |
| if (m <= 0) { |
| y -= 1; |
| m += 12; |
| } |
| } |
| return n_day(y, static_cast<month_t>(m), d, cd, hh, mm, ss); |
| } |
| CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd, diff_t hh, |
| minute_t mm, second_t ss) noexcept { |
| cd += hh / 24; |
| hh %= 24; |
| if (hh < 0) { |
| cd -= 1; |
| hh += 24; |
| } |
| return n_mon(y, m, d, cd, static_cast<hour_t>(hh), mm, ss); |
| } |
| CONSTEXPR_F fields n_min(year_t y, diff_t m, diff_t d, diff_t hh, diff_t ch, |
| diff_t mm, second_t ss) noexcept { |
| ch += mm / 60; |
| mm %= 60; |
| if (mm < 0) { |
| ch -= 1; |
| mm += 60; |
| } |
| return n_hour(y, m, d, hh / 24 + ch / 24, hh % 24 + ch % 24, |
| static_cast<minute_t>(mm), ss); |
| } |
| CONSTEXPR_F fields n_sec(year_t y, diff_t m, diff_t d, diff_t hh, diff_t mm, |
| diff_t ss) noexcept { |
| // Optimization for when (non-constexpr) fields are already normalized. |
| if (0 <= ss && ss < 60) { |
| const second_t nss = static_cast<second_t>(ss); |
| if (0 <= mm && mm < 60) { |
| const minute_t nmm = static_cast<minute_t>(mm); |
| if (0 <= hh && hh < 24) { |
| const hour_t nhh = static_cast<hour_t>(hh); |
| if (1 <= d && d <= 28 && 1 <= m && m <= 12) { |
| const day_t nd = static_cast<day_t>(d); |
| const month_t nm = static_cast<month_t>(m); |
| return fields(y, nm, nd, nhh, nmm, nss); |
| } |
| return n_mon(y, m, d, 0, nhh, nmm, nss); |
| } |
| return n_hour(y, m, d, hh / 24, hh % 24, nmm, nss); |
| } |
| return n_min(y, m, d, hh, mm / 60, mm % 60, nss); |
| } |
| diff_t cm = ss / 60; |
| ss %= 60; |
| if (ss < 0) { |
| cm -= 1; |
| ss += 60; |
| } |
| return n_min(y, m, d, hh, mm / 60 + cm / 60, mm % 60 + cm % 60, |
| static_cast<second_t>(ss)); |
| } |
| |
| } // namespace impl |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| // Increments the indicated (normalized) field by "n". |
| CONSTEXPR_F fields step(second_tag, fields f, diff_t n) noexcept { |
| return impl::n_sec(f.y, f.m, f.d, f.hh, f.mm + n / 60, f.ss + n % 60); |
| } |
| CONSTEXPR_F fields step(minute_tag, fields f, diff_t n) noexcept { |
| return impl::n_min(f.y, f.m, f.d, f.hh + n / 60, 0, f.mm + n % 60, f.ss); |
| } |
| CONSTEXPR_F fields step(hour_tag, fields f, diff_t n) noexcept { |
| return impl::n_hour(f.y, f.m, f.d + n / 24, 0, f.hh + n % 24, f.mm, f.ss); |
| } |
| CONSTEXPR_F fields step(day_tag, fields f, diff_t n) noexcept { |
| return impl::n_day(f.y, f.m, f.d, n, f.hh, f.mm, f.ss); |
| } |
| CONSTEXPR_F fields step(month_tag, fields f, diff_t n) noexcept { |
| return impl::n_mon(f.y + n / 12, f.m + n % 12, f.d, 0, f.hh, f.mm, f.ss); |
| } |
| CONSTEXPR_F fields step(year_tag, fields f, diff_t n) noexcept { |
| return fields(f.y + n, f.m, f.d, f.hh, f.mm, f.ss); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| namespace impl { |
| |
| // Returns (v * f + a) but avoiding intermediate overflow when possible. |
| CONSTEXPR_F diff_t scale_add(diff_t v, diff_t f, diff_t a) noexcept { |
| return (v < 0) ? ((v + 1) * f + a) - f : ((v - 1) * f + a) + f; |
| } |
| |
| // Map a (normalized) Y/M/D to the number of days before/after 1970-01-01. |
| // Probably overflows for years outside [-292277022656:292277026595]. |
| CONSTEXPR_F diff_t ymd_ord(year_t y, month_t m, day_t d) noexcept { |
| const diff_t eyear = (m <= 2) ? y - 1 : y; |
| const diff_t era = (eyear >= 0 ? eyear : eyear - 399) / 400; |
| const diff_t yoe = eyear - era * 400; |
| const diff_t doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; |
| const diff_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; |
| return era * 146097 + doe - 719468; |
| } |
| |
| // Returns the difference in days between two normalized Y-M-D tuples. |
| // ymd_ord() will encounter integer overflow given extreme year values, |
| // yet the difference between two such extreme values may actually be |
| // small, so we take a little care to avoid overflow when possible by |
| // exploiting the 146097-day cycle. |
| CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1, year_t y2, |
| month_t m2, day_t d2) noexcept { |
| const diff_t a_c4_off = y1 % 400; |
| const diff_t b_c4_off = y2 % 400; |
| diff_t c4_diff = (y1 - a_c4_off) - (y2 - b_c4_off); |
| diff_t delta = ymd_ord(a_c4_off, m1, d1) - ymd_ord(b_c4_off, m2, d2); |
| if (c4_diff > 0 && delta < 0) { |
| delta += 2 * 146097; |
| c4_diff -= 2 * 400; |
| } else if (c4_diff < 0 && delta > 0) { |
| delta -= 2 * 146097; |
| c4_diff += 2 * 400; |
| } |
| return (c4_diff / 400 * 146097) + delta; |
| } |
| |
| } // namespace impl |
| |
| // Returns the difference between fields structs using the indicated unit. |
| CONSTEXPR_F diff_t difference(year_tag, fields f1, fields f2) noexcept { |
| return f1.y - f2.y; |
| } |
| CONSTEXPR_F diff_t difference(month_tag, fields f1, fields f2) noexcept { |
| return impl::scale_add(difference(year_tag{}, f1, f2), 12, (f1.m - f2.m)); |
| } |
| CONSTEXPR_F diff_t difference(day_tag, fields f1, fields f2) noexcept { |
| return impl::day_difference(f1.y, f1.m, f1.d, f2.y, f2.m, f2.d); |
| } |
| CONSTEXPR_F diff_t difference(hour_tag, fields f1, fields f2) noexcept { |
| return impl::scale_add(difference(day_tag{}, f1, f2), 24, (f1.hh - f2.hh)); |
| } |
| CONSTEXPR_F diff_t difference(minute_tag, fields f1, fields f2) noexcept { |
| return impl::scale_add(difference(hour_tag{}, f1, f2), 60, (f1.mm - f2.mm)); |
| } |
| CONSTEXPR_F diff_t difference(second_tag, fields f1, fields f2) noexcept { |
| return impl::scale_add(difference(minute_tag{}, f1, f2), 60, f1.ss - f2.ss); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| // Aligns the (normalized) fields struct to the indicated field. |
| CONSTEXPR_F fields align(second_tag, fields f) noexcept { return f; } |
| CONSTEXPR_F fields align(minute_tag, fields f) noexcept { |
| return fields{f.y, f.m, f.d, f.hh, f.mm, 0}; |
| } |
| CONSTEXPR_F fields align(hour_tag, fields f) noexcept { |
| return fields{f.y, f.m, f.d, f.hh, 0, 0}; |
| } |
| CONSTEXPR_F fields align(day_tag, fields f) noexcept { |
| return fields{f.y, f.m, f.d, 0, 0, 0}; |
| } |
| CONSTEXPR_F fields align(month_tag, fields f) noexcept { |
| return fields{f.y, f.m, 1, 0, 0, 0}; |
| } |
| CONSTEXPR_F fields align(year_tag, fields f) noexcept { |
| return fields{f.y, 1, 1, 0, 0, 0}; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| namespace impl { |
| |
| template <typename H> |
| H AbslHashValueImpl(second_tag, H h, fields f) { |
| return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm, f.ss); |
| } |
| template <typename H> |
| H AbslHashValueImpl(minute_tag, H h, fields f) { |
| return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm); |
| } |
| template <typename H> |
| H AbslHashValueImpl(hour_tag, H h, fields f) { |
| return H::combine(std::move(h), f.y, f.m, f.d, f.hh); |
| } |
| template <typename H> |
| H AbslHashValueImpl(day_tag, H h, fields f) { |
| return H::combine(std::move(h), f.y, f.m, f.d); |
| } |
| template <typename H> |
| H AbslHashValueImpl(month_tag, H h, fields f) { |
| return H::combine(std::move(h), f.y, f.m); |
| } |
| template <typename H> |
| H AbslHashValueImpl(year_tag, H h, fields f) { |
| return H::combine(std::move(h), f.y); |
| } |
| |
| } // namespace impl |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| template <typename T> |
| class civil_time { |
| public: |
| explicit CONSTEXPR_M civil_time(year_t y, diff_t m = 1, diff_t d = 1, |
| diff_t hh = 0, diff_t mm = 0, |
| diff_t ss = 0) noexcept |
| : civil_time(impl::n_sec(y, m, d, hh, mm, ss)) {} |
| |
| CONSTEXPR_M civil_time() noexcept : f_{1970, 1, 1, 0, 0, 0} {} |
| civil_time(const civil_time&) = default; |
| civil_time& operator=(const civil_time&) = default; |
| |
| // Conversion between civil times of different alignment. Conversion to |
| // a more precise alignment is allowed implicitly (e.g., day -> hour), |
| // but conversion where information is discarded must be explicit |
| // (e.g., second -> minute). |
| template <typename U, typename S> |
| using preserves_data = |
| typename std::enable_if<std::is_base_of<U, S>::value>::type; |
| template <typename U> |
| CONSTEXPR_M civil_time(const civil_time<U>& ct, |
| preserves_data<T, U>* = nullptr) noexcept |
| : civil_time(ct.f_) {} |
| template <typename U> |
| explicit CONSTEXPR_M civil_time(const civil_time<U>& ct, |
| preserves_data<U, T>* = nullptr) noexcept |
| : civil_time(ct.f_) {} |
| |
| // Factories for the maximum/minimum representable civil_time. |
| static CONSTEXPR_F auto(max)() -> civil_time { |
| const auto max_year = (std::numeric_limits<std::int_least64_t>::max)(); |
| return civil_time(max_year, 12, 31, 23, 59, 59); |
| } |
| static CONSTEXPR_F auto(min)() -> civil_time { |
| const auto min_year = (std::numeric_limits<std::int_least64_t>::min)(); |
| return civil_time(min_year, 1, 1, 0, 0, 0); |
| } |
| |
| // Field accessors. Note: All but year() return an int. |
| CONSTEXPR_M year_t year() const noexcept { return f_.y; } |
| CONSTEXPR_M int month() const noexcept { return f_.m; } |
| CONSTEXPR_M int day() const noexcept { return f_.d; } |
| CONSTEXPR_M int hour() const noexcept { return f_.hh; } |
| CONSTEXPR_M int minute() const noexcept { return f_.mm; } |
| CONSTEXPR_M int second() const noexcept { return f_.ss; } |
| |
| // Assigning arithmetic. |
| CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept { |
| return *this = *this + n; |
| } |
| CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept { |
| return *this = *this - n; |
| } |
| CONSTEXPR_M civil_time& operator++() noexcept { return *this += 1; } |
| CONSTEXPR_M civil_time operator++(int) noexcept { |
| const civil_time a = *this; |
| ++*this; |
| return a; |
| } |
| CONSTEXPR_M civil_time& operator--() noexcept { return *this -= 1; } |
| CONSTEXPR_M civil_time operator--(int) noexcept { |
| const civil_time a = *this; |
| --*this; |
| return a; |
| } |
| |
| // Binary arithmetic operators. |
| friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept { |
| return civil_time(step(T{}, a.f_, n)); |
| } |
| friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept { |
| return a + n; |
| } |
| friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept { |
| return n != (std::numeric_limits<diff_t>::min)() |
| ? civil_time(step(T{}, a.f_, -n)) |
| : civil_time(step(T{}, step(T{}, a.f_, -(n + 1)), 1)); |
| } |
| friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept { |
| return difference(T{}, lhs.f_, rhs.f_); |
| } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, civil_time a) { |
| return impl::AbslHashValueImpl(T{}, std::move(h), a.f_); |
| } |
| |
| private: |
| // All instantiations of this template are allowed to call the following |
| // private constructor and access the private fields member. |
| template <typename U> |
| friend class civil_time; |
| |
| // The designated constructor that all others eventually call. |
| explicit CONSTEXPR_M civil_time(fields f) noexcept : f_(align(T{}, f)) {} |
| |
| fields f_; |
| }; |
| |
| // Disallows difference between differently aligned types. |
| // auto n = civil_day(...) - civil_hour(...); // would be confusing. |
| template <typename T, typename U> |
| CONSTEXPR_F diff_t operator-(civil_time<T>, civil_time<U>) = delete; |
| |
| using civil_year = civil_time<year_tag>; |
| using civil_month = civil_time<month_tag>; |
| using civil_day = civil_time<day_tag>; |
| using civil_hour = civil_time<hour_tag>; |
| using civil_minute = civil_time<minute_tag>; |
| using civil_second = civil_time<second_tag>; |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| // Relational operators that work with differently aligned objects. |
| // Always compares all six fields. |
| template <typename T1, typename T2> |
| CONSTEXPR_F bool operator<(const civil_time<T1>& lhs, |
| const civil_time<T2>& rhs) noexcept { |
| return ( |
| lhs.year() < rhs.year() || |
| (lhs.year() == rhs.year() && |
| (lhs.month() < rhs.month() || |
| (lhs.month() == rhs.month() && |
| (lhs.day() < rhs.day() || (lhs.day() == rhs.day() && |
| (lhs.hour() < rhs.hour() || |
| (lhs.hour() == rhs.hour() && |
| (lhs.minute() < rhs.minute() || |
| (lhs.minute() == rhs.minute() && |
| (lhs.second() < rhs.second()))))))))))); |
| } |
| template <typename T1, typename T2> |
| CONSTEXPR_F bool operator<=(const civil_time<T1>& lhs, |
| const civil_time<T2>& rhs) noexcept { |
| return !(rhs < lhs); |
| } |
| template <typename T1, typename T2> |
| CONSTEXPR_F bool operator>=(const civil_time<T1>& lhs, |
| const civil_time<T2>& rhs) noexcept { |
| return !(lhs < rhs); |
| } |
| template <typename T1, typename T2> |
| CONSTEXPR_F bool operator>(const civil_time<T1>& lhs, |
| const civil_time<T2>& rhs) noexcept { |
| return rhs < lhs; |
| } |
| template <typename T1, typename T2> |
| CONSTEXPR_F bool operator==(const civil_time<T1>& lhs, |
| const civil_time<T2>& rhs) noexcept { |
| return lhs.year() == rhs.year() && lhs.month() == rhs.month() && |
| lhs.day() == rhs.day() && lhs.hour() == rhs.hour() && |
| lhs.minute() == rhs.minute() && lhs.second() == rhs.second(); |
| } |
| template <typename T1, typename T2> |
| CONSTEXPR_F bool operator!=(const civil_time<T1>& lhs, |
| const civil_time<T2>& rhs) noexcept { |
| return !(lhs == rhs); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| enum class weekday { |
| monday, |
| tuesday, |
| wednesday, |
| thursday, |
| friday, |
| saturday, |
| sunday, |
| }; |
| |
| CONSTEXPR_F weekday get_weekday(const civil_second& cs) noexcept { |
| CONSTEXPR_D weekday k_weekday_by_mon_off[13] = { |
| weekday::monday, weekday::tuesday, weekday::wednesday, |
| weekday::thursday, weekday::friday, weekday::saturday, |
| weekday::sunday, weekday::monday, weekday::tuesday, |
| weekday::wednesday, weekday::thursday, weekday::friday, |
| weekday::saturday, |
| }; |
| CONSTEXPR_D int k_weekday_offsets[1 + 12] = { |
| -1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4, |
| }; |
| year_t wd = 2400 + (cs.year() % 400) - (cs.month() < 3); |
| wd += wd / 4 - wd / 100 + wd / 400; |
| wd += k_weekday_offsets[cs.month()] + cs.day(); |
| return k_weekday_by_mon_off[wd % 7 + 6]; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| CONSTEXPR_F civil_day next_weekday(civil_day cd, weekday wd) noexcept { |
| CONSTEXPR_D weekday k_weekdays_forw[14] = { |
| weekday::monday, weekday::tuesday, weekday::wednesday, |
| weekday::thursday, weekday::friday, weekday::saturday, |
| weekday::sunday, weekday::monday, weekday::tuesday, |
| weekday::wednesday, weekday::thursday, weekday::friday, |
| weekday::saturday, weekday::sunday, |
| }; |
| weekday base = get_weekday(cd); |
| for (int i = 0;; ++i) { |
| if (base == k_weekdays_forw[i]) { |
| for (int j = i + 1;; ++j) { |
| if (wd == k_weekdays_forw[j]) { |
| return cd + (j - i); |
| } |
| } |
| } |
| } |
| } |
| |
| CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept { |
| CONSTEXPR_D weekday k_weekdays_back[14] = { |
| weekday::sunday, weekday::saturday, weekday::friday, |
| weekday::thursday, weekday::wednesday, weekday::tuesday, |
| weekday::monday, weekday::sunday, weekday::saturday, |
| weekday::friday, weekday::thursday, weekday::wednesday, |
| weekday::tuesday, weekday::monday, |
| }; |
| weekday base = get_weekday(cd); |
| for (int i = 0;; ++i) { |
| if (base == k_weekdays_back[i]) { |
| for (int j = i + 1;; ++j) { |
| if (wd == k_weekdays_back[j]) { |
| return cd - (j - i); |
| } |
| } |
| } |
| } |
| } |
| |
| CONSTEXPR_F int get_yearday(const civil_second& cs) noexcept { |
| CONSTEXPR_D int k_month_offsets[1 + 12] = { |
| -1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, |
| }; |
| const int feb29 = (cs.month() > 2 && impl::is_leap_year(cs.year())); |
| return k_month_offsets[cs.month()] + feb29 + cs.day(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| |
| std::ostream& operator<<(std::ostream& os, const civil_year& y); |
| std::ostream& operator<<(std::ostream& os, const civil_month& m); |
| std::ostream& operator<<(std::ostream& os, const civil_day& d); |
| std::ostream& operator<<(std::ostream& os, const civil_hour& h); |
| std::ostream& operator<<(std::ostream& os, const civil_minute& m); |
| std::ostream& operator<<(std::ostream& os, const civil_second& s); |
| std::ostream& operator<<(std::ostream& os, weekday wd); |
| |
| } // namespace detail |
| } // namespace cctz |
| } // namespace time_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #undef CONSTEXPR_M |
| #undef CONSTEXPR_F |
| #undef CONSTEXPR_D |
| |
| #endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_ |
| *ÎA |
| soong/.intermediates/external/abseil-cpp/absl_synchronization_kernel_timeout_internal_hdrs/gen/my_include_dir/absl/synchronization/internal/kernel_timeout.h¬@// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ |
| #define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ |
| |
| #ifndef _WIN32 |
| #include <sys/types.h> |
| #endif |
| |
| #include <algorithm> |
| #include <chrono> // NOLINT(build/c++11) |
| #include <cstdint> |
| #include <ctime> |
| #include <limits> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/internal/raw_logging.h" |
| #include "absl/time/clock.h" |
| #include "absl/time/time.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace synchronization_internal { |
| |
| // An optional timeout, with nanosecond granularity. |
| // |
| // This is a private low-level API for use by a handful of low-level |
| // components. Higher-level components should build APIs based on |
| // absl::Time and absl::Duration. |
| class KernelTimeout { |
| public: |
| // Construct an absolute timeout that should expire at `t`. |
| explicit KernelTimeout(absl::Time t); |
| |
| // Construct a relative timeout that should expire after `d`. |
| explicit KernelTimeout(absl::Duration d); |
| |
| // Infinite timeout. |
| constexpr KernelTimeout() : rep_(kNoTimeout) {} |
| |
| // A more explicit factory for those who prefer it. |
| // Equivalent to `KernelTimeout()`. |
| static constexpr KernelTimeout Never() { return KernelTimeout(); } |
| |
| // Returns true if there is a timeout that will eventually expire. |
| // Returns false if the timeout is infinite. |
| bool has_timeout() const { return rep_ != kNoTimeout; } |
| |
| // If `has_timeout()` is true, returns true if the timeout was provided as an |
| // `absl::Time`. The return value is undefined if `has_timeout()` is false |
| // because all indefinite timeouts are equivalent. |
| bool is_absolute_timeout() const { return (rep_ & 1) == 0; } |
| |
| // If `has_timeout()` is true, returns true if the timeout was provided as an |
| // `absl::Duration`. The return value is undefined if `has_timeout()` is false |
| // because all indefinite timeouts are equivalent. |
| bool is_relative_timeout() const { return (rep_ & 1) == 1; } |
| |
| // Convert to `struct timespec` for interfaces that expect an absolute |
| // timeout. If !has_timeout() or is_relative_timeout(), attempts to convert to |
| // a reasonable absolute timeout, but callers should to test has_timeout() and |
| // is_relative_timeout() and prefer to use a more appropriate interface. |
| struct timespec MakeAbsTimespec() const; |
| |
| // Convert to `struct timespec` for interfaces that expect a relative |
| // timeout. If !has_timeout() or is_absolute_timeout(), attempts to convert to |
| // a reasonable relative timeout, but callers should to test has_timeout() and |
| // is_absolute_timeout() and prefer to use a more appropriate interface. Since |
| // the return value is a relative duration, it should be recomputed by calling |
| // this method in the case of a spurious wakeup. |
| struct timespec MakeRelativeTimespec() const; |
| |
| #ifndef _WIN32 |
| // Convert to `struct timespec` for interfaces that expect an absolute timeout |
| // on a specific clock `c`. This is similar to `MakeAbsTimespec()`, but |
| // callers usually want to use this method with `CLOCK_MONOTONIC` when |
| // relative timeouts are requested, and when the appropriate interface expects |
| // an absolute timeout relative to a specific clock (for example, |
| // pthread_cond_clockwait() or sem_clockwait()). If !has_timeout(), attempts |
| // to convert to a reasonable absolute timeout, but callers should to test |
| // has_timeout() prefer to use a more appropriate interface. |
| struct timespec MakeClockAbsoluteTimespec(clockid_t c) const; |
| #endif |
| |
| // Convert to unix epoch nanos for interfaces that expect an absolute timeout |
| // in nanoseconds. If !has_timeout() or is_relative_timeout(), attempts to |
| // convert to a reasonable absolute timeout, but callers should to test |
| // has_timeout() and is_relative_timeout() and prefer to use a more |
| // appropriate interface. |
| int64_t MakeAbsNanos() const; |
| |
| // Converts to milliseconds from now, or INFINITE when |
| // !has_timeout(). For use by SleepConditionVariableSRW on |
| // Windows. Callers should recognize that the return value is a |
| // relative duration (it should be recomputed by calling this method |
| // in the case of a spurious wakeup). |
| // This header file may be included transitively by public header files, |
| // so we define our own DWORD and INFINITE instead of getting them from |
| // <intsafe.h> and <WinBase.h>. |
| typedef unsigned long DWord; // NOLINT |
| DWord InMillisecondsFromNow() const; |
| |
| // Convert to std::chrono::time_point for interfaces that expect an absolute |
| // timeout, like std::condition_variable::wait_until(). If !has_timeout() or |
| // is_relative_timeout(), attempts to convert to a reasonable absolute |
| // timeout, but callers should test has_timeout() and is_relative_timeout() |
| // and prefer to use a more appropriate interface. |
| std::chrono::time_point<std::chrono::system_clock> ToChronoTimePoint() const; |
| |
| // Convert to std::chrono::time_point for interfaces that expect a relative |
| // timeout, like std::condition_variable::wait_for(). If !has_timeout() or |
| // is_absolute_timeout(), attempts to convert to a reasonable relative |
| // timeout, but callers should test has_timeout() and is_absolute_timeout() |
| // and prefer to use a more appropriate interface. Since the return value is a |
| // relative duration, it should be recomputed by calling this method in the |
| // case of a spurious wakeup. |
| std::chrono::nanoseconds ToChronoDuration() const; |
| |
| // Returns true if steady (aka monotonic) clocks are supported by the system. |
| // This method exists because go/btm requires synchronized clocks, and |
| // thus requires we use the system (aka walltime) clock. |
| static constexpr bool SupportsSteadyClock() { return true; } |
| |
| private: |
| // Returns the current time, expressed as a count of nanoseconds since the |
| // epoch used by an arbitrary clock. The implementation tries to use a steady |
| // (monotonic) clock if one is available. |
| static int64_t SteadyClockNow(); |
| |
| // Internal representation. |
| // - If the value is kNoTimeout, then the timeout is infinite, and |
| // has_timeout() will return true. |
| // - If the low bit is 0, then the high 63 bits is the number of nanoseconds |
| // after the unix epoch. |
| // - If the low bit is 1, then the high 63 bits is the number of nanoseconds |
| // after the epoch used by SteadyClockNow(). |
| // |
| // In all cases the time is stored as an absolute time, the only difference is |
| // the clock epoch. The use of absolute times is important since in the case |
| // of a relative timeout with a spurious wakeup, the program would have to |
| // restart the wait, and thus needs a way of recomputing the remaining time. |
| uint64_t rep_; |
| |
| // Returns the number of nanoseconds stored in the internal representation. |
| // When combined with the clock epoch indicated by the low bit (which is |
| // accessed through is_absolute_timeout() and is_relative_timeout()), the |
| // return value is used to compute when the timeout should occur. |
| int64_t RawAbsNanos() const { return static_cast<int64_t>(rep_ >> 1); } |
| |
| // Converts to nanoseconds from now. Since the return value is a relative |
| // duration, it should be recomputed by calling this method in the case of a |
| // spurious wakeup. |
| int64_t InNanosecondsFromNow() const; |
| |
| // A value that represents no timeout (or an infinite timeout). |
| static constexpr uint64_t kNoTimeout = (std::numeric_limits<uint64_t>::max)(); |
| |
| // The maximum value that can be stored in the high 63 bits. |
| static constexpr int64_t kMaxNanos = (std::numeric_limits<int64_t>::max)(); |
| }; |
| |
| } // namespace synchronization_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ |
| *ÑÑ |
| [soong/.intermediates/external/abseil-cpp/absl_time_hdrs/gen/my_include_dir/absl/time/time.hðÐ// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: time.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines abstractions for computing with absolute points |
| // in time, durations of time, and formatting and parsing time within a given |
| // time zone. The following abstractions are defined: |
| // |
| // * `absl::Time` defines an absolute, specific instance in time |
| // * `absl::Duration` defines a signed, fixed-length span of time |
| // * `absl::TimeZone` defines geopolitical time zone regions (as collected |
| // within the IANA Time Zone database (https://www.iana.org/time-zones)). |
| // |
| // Note: Absolute times are distinct from civil times, which refer to the |
| // human-scale time commonly represented by `YYYY-MM-DD hh:mm:ss`. The mapping |
| // between absolute and civil times can be specified by use of time zones |
| // (`absl::TimeZone` within this API). That is: |
| // |
| // Civil Time = F(Absolute Time, Time Zone) |
| // Absolute Time = G(Civil Time, Time Zone) |
| // |
| // See civil_time.h for abstractions related to constructing and manipulating |
| // civil time. |
| // |
| // Example: |
| // |
| // absl::TimeZone nyc; |
| // // LoadTimeZone() may fail so it's always better to check for success. |
| // if (!absl::LoadTimeZone("America/New_York", &nyc)) { |
| // // handle error case |
| // } |
| // |
| // // My flight leaves NYC on Jan 2, 2017 at 03:04:05 |
| // absl::CivilSecond cs(2017, 1, 2, 3, 4, 5); |
| // absl::Time takeoff = absl::FromCivil(cs, nyc); |
| // |
| // absl::Duration flight_duration = absl::Hours(21) + absl::Minutes(35); |
| // absl::Time landing = takeoff + flight_duration; |
| // |
| // absl::TimeZone syd; |
| // if (!absl::LoadTimeZone("Australia/Sydney", &syd)) { |
| // // handle error case |
| // } |
| // std::string s = absl::FormatTime( |
| // "My flight will land in Sydney on %Y-%m-%d at %H:%M:%S", |
| // landing, syd); |
| |
| #ifndef ABSL_TIME_TIME_H_ |
| #define ABSL_TIME_TIME_H_ |
| |
| #if !defined(_MSC_VER) |
| #include <sys/time.h> |
| #else |
| // We don't include `winsock2.h` because it drags in `windows.h` and friends, |
| // and they define conflicting macros like OPAQUE, ERROR, and more. This has the |
| // potential to break Abseil users. |
| // |
| // Instead we only forward declare `timeval` and require Windows users include |
| // `winsock2.h` themselves. This is both inconsistent and troublesome, but so is |
| // including 'windows.h' so we are picking the lesser of two evils here. |
| struct timeval; |
| #endif |
| |
| #include "absl/base/config.h" |
| |
| // For feature testing and determining which headers can be included. |
| #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L |
| #include <version> |
| #endif |
| |
| #include <chrono> // NOLINT(build/c++11) |
| #include <cmath> |
| #ifdef __cpp_lib_three_way_comparison |
| #include <compare> |
| #endif // __cpp_lib_three_way_comparison |
| #include <cstdint> |
| #include <ctime> |
| #include <limits> |
| #include <ostream> |
| #include <ratio> // NOLINT(build/c++11) |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/macros.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/time/civil_time.h" |
| #include "absl/time/internal/cctz/include/cctz/time_zone.h" |
| |
| #if defined(__cpp_impl_three_way_comparison) && \ |
| defined(__cpp_lib_three_way_comparison) |
| #define ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON 1 |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| class Duration; // Defined below |
| class Time; // Defined below |
| class TimeZone; // Defined below |
| |
| namespace time_internal { |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixDuration(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration ToUnixDuration(Time t); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t GetRepHi(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr uint32_t GetRepLo(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration MakeDuration(int64_t hi, |
| uint32_t lo); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration MakeDuration(int64_t hi, |
| int64_t lo); |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration MakePosDoubleDuration(double n); |
| constexpr int64_t kTicksPerNanosecond = 4; |
| constexpr int64_t kTicksPerSecond = 1000 * 1000 * 1000 * kTicksPerNanosecond; |
| template <std::intmax_t N> |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v, |
| std::ratio<1, N>); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v, |
| std::ratio<60>); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v, |
| std::ratio<3600>); |
| template <typename T> |
| using EnableIfIntegral = typename std::enable_if< |
| std::is_integral<T>::value || std::is_enum<T>::value, int>::type; |
| template <typename T> |
| using EnableIfFloat = |
| typename std::enable_if<std::is_floating_point<T>::value, int>::type; |
| } // namespace time_internal |
| |
| // Duration |
| // |
| // The `absl::Duration` class represents a signed, fixed-length amount of time. |
| // A `Duration` is generated using a unit-specific factory function, or is |
| // the result of subtracting one `absl::Time` from another. Durations behave |
| // like unit-safe integers and they support all the natural integer-like |
| // arithmetic operations. Arithmetic overflows and saturates at +/- infinity. |
| // `Duration` is trivially destructible and should be passed by value rather |
| // than const reference. |
| // |
| // Factory functions `Nanoseconds()`, `Microseconds()`, `Milliseconds()`, |
| // `Seconds()`, `Minutes()`, `Hours()` and `InfiniteDuration()` allow for |
| // creation of constexpr `Duration` values |
| // |
| // Examples: |
| // |
| // constexpr absl::Duration ten_ns = absl::Nanoseconds(10); |
| // constexpr absl::Duration min = absl::Minutes(1); |
| // constexpr absl::Duration hour = absl::Hours(1); |
| // absl::Duration dur = 60 * min; // dur == hour |
| // absl::Duration half_sec = absl::Milliseconds(500); |
| // absl::Duration quarter_sec = 0.25 * absl::Seconds(1); |
| // |
| // `Duration` values can be easily converted to an integral number of units |
| // using the division operator. |
| // |
| // Example: |
| // |
| // constexpr absl::Duration dur = absl::Milliseconds(1500); |
| // int64_t ns = dur / absl::Nanoseconds(1); // ns == 1500000000 |
| // int64_t ms = dur / absl::Milliseconds(1); // ms == 1500 |
| // int64_t sec = dur / absl::Seconds(1); // sec == 1 (subseconds truncated) |
| // int64_t min = dur / absl::Minutes(1); // min == 0 |
| // |
| // See the `IDivDuration()` and `FDivDuration()` functions below for details on |
| // how to access the fractional parts of the quotient. |
| // |
| // Alternatively, conversions can be performed using helpers such as |
| // `ToInt64Microseconds()` and `ToDoubleSeconds()`. |
| class Duration { |
| public: |
| // Value semantics. |
| constexpr Duration() : rep_hi_(0), rep_lo_(0) {} // zero-length duration |
| |
| // Copyable. |
| #if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1930 |
| // Explicitly defining the constexpr copy constructor avoids an MSVC bug. |
| constexpr Duration(const Duration& d) |
| : rep_hi_(d.rep_hi_), rep_lo_(d.rep_lo_) {} |
| #else |
| constexpr Duration(const Duration& d) = default; |
| #endif |
| Duration& operator=(const Duration& d) = default; |
| |
| // Compound assignment operators. |
| Duration& operator+=(Duration d); |
| Duration& operator-=(Duration d); |
| Duration& operator*=(int64_t r); |
| Duration& operator*=(double r); |
| Duration& operator/=(int64_t r); |
| Duration& operator/=(double r); |
| Duration& operator%=(Duration rhs); |
| |
| // Overloads that forward to either the int64_t or double overloads above. |
| // Integer operands must be representable as int64_t. Integer division is |
| // truncating, so values less than the resolution will be returned as zero. |
| // Floating-point multiplication and division is rounding (halfway cases |
| // rounding away from zero), so values less than the resolution may be |
| // returned as either the resolution or zero. In particular, `d / 2.0` |
| // can produce `d` when it is the resolution and "even". |
| template <typename T, time_internal::EnableIfIntegral<T> = 0> |
| Duration& operator*=(T r) { |
| int64_t x = r; |
| return *this *= x; |
| } |
| |
| template <typename T, time_internal::EnableIfIntegral<T> = 0> |
| Duration& operator/=(T r) { |
| int64_t x = r; |
| return *this /= x; |
| } |
| |
| template <typename T, time_internal::EnableIfFloat<T> = 0> |
| Duration& operator*=(T r) { |
| double x = r; |
| return *this *= x; |
| } |
| |
| template <typename T, time_internal::EnableIfFloat<T> = 0> |
| Duration& operator/=(T r) { |
| double x = r; |
| return *this /= x; |
| } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, Duration d) { |
| return H::combine(std::move(h), d.rep_hi_.Get(), d.rep_lo_); |
| } |
| |
| private: |
| friend constexpr int64_t time_internal::GetRepHi(Duration d); |
| friend constexpr uint32_t time_internal::GetRepLo(Duration d); |
| friend constexpr Duration time_internal::MakeDuration(int64_t hi, |
| uint32_t lo); |
| constexpr Duration(int64_t hi, uint32_t lo) : rep_hi_(hi), rep_lo_(lo) {} |
| |
| // We store `rep_hi_` 4-byte rather than 8-byte aligned to avoid 4 bytes of |
| // tail padding. |
| class HiRep { |
| public: |
| // Default constructor default-initializes `hi_`, which has the same |
| // semantics as default-initializing an `int64_t` (undetermined value). |
| HiRep() = default; |
| |
| HiRep(const HiRep&) = default; |
| HiRep& operator=(const HiRep&) = default; |
| |
| explicit constexpr HiRep(const int64_t value) |
| : // C++17 forbids default-initialization in constexpr contexts. We can |
| // remove this in C++20. |
| #if defined(ABSL_IS_BIG_ENDIAN) && ABSL_IS_BIG_ENDIAN |
| hi_(0), |
| lo_(0) |
| #else |
| lo_(0), |
| hi_(0) |
| #endif |
| { |
| *this = value; |
| } |
| |
| constexpr int64_t Get() const { |
| const uint64_t unsigned_value = |
| (static_cast<uint64_t>(hi_) << 32) | static_cast<uint64_t>(lo_); |
| // `static_cast<int64_t>(unsigned_value)` is implementation-defined |
| // before c++20. On all supported platforms the behaviour is that mandated |
| // by c++20, i.e. "If the destination type is signed, [...] the result is |
| // the unique value of the destination type equal to the source value |
| // modulo 2^n, where n is the number of bits used to represent the |
| // destination type." |
| static_assert( |
| (static_cast<int64_t>((std::numeric_limits<uint64_t>::max)()) == |
| int64_t{-1}) && |
| (static_cast<int64_t>(static_cast<uint64_t>( |
| (std::numeric_limits<int64_t>::max)()) + |
| 1) == |
| (std::numeric_limits<int64_t>::min)()), |
| "static_cast<int64_t>(uint64_t) does not have c++20 semantics"); |
| return static_cast<int64_t>(unsigned_value); |
| } |
| |
| constexpr HiRep& operator=(const int64_t value) { |
| // "If the destination type is unsigned, the resulting value is the |
| // smallest unsigned value equal to the source value modulo 2^n |
| // where `n` is the number of bits used to represent the destination |
| // type". |
| const auto unsigned_value = static_cast<uint64_t>(value); |
| hi_ = static_cast<uint32_t>(unsigned_value >> 32); |
| lo_ = static_cast<uint32_t>(unsigned_value); |
| return *this; |
| } |
| |
| private: |
| // Notes: |
| // - Ideally we would use a `char[]` and `std::bitcast`, but the latter |
| // does not exist (and is not constexpr in `absl`) before c++20. |
| // - Order is optimized depending on endianness so that the compiler can |
| // turn `Get()` (resp. `operator=()`) into a single 8-byte load (resp. |
| // store). |
| #if defined(ABSL_IS_BIG_ENDIAN) && ABSL_IS_BIG_ENDIAN |
| uint32_t hi_; |
| uint32_t lo_; |
| #else |
| uint32_t lo_; |
| uint32_t hi_; |
| #endif |
| }; |
| HiRep rep_hi_; |
| uint32_t rep_lo_; |
| }; |
| |
| // Relational Operators |
| |
| #ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr std::strong_ordering operator<=>( |
| Duration lhs, Duration rhs); |
| |
| #endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<(Duration lhs, |
| Duration rhs); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator>(Duration lhs, |
| Duration rhs) { |
| return rhs < lhs; |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator>=(Duration lhs, |
| Duration rhs) { |
| return !(lhs < rhs); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<=(Duration lhs, |
| Duration rhs) { |
| return !(rhs < lhs); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator==(Duration lhs, |
| Duration rhs); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator!=(Duration lhs, |
| Duration rhs) { |
| return !(lhs == rhs); |
| } |
| |
| // Additive Operators |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration operator-(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration operator+(Duration lhs, |
| Duration rhs) { |
| return lhs += rhs; |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration operator-(Duration lhs, |
| Duration rhs) { |
| return lhs -= rhs; |
| } |
| |
| // IDivDuration() |
| // |
| // Divides a numerator `Duration` by a denominator `Duration`, returning the |
| // quotient and remainder. The remainder always has the same sign as the |
| // numerator. The returned quotient and remainder respect the identity: |
| // |
| // numerator = denominator * quotient + remainder |
| // |
| // Returned quotients are capped to the range of `int64_t`, with the difference |
| // spilling into the remainder to uphold the above identity. This means that the |
| // remainder returned could differ from the remainder returned by |
| // `Duration::operator%` for huge quotients. |
| // |
| // See also the notes on `InfiniteDuration()` below regarding the behavior of |
| // division involving zero and infinite durations. |
| // |
| // Example: |
| // |
| // constexpr absl::Duration a = |
| // absl::Seconds(std::numeric_limits<int64_t>::max()); // big |
| // constexpr absl::Duration b = absl::Nanoseconds(1); // small |
| // |
| // absl::Duration rem = a % b; |
| // // rem == absl::ZeroDuration() |
| // |
| // // Here, q would overflow int64_t, so rem accounts for the difference. |
| // int64_t q = absl::IDivDuration(a, b, &rem); |
| // // q == std::numeric_limits<int64_t>::max(), rem == a - b * q |
| int64_t IDivDuration(Duration num, Duration den, Duration* rem); |
| |
| // FDivDuration() |
| // |
| // Divides a `Duration` numerator into a fractional number of units of a |
| // `Duration` denominator. |
| // |
| // See also the notes on `InfiniteDuration()` below regarding the behavior of |
| // division involving zero and infinite durations. |
| // |
| // Example: |
| // |
| // double d = absl::FDivDuration(absl::Milliseconds(1500), absl::Seconds(1)); |
| // // d == 1.5 |
| ABSL_ATTRIBUTE_CONST_FUNCTION double FDivDuration(Duration num, Duration den); |
| |
| // Multiplicative Operators |
| // Integer operands must be representable as int64_t. |
| template <typename T> |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration operator*(Duration lhs, T rhs) { |
| return lhs *= rhs; |
| } |
| template <typename T> |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration operator*(T lhs, Duration rhs) { |
| return rhs *= lhs; |
| } |
| template <typename T> |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration operator/(Duration lhs, T rhs) { |
| return lhs /= rhs; |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t operator/(Duration lhs, |
| Duration rhs) { |
| return IDivDuration(lhs, rhs, |
| &lhs); // trunc towards zero |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration operator%(Duration lhs, |
| Duration rhs) { |
| return lhs %= rhs; |
| } |
| |
| // ZeroDuration() |
| // |
| // Returns a zero-length duration. This function behaves just like the default |
| // constructor, but the name helps make the semantics clear at call sites. |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration ZeroDuration() { |
| return Duration(); |
| } |
| |
| // AbsDuration() |
| // |
| // Returns the absolute value of a duration. |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration AbsDuration(Duration d) { |
| return (d < ZeroDuration()) ? -d : d; |
| } |
| |
| // Trunc() |
| // |
| // Truncates a duration (toward zero) to a multiple of a non-zero unit. |
| // |
| // Example: |
| // |
| // absl::Duration d = absl::Nanoseconds(123456789); |
| // absl::Duration a = absl::Trunc(d, absl::Microseconds(1)); // 123456us |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration Trunc(Duration d, Duration unit); |
| |
| // Floor() |
| // |
| // Floors a duration using the passed duration unit to its largest value not |
| // greater than the duration. |
| // |
| // Example: |
| // |
| // absl::Duration d = absl::Nanoseconds(123456789); |
| // absl::Duration b = absl::Floor(d, absl::Microseconds(1)); // 123456us |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration Floor(Duration d, Duration unit); |
| |
| // Ceil() |
| // |
| // Returns the ceiling of a duration using the passed duration unit to its |
| // smallest value not less than the duration. |
| // |
| // Example: |
| // |
| // absl::Duration d = absl::Nanoseconds(123456789); |
| // absl::Duration c = absl::Ceil(d, absl::Microseconds(1)); // 123457us |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration Ceil(Duration d, Duration unit); |
| |
| // InfiniteDuration() |
| // |
| // Returns an infinite `Duration`. To get a `Duration` representing negative |
| // infinity, use `-InfiniteDuration()`. |
| // |
| // Duration arithmetic overflows to +/- infinity and saturates. In general, |
| // arithmetic with `Duration` infinities is similar to IEEE 754 infinities |
| // except where IEEE 754 NaN would be involved, in which case +/- |
| // `InfiniteDuration()` is used in place of a "nan" Duration. |
| // |
| // Examples: |
| // |
| // constexpr absl::Duration inf = absl::InfiniteDuration(); |
| // const absl::Duration d = ... any finite duration ... |
| // |
| // inf == inf + inf |
| // inf == inf + d |
| // inf == inf - inf |
| // -inf == d - inf |
| // |
| // inf == d * 1e100 |
| // inf == inf / 2 |
| // 0 == d / inf |
| // INT64_MAX == inf / d |
| // |
| // d < inf |
| // -inf < d |
| // |
| // // Division by zero returns infinity, or INT64_MIN/MAX where appropriate. |
| // inf == d / 0 |
| // INT64_MAX == d / absl::ZeroDuration() |
| // |
| // The examples involving the `/` operator above also apply to `IDivDuration()` |
| // and `FDivDuration()`. |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration InfiniteDuration(); |
| |
| // Nanoseconds() |
| // Microseconds() |
| // Milliseconds() |
| // Seconds() |
| // Minutes() |
| // Hours() |
| // |
| // Factory functions for constructing `Duration` values from an integral number |
| // of the unit indicated by the factory function's name. The number must be |
| // representable as int64_t. |
| // |
| // NOTE: no "Days()" factory function exists because "a day" is ambiguous. |
| // Civil days are not always 24 hours long, and a 24-hour duration often does |
| // not correspond with a civil day. If a 24-hour duration is needed, use |
| // `absl::Hours(24)`. If you actually want a civil day, use absl::CivilDay |
| // from civil_time.h. |
| // |
| // Example: |
| // |
| // absl::Duration a = absl::Seconds(60); |
| // absl::Duration b = absl::Minutes(1); // b == a |
| template <typename T, time_internal::EnableIfIntegral<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Nanoseconds(T n) { |
| return time_internal::FromInt64(n, std::nano{}); |
| } |
| template <typename T, time_internal::EnableIfIntegral<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Microseconds(T n) { |
| return time_internal::FromInt64(n, std::micro{}); |
| } |
| template <typename T, time_internal::EnableIfIntegral<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Milliseconds(T n) { |
| return time_internal::FromInt64(n, std::milli{}); |
| } |
| template <typename T, time_internal::EnableIfIntegral<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Seconds(T n) { |
| return time_internal::FromInt64(n, std::ratio<1>{}); |
| } |
| template <typename T, time_internal::EnableIfIntegral<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Minutes(T n) { |
| return time_internal::FromInt64(n, std::ratio<60>{}); |
| } |
| template <typename T, time_internal::EnableIfIntegral<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Hours(T n) { |
| return time_internal::FromInt64(n, std::ratio<3600>{}); |
| } |
| |
| // Factory overloads for constructing `Duration` values from a floating-point |
| // number of the unit indicated by the factory function's name. These functions |
| // exist for convenience, but they are not as efficient as the integral |
| // factories, which should be preferred. |
| // |
| // Example: |
| // |
| // auto a = absl::Seconds(1.5); // OK |
| // auto b = absl::Milliseconds(1500); // BETTER |
| template <typename T, time_internal::EnableIfFloat<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration Nanoseconds(T n) { |
| return n * Nanoseconds(1); |
| } |
| template <typename T, time_internal::EnableIfFloat<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration Microseconds(T n) { |
| return n * Microseconds(1); |
| } |
| template <typename T, time_internal::EnableIfFloat<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration Milliseconds(T n) { |
| return n * Milliseconds(1); |
| } |
| template <typename T, time_internal::EnableIfFloat<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration Seconds(T n) { |
| if (n >= 0) { // Note: `NaN >= 0` is false. |
| if (n >= static_cast<T>((std::numeric_limits<int64_t>::max)())) { |
| return InfiniteDuration(); |
| } |
| return time_internal::MakePosDoubleDuration(n); |
| } else { |
| if (std::isnan(n)) |
| return std::signbit(n) ? -InfiniteDuration() : InfiniteDuration(); |
| if (n <= (std::numeric_limits<int64_t>::min)()) return -InfiniteDuration(); |
| return -time_internal::MakePosDoubleDuration(-n); |
| } |
| } |
| template <typename T, time_internal::EnableIfFloat<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration Minutes(T n) { |
| return n * Minutes(1); |
| } |
| template <typename T, time_internal::EnableIfFloat<T> = 0> |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration Hours(T n) { |
| return n * Hours(1); |
| } |
| |
| // ToInt64Nanoseconds() |
| // ToInt64Microseconds() |
| // ToInt64Milliseconds() |
| // ToInt64Seconds() |
| // ToInt64Minutes() |
| // ToInt64Hours() |
| // |
| // Helper functions that convert a Duration to an integral count of the |
| // indicated unit. These return the same results as the `IDivDuration()` |
| // function, though they usually do so more efficiently; see the |
| // documentation of `IDivDuration()` for details about overflow, etc. |
| // |
| // Example: |
| // |
| // absl::Duration d = absl::Milliseconds(1500); |
| // int64_t isec = absl::ToInt64Seconds(d); // isec == 1 |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Nanoseconds(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Microseconds(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Milliseconds(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Seconds(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Minutes(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Hours(Duration d); |
| |
| // ToDoubleNanoseconds() |
| // ToDoubleMicroseconds() |
| // ToDoubleMilliseconds() |
| // ToDoubleSeconds() |
| // ToDoubleMinutes() |
| // ToDoubleHours() |
| // |
| // Helper functions that convert a Duration to a floating point count of the |
| // indicated unit. These functions are shorthand for the `FDivDuration()` |
| // function above; see its documentation for details about overflow, etc. |
| // |
| // Example: |
| // |
| // absl::Duration d = absl::Milliseconds(1500); |
| // double dsec = absl::ToDoubleSeconds(d); // dsec == 1.5 |
| ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleNanoseconds(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleMicroseconds(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleMilliseconds(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleSeconds(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleMinutes(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleHours(Duration d); |
| |
| // FromChrono() |
| // |
| // Converts any of the pre-defined std::chrono durations to an absl::Duration. |
| // |
| // Example: |
| // |
| // std::chrono::milliseconds ms(123); |
| // absl::Duration d = absl::FromChrono(ms); |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::nanoseconds& d); |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::microseconds& d); |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::milliseconds& d); |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::seconds& d); |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::minutes& d); |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::hours& d); |
| |
| // ToChronoNanoseconds() |
| // ToChronoMicroseconds() |
| // ToChronoMilliseconds() |
| // ToChronoSeconds() |
| // ToChronoMinutes() |
| // ToChronoHours() |
| // |
| // Converts an absl::Duration to any of the pre-defined std::chrono durations. |
| // If overflow would occur, the returned value will saturate at the min/max |
| // chrono duration value instead. |
| // |
| // Example: |
| // |
| // absl::Duration d = absl::Microseconds(123); |
| // auto x = absl::ToChronoMicroseconds(d); |
| // auto y = absl::ToChronoNanoseconds(d); // x == y |
| // auto z = absl::ToChronoSeconds(absl::InfiniteDuration()); |
| // // z == std::chrono::seconds::max() |
| ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::nanoseconds ToChronoNanoseconds( |
| Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::microseconds ToChronoMicroseconds( |
| Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::milliseconds ToChronoMilliseconds( |
| Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::seconds ToChronoSeconds(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::minutes ToChronoMinutes(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::hours ToChronoHours(Duration d); |
| |
| // FormatDuration() |
| // |
| // Returns a string representing the duration in the form "72h3m0.5s". |
| // Returns "inf" or "-inf" for +/- `InfiniteDuration()`. |
| ABSL_ATTRIBUTE_CONST_FUNCTION std::string FormatDuration(Duration d); |
| |
| // Output stream operator. |
| inline std::ostream& operator<<(std::ostream& os, Duration d) { |
| return os << FormatDuration(d); |
| } |
| |
| // Support for StrFormat(), StrCat() etc. |
| template <typename Sink> |
| void AbslStringify(Sink& sink, Duration d) { |
| sink.Append(FormatDuration(d)); |
| } |
| |
| // ParseDuration() |
| // |
| // Parses a duration string consisting of a possibly signed sequence of |
| // decimal numbers, each with an optional fractional part and a unit |
| // suffix. The valid suffixes are "ns", "us" "ms", "s", "m", and "h". |
| // Simple examples include "300ms", "-1.5h", and "2h45m". Parses "0" as |
| // `ZeroDuration()`. Parses "inf" and "-inf" as +/- `InfiniteDuration()`. |
| bool ParseDuration(absl::string_view dur_string, Duration* d); |
| |
| // AbslParseFlag() |
| // |
| // Parses a command-line flag string representation `text` into a Duration |
| // value. Duration flags must be specified in a format that is valid input for |
| // `absl::ParseDuration()`. |
| bool AbslParseFlag(absl::string_view text, Duration* dst, std::string* error); |
| |
| |
| // AbslUnparseFlag() |
| // |
| // Unparses a Duration value into a command-line string representation using |
| // the format specified by `absl::ParseDuration()`. |
| std::string AbslUnparseFlag(Duration d); |
| |
| ABSL_DEPRECATED("Use AbslParseFlag() instead.") |
| bool ParseFlag(const std::string& text, Duration* dst, std::string* error); |
| ABSL_DEPRECATED("Use AbslUnparseFlag() instead.") |
| std::string UnparseFlag(Duration d); |
| |
| // Time |
| // |
| // An `absl::Time` represents a specific instant in time. Arithmetic operators |
| // are provided for naturally expressing time calculations. Instances are |
| // created using `absl::Now()` and the `absl::From*()` factory functions that |
| // accept the gamut of other time representations. Formatting and parsing |
| // functions are provided for conversion to and from strings. `absl::Time` is |
| // trivially destructible and should be passed by value rather than const |
| // reference. |
| // |
| // `absl::Time` assumes there are 60 seconds in a minute, which means the |
| // underlying time scales must be "smeared" to eliminate leap seconds. |
| // See https://developers.google.com/time/smear. |
| // |
| // Even though `absl::Time` supports a wide range of timestamps, exercise |
| // caution when using values in the distant past. `absl::Time` uses the |
| // Proleptic Gregorian calendar, which extends the Gregorian calendar backward |
| // to dates before its introduction in 1582. |
| // See https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar |
| // for more information. Use the ICU calendar classes to convert a date in |
| // some other calendar (http://userguide.icu-project.org/datetime/calendar). |
| // |
| // Similarly, standardized time zones are a reasonably recent innovation, with |
| // the Greenwich prime meridian being established in 1884. The TZ database |
| // itself does not profess accurate offsets for timestamps prior to 1970. The |
| // breakdown of future timestamps is subject to the whim of regional |
| // governments. |
| // |
| // The `absl::Time` class represents an instant in time as a count of clock |
| // ticks of some granularity (resolution) from some starting point (epoch). |
| // |
| // `absl::Time` uses a resolution that is high enough to avoid loss in |
| // precision, and a range that is wide enough to avoid overflow, when |
| // converting between tick counts in most Google time scales (i.e., resolution |
| // of at least one nanosecond, and range +/-100 billion years). Conversions |
| // between the time scales are performed by truncating (towards negative |
| // infinity) to the nearest representable point. |
| // |
| // Examples: |
| // |
| // absl::Time t1 = ...; |
| // absl::Time t2 = t1 + absl::Minutes(2); |
| // absl::Duration d = t2 - t1; // == absl::Minutes(2) |
| // |
| class Time { |
| public: |
| // Value semantics. |
| |
| // Returns the Unix epoch. However, those reading your code may not know |
| // or expect the Unix epoch as the default value, so make your code more |
| // readable by explicitly initializing all instances before use. |
| // |
| // Example: |
| // absl::Time t = absl::UnixEpoch(); |
| // absl::Time t = absl::Now(); |
| // absl::Time t = absl::TimeFromTimeval(tv); |
| // absl::Time t = absl::InfinitePast(); |
| constexpr Time() = default; |
| |
| // Copyable. |
| constexpr Time(const Time& t) = default; |
| Time& operator=(const Time& t) = default; |
| |
| // Assignment operators. |
| Time& operator+=(Duration d) { |
| rep_ += d; |
| return *this; |
| } |
| Time& operator-=(Duration d) { |
| rep_ -= d; |
| return *this; |
| } |
| |
| // Time::Breakdown |
| // |
| // The calendar and wall-clock (aka "civil time") components of an |
| // `absl::Time` in a certain `absl::TimeZone`. This struct is not |
| // intended to represent an instant in time. So, rather than passing |
| // a `Time::Breakdown` to a function, pass an `absl::Time` and an |
| // `absl::TimeZone`. |
| // |
| // Deprecated. Use `absl::TimeZone::CivilInfo`. |
| struct ABSL_DEPRECATED("Use `absl::TimeZone::CivilInfo`.") Breakdown { |
| int64_t year; // year (e.g., 2013) |
| int month; // month of year [1:12] |
| int day; // day of month [1:31] |
| int hour; // hour of day [0:23] |
| int minute; // minute of hour [0:59] |
| int second; // second of minute [0:59] |
| Duration subsecond; // [Seconds(0):Seconds(1)) if finite |
| int weekday; // 1==Mon, ..., 7=Sun |
| int yearday; // day of year [1:366] |
| |
| // Note: The following fields exist for backward compatibility |
| // with older APIs. Accessing these fields directly is a sign of |
| // imprudent logic in the calling code. Modern time-related code |
| // should only access this data indirectly by way of FormatTime(). |
| // These fields are undefined for InfiniteFuture() and InfinitePast(). |
| int offset; // seconds east of UTC |
| bool is_dst; // is offset non-standard? |
| const char* zone_abbr; // time-zone abbreviation (e.g., "PST") |
| }; |
| |
| // Time::In() |
| // |
| // Returns the breakdown of this instant in the given TimeZone. |
| // |
| // Deprecated. Use `absl::TimeZone::At(Time)`. |
| ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING |
| ABSL_DEPRECATED("Use `absl::TimeZone::At(Time)`.") |
| Breakdown In(TimeZone tz) const; |
| ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING |
| |
| template <typename H> |
| friend H AbslHashValue(H h, Time t) { |
| return H::combine(std::move(h), t.rep_); |
| } |
| |
| private: |
| friend constexpr Time time_internal::FromUnixDuration(Duration d); |
| friend constexpr Duration time_internal::ToUnixDuration(Time t); |
| |
| #ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON |
| friend constexpr std::strong_ordering operator<=>(Time lhs, Time rhs); |
| #endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON |
| |
| friend constexpr bool operator<(Time lhs, Time rhs); |
| friend constexpr bool operator==(Time lhs, Time rhs); |
| friend Duration operator-(Time lhs, Time rhs); |
| friend constexpr Time UniversalEpoch(); |
| friend constexpr Time InfiniteFuture(); |
| friend constexpr Time InfinitePast(); |
| constexpr explicit Time(Duration rep) : rep_(rep) {} |
| Duration rep_; |
| }; |
| |
| // Relational Operators |
| #ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr std::strong_ordering operator<=>( |
| Time lhs, Time rhs) { |
| return lhs.rep_ <=> rhs.rep_; |
| } |
| |
| #endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<(Time lhs, Time rhs) { |
| return lhs.rep_ < rhs.rep_; |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator>(Time lhs, Time rhs) { |
| return rhs < lhs; |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator>=(Time lhs, Time rhs) { |
| return !(lhs < rhs); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<=(Time lhs, Time rhs) { |
| return !(rhs < lhs); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator==(Time lhs, Time rhs) { |
| return lhs.rep_ == rhs.rep_; |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator!=(Time lhs, Time rhs) { |
| return !(lhs == rhs); |
| } |
| |
| // Additive Operators |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline Time operator+(Time lhs, Duration rhs) { |
| return lhs += rhs; |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline Time operator+(Duration lhs, Time rhs) { |
| return rhs += lhs; |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline Time operator-(Time lhs, Duration rhs) { |
| return lhs -= rhs; |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration operator-(Time lhs, Time rhs) { |
| return lhs.rep_ - rhs.rep_; |
| } |
| |
| // UnixEpoch() |
| // |
| // Returns the `absl::Time` representing "1970-01-01 00:00:00.0 +0000". |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time UnixEpoch() { return Time(); } |
| |
| // UniversalEpoch() |
| // |
| // Returns the `absl::Time` representing "0001-01-01 00:00:00.0 +0000", the |
| // epoch of the ICU Universal Time Scale. |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time UniversalEpoch() { |
| // 719162 is the number of days from 0001-01-01 to 1970-01-01, |
| // assuming the Gregorian calendar. |
| return Time( |
| time_internal::MakeDuration(-24 * 719162 * int64_t{3600}, uint32_t{0})); |
| } |
| |
| // InfiniteFuture() |
| // |
| // Returns an `absl::Time` that is infinitely far in the future. |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time InfiniteFuture() { |
| return Time(time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(), |
| ~uint32_t{0})); |
| } |
| |
| // InfinitePast() |
| // |
| // Returns an `absl::Time` that is infinitely far in the past. |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time InfinitePast() { |
| return Time(time_internal::MakeDuration((std::numeric_limits<int64_t>::min)(), |
| ~uint32_t{0})); |
| } |
| |
| // FromUnixNanos() |
| // FromUnixMicros() |
| // FromUnixMillis() |
| // FromUnixSeconds() |
| // FromTimeT() |
| // FromUDate() |
| // FromUniversal() |
| // |
| // Creates an `absl::Time` from a variety of other representations. See |
| // https://unicode-org.github.io/icu/userguide/datetime/universaltimescale.html |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixNanos(int64_t ns); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixMicros(int64_t us); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixMillis(int64_t ms); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixSeconds(int64_t s); |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromTimeT(time_t t); |
| ABSL_ATTRIBUTE_CONST_FUNCTION Time FromUDate(double udate); |
| ABSL_ATTRIBUTE_CONST_FUNCTION Time FromUniversal(int64_t universal); |
| |
| // ToUnixNanos() |
| // ToUnixMicros() |
| // ToUnixMillis() |
| // ToUnixSeconds() |
| // ToTimeT() |
| // ToUDate() |
| // ToUniversal() |
| // |
| // Converts an `absl::Time` to a variety of other representations. See |
| // https://unicode-org.github.io/icu/userguide/datetime/universaltimescale.html |
| // |
| // Note that these operations round down toward negative infinity where |
| // necessary to adjust to the resolution of the result type. Beware of |
| // possible time_t over/underflow in ToTime{T,val,spec}() on 32-bit platforms. |
| ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToUnixNanos(Time t); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToUnixMicros(Time t); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToUnixMillis(Time t); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToUnixSeconds(Time t); |
| ABSL_ATTRIBUTE_CONST_FUNCTION time_t ToTimeT(Time t); |
| ABSL_ATTRIBUTE_CONST_FUNCTION double ToUDate(Time t); |
| ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToUniversal(Time t); |
| |
| // DurationFromTimespec() |
| // DurationFromTimeval() |
| // ToTimespec() |
| // ToTimeval() |
| // TimeFromTimespec() |
| // TimeFromTimeval() |
| // ToTimespec() |
| // ToTimeval() |
| // |
| // Some APIs use a timespec or a timeval as a Duration (e.g., nanosleep(2) |
| // and select(2)), while others use them as a Time (e.g. clock_gettime(2) |
| // and gettimeofday(2)), so conversion functions are provided for both cases. |
| // The "to timespec/val" direction is easily handled via overloading, but |
| // for "from timespec/val" the desired type is part of the function name. |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration DurationFromTimespec(timespec ts); |
| ABSL_ATTRIBUTE_CONST_FUNCTION Duration DurationFromTimeval(timeval tv); |
| ABSL_ATTRIBUTE_CONST_FUNCTION timespec ToTimespec(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION timeval ToTimeval(Duration d); |
| ABSL_ATTRIBUTE_CONST_FUNCTION Time TimeFromTimespec(timespec ts); |
| ABSL_ATTRIBUTE_CONST_FUNCTION Time TimeFromTimeval(timeval tv); |
| ABSL_ATTRIBUTE_CONST_FUNCTION timespec ToTimespec(Time t); |
| ABSL_ATTRIBUTE_CONST_FUNCTION timeval ToTimeval(Time t); |
| |
| // FromChrono() |
| // |
| // Converts a std::chrono::system_clock::time_point to an absl::Time. |
| // |
| // Example: |
| // |
| // auto tp = std::chrono::system_clock::from_time_t(123); |
| // absl::Time t = absl::FromChrono(tp); |
| // // t == absl::FromTimeT(123) |
| ABSL_ATTRIBUTE_PURE_FUNCTION Time |
| FromChrono(const std::chrono::system_clock::time_point& tp); |
| |
| // ToChronoTime() |
| // |
| // Converts an absl::Time to a std::chrono::system_clock::time_point. If |
| // overflow would occur, the returned value will saturate at the min/max time |
| // point value instead. |
| // |
| // Example: |
| // |
| // absl::Time t = absl::FromTimeT(123); |
| // auto tp = absl::ToChronoTime(t); |
| // // tp == std::chrono::system_clock::from_time_t(123); |
| ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::system_clock::time_point |
| ToChronoTime(Time); |
| |
| // AbslParseFlag() |
| // |
| // Parses the command-line flag string representation `text` into a Time value. |
| // Time flags must be specified in a format that matches absl::RFC3339_full. |
| // |
| // For example: |
| // |
| // --start_time=2016-01-02T03:04:05.678+08:00 |
| // |
| // Note: A UTC offset (or 'Z' indicating a zero-offset from UTC) is required. |
| // |
| // Additionally, if you'd like to specify a time as a count of |
| // seconds/milliseconds/etc from the Unix epoch, use an absl::Duration flag |
| // and add that duration to absl::UnixEpoch() to get an absl::Time. |
| bool AbslParseFlag(absl::string_view text, Time* t, std::string* error); |
| |
| // AbslUnparseFlag() |
| // |
| // Unparses a Time value into a command-line string representation using |
| // the format specified by `absl::ParseTime()`. |
| std::string AbslUnparseFlag(Time t); |
| |
| ABSL_DEPRECATED("Use AbslParseFlag() instead.") |
| bool ParseFlag(const std::string& text, Time* t, std::string* error); |
| ABSL_DEPRECATED("Use AbslUnparseFlag() instead.") |
| std::string UnparseFlag(Time t); |
| |
| // TimeZone |
| // |
| // The `absl::TimeZone` is an opaque, small, value-type class representing a |
| // geo-political region within which particular rules are used for converting |
| // between absolute and civil times (see https://git.io/v59Ly). `absl::TimeZone` |
| // values are named using the TZ identifiers from the IANA Time Zone Database, |
| // such as "America/Los_Angeles" or "Australia/Sydney". `absl::TimeZone` values |
| // are created from factory functions such as `absl::LoadTimeZone()`. Note: |
| // strings like "PST" and "EDT" are not valid TZ identifiers. Prefer to pass by |
| // value rather than const reference. |
| // |
| // For more on the fundamental concepts of time zones, absolute times, and civil |
| // times, see https://github.com/google/cctz#fundamental-concepts |
| // |
| // Examples: |
| // |
| // absl::TimeZone utc = absl::UTCTimeZone(); |
| // absl::TimeZone pst = absl::FixedTimeZone(-8 * 60 * 60); |
| // absl::TimeZone loc = absl::LocalTimeZone(); |
| // absl::TimeZone lax; |
| // if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { |
| // // handle error case |
| // } |
| // |
| // See also: |
| // - https://github.com/google/cctz |
| // - https://www.iana.org/time-zones |
| // - https://en.wikipedia.org/wiki/Zoneinfo |
| class TimeZone { |
| public: |
| explicit TimeZone(time_internal::cctz::time_zone tz) : cz_(tz) {} |
| TimeZone() = default; // UTC, but prefer UTCTimeZone() to be explicit. |
| |
| // Copyable. |
| TimeZone(const TimeZone&) = default; |
| TimeZone& operator=(const TimeZone&) = default; |
| |
| explicit operator time_internal::cctz::time_zone() const { return cz_; } |
| |
| std::string name() const { return cz_.name(); } |
| |
| // TimeZone::CivilInfo |
| // |
| // Information about the civil time corresponding to an absolute time. |
| // This struct is not intended to represent an instant in time. So, rather |
| // than passing a `TimeZone::CivilInfo` to a function, pass an `absl::Time` |
| // and an `absl::TimeZone`. |
| struct CivilInfo { |
| CivilSecond cs; |
| Duration subsecond; |
| |
| // Note: The following fields exist for backward compatibility |
| // with older APIs. Accessing these fields directly is a sign of |
| // imprudent logic in the calling code. Modern time-related code |
| // should only access this data indirectly by way of FormatTime(). |
| // These fields are undefined for InfiniteFuture() and InfinitePast(). |
| int offset; // seconds east of UTC |
| bool is_dst; // is offset non-standard? |
| const char* zone_abbr; // time-zone abbreviation (e.g., "PST") |
| }; |
| |
| // TimeZone::At(Time) |
| // |
| // Returns the civil time for this TimeZone at a certain `absl::Time`. |
| // If the input time is infinite, the output civil second will be set to |
| // CivilSecond::max() or min(), and the subsecond will be infinite. |
| // |
| // Example: |
| // |
| // const auto epoch = lax.At(absl::UnixEpoch()); |
| // // epoch.cs == 1969-12-31 16:00:00 |
| // // epoch.subsecond == absl::ZeroDuration() |
| // // epoch.offset == -28800 |
| // // epoch.is_dst == false |
| // // epoch.abbr == "PST" |
| CivilInfo At(Time t) const; |
| |
| // TimeZone::TimeInfo |
| // |
| // Information about the absolute times corresponding to a civil time. |
| // (Subseconds must be handled separately.) |
| // |
| // It is possible for a caller to pass a civil-time value that does |
| // not represent an actual or unique instant in time (due to a shift |
| // in UTC offset in the TimeZone, which results in a discontinuity in |
| // the civil-time components). For example, a daylight-saving-time |
| // transition skips or repeats civil times---in the United States, |
| // March 13, 2011 02:15 never occurred, while November 6, 2011 01:15 |
| // occurred twice---so requests for such times are not well-defined. |
| // To account for these possibilities, `absl::TimeZone::TimeInfo` is |
| // richer than just a single `absl::Time`. |
| struct TimeInfo { |
| enum CivilKind { |
| UNIQUE, // the civil time was singular (pre == trans == post) |
| SKIPPED, // the civil time did not exist (pre >= trans > post) |
| REPEATED, // the civil time was ambiguous (pre < trans <= post) |
| } kind; |
| Time pre; // time calculated using the pre-transition offset |
| Time trans; // when the civil-time discontinuity occurred |
| Time post; // time calculated using the post-transition offset |
| }; |
| |
| // TimeZone::At(CivilSecond) |
| // |
| // Returns an `absl::TimeInfo` containing the absolute time(s) for this |
| // TimeZone at an `absl::CivilSecond`. When the civil time is skipped or |
| // repeated, returns times calculated using the pre-transition and post- |
| // transition UTC offsets, plus the transition time itself. |
| // |
| // Examples: |
| // |
| // // A unique civil time |
| // const auto jan01 = lax.At(absl::CivilSecond(2011, 1, 1, 0, 0, 0)); |
| // // jan01.kind == TimeZone::TimeInfo::UNIQUE |
| // // jan01.pre is 2011-01-01 00:00:00 -0800 |
| // // jan01.trans is 2011-01-01 00:00:00 -0800 |
| // // jan01.post is 2011-01-01 00:00:00 -0800 |
| // |
| // // A Spring DST transition, when there is a gap in civil time |
| // const auto mar13 = lax.At(absl::CivilSecond(2011, 3, 13, 2, 15, 0)); |
| // // mar13.kind == TimeZone::TimeInfo::SKIPPED |
| // // mar13.pre is 2011-03-13 03:15:00 -0700 |
| // // mar13.trans is 2011-03-13 03:00:00 -0700 |
| // // mar13.post is 2011-03-13 01:15:00 -0800 |
| // |
| // // A Fall DST transition, when civil times are repeated |
| // const auto nov06 = lax.At(absl::CivilSecond(2011, 11, 6, 1, 15, 0)); |
| // // nov06.kind == TimeZone::TimeInfo::REPEATED |
| // // nov06.pre is 2011-11-06 01:15:00 -0700 |
| // // nov06.trans is 2011-11-06 01:00:00 -0800 |
| // // nov06.post is 2011-11-06 01:15:00 -0800 |
| TimeInfo At(CivilSecond ct) const; |
| |
| // TimeZone::NextTransition() |
| // TimeZone::PrevTransition() |
| // |
| // Finds the time of the next/previous offset change in this time zone. |
| // |
| // By definition, `NextTransition(t, &trans)` returns false when `t` is |
| // `InfiniteFuture()`, and `PrevTransition(t, &trans)` returns false |
| // when `t` is `InfinitePast()`. If the zone has no transitions, the |
| // result will also be false no matter what the argument. |
| // |
| // Otherwise, when `t` is `InfinitePast()`, `NextTransition(t, &trans)` |
| // returns true and sets `trans` to the first recorded transition. Chains |
| // of calls to `NextTransition()/PrevTransition()` will eventually return |
| // false, but it is unspecified exactly when `NextTransition(t, &trans)` |
| // jumps to false, or what time is set by `PrevTransition(t, &trans)` for |
| // a very distant `t`. |
| // |
| // Note: Enumeration of time-zone transitions is for informational purposes |
| // only. Modern time-related code should not care about when offset changes |
| // occur. |
| // |
| // Example: |
| // absl::TimeZone nyc; |
| // if (!absl::LoadTimeZone("America/New_York", &nyc)) { ... } |
| // const auto now = absl::Now(); |
| // auto t = absl::InfinitePast(); |
| // absl::TimeZone::CivilTransition trans; |
| // while (t <= now && nyc.NextTransition(t, &trans)) { |
| // // transition: trans.from -> trans.to |
| // t = nyc.At(trans.to).trans; |
| // } |
| struct CivilTransition { |
| CivilSecond from; // the civil time we jump from |
| CivilSecond to; // the civil time we jump to |
| }; |
| bool NextTransition(Time t, CivilTransition* trans) const; |
| bool PrevTransition(Time t, CivilTransition* trans) const; |
| |
| template <typename H> |
| friend H AbslHashValue(H h, TimeZone tz) { |
| return H::combine(std::move(h), tz.cz_); |
| } |
| |
| private: |
| friend bool operator==(TimeZone a, TimeZone b) { return a.cz_ == b.cz_; } |
| friend bool operator!=(TimeZone a, TimeZone b) { return a.cz_ != b.cz_; } |
| friend std::ostream& operator<<(std::ostream& os, TimeZone tz) { |
| return os << tz.name(); |
| } |
| |
| time_internal::cctz::time_zone cz_; |
| }; |
| |
| // LoadTimeZone() |
| // |
| // Loads the named zone. May perform I/O on the initial load of the named |
| // zone. If the name is invalid, or some other kind of error occurs, returns |
| // `false` and `*tz` is set to the UTC time zone. |
| inline bool LoadTimeZone(absl::string_view name, TimeZone* tz) { |
| if (name == "localtime") { |
| *tz = TimeZone(time_internal::cctz::local_time_zone()); |
| return true; |
| } |
| time_internal::cctz::time_zone cz; |
| const bool b = time_internal::cctz::load_time_zone(std::string(name), &cz); |
| *tz = TimeZone(cz); |
| return b; |
| } |
| |
| // FixedTimeZone() |
| // |
| // Returns a TimeZone that is a fixed offset (seconds east) from UTC. |
| // Note: If the absolute value of the offset is greater than 24 hours |
| // you'll get UTC (i.e., no offset) instead. |
| inline TimeZone FixedTimeZone(int seconds) { |
| return TimeZone( |
| time_internal::cctz::fixed_time_zone(std::chrono::seconds(seconds))); |
| } |
| |
| // UTCTimeZone() |
| // |
| // Convenience method returning the UTC time zone. |
| inline TimeZone UTCTimeZone() { |
| return TimeZone(time_internal::cctz::utc_time_zone()); |
| } |
| |
| // LocalTimeZone() |
| // |
| // Convenience method returning the local time zone, or UTC if there is |
| // no configured local zone. Warning: Be wary of using LocalTimeZone(), |
| // and particularly so in a server process, as the zone configured for the |
| // local machine should be irrelevant. Prefer an explicit zone name. |
| inline TimeZone LocalTimeZone() { |
| return TimeZone(time_internal::cctz::local_time_zone()); |
| } |
| |
| // ToCivilSecond() |
| // ToCivilMinute() |
| // ToCivilHour() |
| // ToCivilDay() |
| // ToCivilMonth() |
| // ToCivilYear() |
| // |
| // Helpers for TimeZone::At(Time) to return particularly aligned civil times. |
| // |
| // Example: |
| // |
| // absl::Time t = ...; |
| // absl::TimeZone tz = ...; |
| // const auto cd = absl::ToCivilDay(t, tz); |
| ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilSecond ToCivilSecond(Time t, |
| TimeZone tz) { |
| return tz.At(t).cs; // already a CivilSecond |
| } |
| ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilMinute ToCivilMinute(Time t, |
| TimeZone tz) { |
| return CivilMinute(tz.At(t).cs); |
| } |
| ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilHour ToCivilHour(Time t, TimeZone tz) { |
| return CivilHour(tz.At(t).cs); |
| } |
| ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilDay ToCivilDay(Time t, TimeZone tz) { |
| return CivilDay(tz.At(t).cs); |
| } |
| ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilMonth ToCivilMonth(Time t, |
| TimeZone tz) { |
| return CivilMonth(tz.At(t).cs); |
| } |
| ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilYear ToCivilYear(Time t, TimeZone tz) { |
| return CivilYear(tz.At(t).cs); |
| } |
| |
| // FromCivil() |
| // |
| // Helper for TimeZone::At(CivilSecond) that provides "order-preserving |
| // semantics." If the civil time maps to a unique time, that time is |
| // returned. If the civil time is repeated in the given time zone, the |
| // time using the pre-transition offset is returned. Otherwise, the |
| // civil time is skipped in the given time zone, and the transition time |
| // is returned. This means that for any two civil times, ct1 and ct2, |
| // (ct1 < ct2) => (FromCivil(ct1) <= FromCivil(ct2)), the equal case |
| // being when two non-existent civil times map to the same transition time. |
| // |
| // Note: Accepts civil times of any alignment. |
| ABSL_ATTRIBUTE_PURE_FUNCTION inline Time FromCivil(CivilSecond ct, |
| TimeZone tz) { |
| const auto ti = tz.At(ct); |
| if (ti.kind == TimeZone::TimeInfo::SKIPPED) return ti.trans; |
| return ti.pre; |
| } |
| |
| // TimeConversion |
| // |
| // An `absl::TimeConversion` represents the conversion of year, month, day, |
| // hour, minute, and second values (i.e., a civil time), in a particular |
| // `absl::TimeZone`, to a time instant (an absolute time), as returned by |
| // `absl::ConvertDateTime()`. Legacy version of `absl::TimeZone::TimeInfo`. |
| // |
| // Deprecated. Use `absl::TimeZone::TimeInfo`. |
| struct ABSL_DEPRECATED("Use `absl::TimeZone::TimeInfo`.") TimeConversion { |
| Time pre; // time calculated using the pre-transition offset |
| Time trans; // when the civil-time discontinuity occurred |
| Time post; // time calculated using the post-transition offset |
| |
| enum Kind { |
| UNIQUE, // the civil time was singular (pre == trans == post) |
| SKIPPED, // the civil time did not exist |
| REPEATED, // the civil time was ambiguous |
| }; |
| Kind kind; |
| |
| bool normalized; // input values were outside their valid ranges |
| }; |
| |
| // ConvertDateTime() |
| // |
| // Legacy version of `absl::TimeZone::At(absl::CivilSecond)` that takes |
| // the civil time as six, separate values (YMDHMS). |
| // |
| // The input month, day, hour, minute, and second values can be outside |
| // of their valid ranges, in which case they will be "normalized" during |
| // the conversion. |
| // |
| // Example: |
| // |
| // // "October 32" normalizes to "November 1". |
| // absl::TimeConversion tc = |
| // absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, lax); |
| // // tc.kind == TimeConversion::UNIQUE && tc.normalized == true |
| // // absl::ToCivilDay(tc.pre, tz).month() == 11 |
| // // absl::ToCivilDay(tc.pre, tz).day() == 1 |
| // |
| // Deprecated. Use `absl::TimeZone::At(CivilSecond)`. |
| ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING |
| ABSL_DEPRECATED("Use `absl::TimeZone::At(CivilSecond)`.") |
| TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, |
| int min, int sec, TimeZone tz); |
| ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING |
| |
| // FromDateTime() |
| // |
| // A convenience wrapper for `absl::ConvertDateTime()` that simply returns |
| // the "pre" `absl::Time`. That is, the unique result, or the instant that |
| // is correct using the pre-transition offset (as if the transition never |
| // happened). |
| // |
| // Example: |
| // |
| // absl::Time t = absl::FromDateTime(2017, 9, 26, 9, 30, 0, lax); |
| // // t = 2017-09-26 09:30:00 -0700 |
| // |
| // Deprecated. Use `absl::FromCivil(CivilSecond, TimeZone)`. Note that the |
| // behavior of `FromCivil()` differs from `FromDateTime()` for skipped civil |
| // times. If you care about that see `absl::TimeZone::At(absl::CivilSecond)`. |
| ABSL_DEPRECATED("Use `absl::FromCivil(CivilSecond, TimeZone)`.") |
| inline Time FromDateTime(int64_t year, int mon, int day, int hour, int min, |
| int sec, TimeZone tz) { |
| ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING |
| return ConvertDateTime(year, mon, day, hour, min, sec, tz).pre; |
| ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING |
| } |
| |
| // FromTM() |
| // |
| // Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and |
| // `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3) |
| // for a description of the expected values of the tm fields. If the civil time |
| // is unique (see `absl::TimeZone::At(absl::CivilSecond)` above), the matching |
| // time instant is returned. Otherwise, the `tm_isdst` field is consulted to |
| // choose between the possible results. For a repeated civil time, `tm_isdst != |
| // 0` returns the matching DST instant, while `tm_isdst == 0` returns the |
| // matching non-DST instant. For a skipped civil time there is no matching |
| // instant, so `tm_isdst != 0` returns the DST instant, and `tm_isdst == 0` |
| // returns the non-DST instant, that would have matched if the transition never |
| // happened. |
| ABSL_ATTRIBUTE_PURE_FUNCTION Time FromTM(const struct tm& tm, TimeZone tz); |
| |
| // ToTM() |
| // |
| // Converts the given `absl::Time` to a struct tm using the given time zone. |
| // See ctime(3) for a description of the values of the tm fields. |
| ABSL_ATTRIBUTE_PURE_FUNCTION struct tm ToTM(Time t, TimeZone tz); |
| |
| // RFC3339_full |
| // RFC3339_sec |
| // |
| // FormatTime()/ParseTime() format specifiers for RFC3339 date/time strings, |
| // with trailing zeros trimmed or with fractional seconds omitted altogether. |
| // |
| // Note that RFC3339_sec[] matches an ISO 8601 extended format for date and |
| // time with UTC offset. Also note the use of "%Y": RFC3339 mandates that |
| // years have exactly four digits, but we allow them to take their natural |
| // width. |
| ABSL_DLL extern const char RFC3339_full[]; // %Y-%m-%d%ET%H:%M:%E*S%Ez |
| ABSL_DLL extern const char RFC3339_sec[]; // %Y-%m-%d%ET%H:%M:%S%Ez |
| |
| // RFC1123_full |
| // RFC1123_no_wday |
| // |
| // FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings. |
| ABSL_DLL extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z |
| ABSL_DLL extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z |
| |
| // FormatTime() |
| // |
| // Formats the given `absl::Time` in the `absl::TimeZone` according to the |
| // provided format string. Uses strftime()-like formatting options, with |
| // the following extensions: |
| // |
| // - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm) |
| // - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss) |
| // - %E#S - Seconds with # digits of fractional precision |
| // - %E*S - Seconds with full fractional precision (a literal '*') |
| // - %E#f - Fractional seconds with # digits of precision |
| // - %E*f - Fractional seconds with full precision (a literal '*') |
| // - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) |
| // - %ET - The RFC3339 "date-time" separator "T" |
| // |
| // Note that %E0S behaves like %S, and %E0f produces no characters. In |
| // contrast %E*f always produces at least one digit, which may be '0'. |
| // |
| // Note that %Y produces as many characters as it takes to fully render the |
| // year. A year outside of [-999:9999] when formatted with %E4Y will produce |
| // more than four characters, just like %Y. |
| // |
| // We recommend that format strings include the UTC offset (%z, %Ez, or %E*z) |
| // so that the result uniquely identifies a time instant. |
| // |
| // Example: |
| // |
| // absl::CivilSecond cs(2013, 1, 2, 3, 4, 5); |
| // absl::Time t = absl::FromCivil(cs, lax); |
| // std::string f = absl::FormatTime("%H:%M:%S", t, lax); // "03:04:05" |
| // f = absl::FormatTime("%H:%M:%E3S", t, lax); // "03:04:05.000" |
| // |
| // Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned |
| // string will be exactly "infinite-future". If the given `absl::Time` is |
| // `absl::InfinitePast()`, the returned string will be exactly "infinite-past". |
| // In both cases the given format string and `absl::TimeZone` are ignored. |
| // |
| ABSL_ATTRIBUTE_PURE_FUNCTION std::string FormatTime(absl::string_view format, |
| Time t, TimeZone tz); |
| |
| // Convenience functions that format the given time using the RFC3339_full |
| // format. The first overload uses the provided TimeZone, while the second |
| // uses LocalTimeZone(). |
| ABSL_ATTRIBUTE_PURE_FUNCTION std::string FormatTime(Time t, TimeZone tz); |
| ABSL_ATTRIBUTE_PURE_FUNCTION std::string FormatTime(Time t); |
| |
| // Output stream operator. |
| inline std::ostream& operator<<(std::ostream& os, Time t) { |
| return os << FormatTime(t); |
| } |
| |
| // Support for StrFormat(), StrCat() etc. |
| template <typename Sink> |
| void AbslStringify(Sink& sink, Time t) { |
| sink.Append(FormatTime(t)); |
| } |
| |
| // ParseTime() |
| // |
| // Parses an input string according to the provided format string and |
| // returns the corresponding `absl::Time`. Uses strftime()-like formatting |
| // options, with the same extensions as FormatTime(), but with the |
| // exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez |
| // and %E*z also accept the same inputs, which (along with %z) includes |
| // 'z' and 'Z' as synonyms for +00:00. %ET accepts either 'T' or 't'. |
| // |
| // %Y consumes as many numeric characters as it can, so the matching data |
| // should always be terminated with a non-numeric. %E4Y always consumes |
| // exactly four characters, including any sign. |
| // |
| // Unspecified fields are taken from the default date and time of ... |
| // |
| // "1970-01-01 00:00:00.0 +0000" |
| // |
| // For example, parsing a string of "15:45" (%H:%M) will return an absl::Time |
| // that represents "1970-01-01 15:45:00.0 +0000". |
| // |
| // Note that since ParseTime() returns time instants, it makes the most sense |
| // to parse fully-specified date/time strings that include a UTC offset (%z, |
| // %Ez, or %E*z). |
| // |
| // Note also that `absl::ParseTime()` only heeds the fields year, month, day, |
| // hour, minute, (fractional) second, and UTC offset. Other fields, like |
| // weekday (%a or %A), while parsed for syntactic validity, are ignored |
| // in the conversion. |
| // |
| // Date and time fields that are out-of-range will be treated as errors |
| // rather than normalizing them like `absl::CivilSecond` does. For example, |
| // it is an error to parse the date "Oct 32, 2013" because 32 is out of range. |
| // |
| // A leap second of ":60" is normalized to ":00" of the following minute |
| // with fractional seconds discarded. The following table shows how the |
| // given seconds and subseconds will be parsed: |
| // |
| // "59.x" -> 59.x // exact |
| // "60.x" -> 00.0 // normalized |
| // "00.x" -> 00.x // exact |
| // |
| // Errors are indicated by returning false and assigning an error message |
| // to the "err" out param if it is non-null. |
| // |
| // Note: If the input string is exactly "infinite-future", the returned |
| // `absl::Time` will be `absl::InfiniteFuture()` and `true` will be returned. |
| // If the input string is "infinite-past", the returned `absl::Time` will be |
| // `absl::InfinitePast()` and `true` will be returned. |
| // |
| bool ParseTime(absl::string_view format, absl::string_view input, Time* time, |
| std::string* err); |
| |
| // Like ParseTime() above, but if the format string does not contain a UTC |
| // offset specification (%z/%Ez/%E*z) then the input is interpreted in the |
| // given TimeZone. This means that the input, by itself, does not identify a |
| // unique instant. Being time-zone dependent, it also admits the possibility |
| // of ambiguity or non-existence, in which case the "pre" time (as defined |
| // by TimeZone::TimeInfo) is returned. For these reasons we recommend that |
| // all date/time strings include a UTC offset so they're context independent. |
| bool ParseTime(absl::string_view format, absl::string_view input, TimeZone tz, |
| Time* time, std::string* err); |
| |
| // ============================================================================ |
| // Implementation Details Follow |
| // ============================================================================ |
| |
| namespace time_internal { |
| |
| // Creates a Duration with a given representation. |
| // REQUIRES: hi,lo is a valid representation of a Duration as specified |
| // in time/duration.cc. |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration MakeDuration(int64_t hi, |
| uint32_t lo = 0) { |
| return Duration(hi, lo); |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration MakeDuration(int64_t hi, |
| int64_t lo) { |
| return MakeDuration(hi, static_cast<uint32_t>(lo)); |
| } |
| |
| // Make a Duration value from a floating-point number, as long as that number |
| // is in the range [ 0 .. numeric_limits<int64_t>::max ), that is, as long as |
| // it's positive and can be converted to int64_t without risk of UB. |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration MakePosDoubleDuration(double n) { |
| const int64_t int_secs = static_cast<int64_t>(n); |
| const uint32_t ticks = static_cast<uint32_t>( |
| std::round((n - static_cast<double>(int_secs)) * kTicksPerSecond)); |
| return ticks < kTicksPerSecond |
| ? MakeDuration(int_secs, ticks) |
| : MakeDuration(int_secs + 1, ticks - kTicksPerSecond); |
| } |
| |
| // Creates a normalized Duration from an almost-normalized (sec,ticks) |
| // pair. sec may be positive or negative. ticks must be in the range |
| // -kTicksPerSecond < *ticks < kTicksPerSecond. If ticks is negative it |
| // will be normalized to a positive value in the resulting Duration. |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration MakeNormalizedDuration( |
| int64_t sec, int64_t ticks) { |
| return (ticks < 0) ? MakeDuration(sec - 1, ticks + kTicksPerSecond) |
| : MakeDuration(sec, ticks); |
| } |
| |
| // Provide access to the Duration representation. |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t GetRepHi(Duration d) { |
| return d.rep_hi_.Get(); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr uint32_t GetRepLo(Duration d) { |
| return d.rep_lo_; |
| } |
| |
| // Returns true iff d is positive or negative infinity. |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool IsInfiniteDuration(Duration d) { |
| return GetRepLo(d) == ~uint32_t{0}; |
| } |
| |
| // Returns an infinite Duration with the opposite sign. |
| // REQUIRES: IsInfiniteDuration(d) |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration OppositeInfinity(Duration d) { |
| return GetRepHi(d) < 0 |
| ? MakeDuration((std::numeric_limits<int64_t>::max)(), ~uint32_t{0}) |
| : MakeDuration((std::numeric_limits<int64_t>::min)(), |
| ~uint32_t{0}); |
| } |
| |
| // Returns (-n)-1 (equivalently -(n+1)) without avoidable overflow. |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t NegateAndSubtractOne( |
| int64_t n) { |
| // Note: Good compilers will optimize this expression to ~n when using |
| // a two's-complement representation (which is required for int64_t). |
| return (n < 0) ? -(n + 1) : (-n) - 1; |
| } |
| |
| // Map between a Time and a Duration since the Unix epoch. Note that these |
| // functions depend on the above mentioned choice of the Unix epoch for the |
| // Time representation (and both need to be Time friends). Without this |
| // knowledge, we would need to add-in/subtract-out UnixEpoch() respectively. |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixDuration(Duration d) { |
| return Time(d); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration ToUnixDuration(Time t) { |
| return t.rep_; |
| } |
| |
| template <std::intmax_t N> |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v, |
| std::ratio<1, N>) { |
| static_assert(0 < N && N <= 1000 * 1000 * 1000, "Unsupported ratio"); |
| // Subsecond ratios cannot overflow. |
| return MakeNormalizedDuration( |
| v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v, |
| std::ratio<60>) { |
| return (v <= (std::numeric_limits<int64_t>::max)() / 60 && |
| v >= (std::numeric_limits<int64_t>::min)() / 60) |
| ? MakeDuration(v * 60) |
| : v > 0 ? InfiniteDuration() : -InfiniteDuration(); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v, |
| std::ratio<3600>) { |
| return (v <= (std::numeric_limits<int64_t>::max)() / 3600 && |
| v >= (std::numeric_limits<int64_t>::min)() / 3600) |
| ? MakeDuration(v * 3600) |
| : v > 0 ? InfiniteDuration() : -InfiniteDuration(); |
| } |
| |
| // IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is |
| // valid. That is, if a T can be assigned to an int64_t without narrowing. |
| template <typename T> |
| constexpr auto IsValidRep64(int) -> decltype(int64_t{std::declval<T>()} == 0) { |
| return true; |
| } |
| template <typename T> |
| constexpr auto IsValidRep64(char) -> bool { |
| return false; |
| } |
| |
| // Converts a std::chrono::duration to an absl::Duration. |
| template <typename Rep, typename Period> |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::duration<Rep, Period>& d) { |
| static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid"); |
| return FromInt64(int64_t{d.count()}, Period{}); |
| } |
| |
| template <typename Ratio> |
| ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64(Duration d, Ratio) { |
| // Note: This may be used on MSVC, which may have a system_clock period of |
| // std::ratio<1, 10 * 1000 * 1000> |
| return ToInt64Seconds(d * Ratio::den / Ratio::num); |
| } |
| // Fastpath implementations for the 6 common duration units. |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d, std::nano) { |
| return ToInt64Nanoseconds(d); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d, std::micro) { |
| return ToInt64Microseconds(d); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d, std::milli) { |
| return ToInt64Milliseconds(d); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d, |
| std::ratio<1>) { |
| return ToInt64Seconds(d); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d, |
| std::ratio<60>) { |
| return ToInt64Minutes(d); |
| } |
| ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d, |
| std::ratio<3600>) { |
| return ToInt64Hours(d); |
| } |
| |
| // Converts an absl::Duration to a chrono duration of type T. |
| template <typename T> |
| ABSL_ATTRIBUTE_CONST_FUNCTION T ToChronoDuration(Duration d) { |
| using Rep = typename T::rep; |
| using Period = typename T::period; |
| static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid"); |
| if (time_internal::IsInfiniteDuration(d)) |
| return d < ZeroDuration() ? (T::min)() : (T::max)(); |
| const auto v = ToInt64(d, Period{}); |
| if (v > (std::numeric_limits<Rep>::max)()) return (T::max)(); |
| if (v < (std::numeric_limits<Rep>::min)()) return (T::min)(); |
| return T{v}; |
| } |
| |
| } // namespace time_internal |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<(Duration lhs, |
| Duration rhs) { |
| return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs) |
| ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs) |
| : time_internal::GetRepHi(lhs) == (std::numeric_limits<int64_t>::min)() |
| ? time_internal::GetRepLo(lhs) + 1 < |
| time_internal::GetRepLo(rhs) + 1 |
| : time_internal::GetRepLo(lhs) < time_internal::GetRepLo(rhs); |
| } |
| |
| #ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr std::strong_ordering operator<=>( |
| Duration lhs, Duration rhs) { |
| const int64_t lhs_hi = time_internal::GetRepHi(lhs); |
| const int64_t rhs_hi = time_internal::GetRepHi(rhs); |
| if (auto c = lhs_hi <=> rhs_hi; c != std::strong_ordering::equal) { |
| return c; |
| } |
| const uint32_t lhs_lo = time_internal::GetRepLo(lhs); |
| const uint32_t rhs_lo = time_internal::GetRepLo(rhs); |
| return (lhs_hi == (std::numeric_limits<int64_t>::min)()) |
| ? (lhs_lo + 1) <=> (rhs_lo + 1) |
| : lhs_lo <=> rhs_lo; |
| } |
| |
| #endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator==(Duration lhs, |
| Duration rhs) { |
| return time_internal::GetRepHi(lhs) == time_internal::GetRepHi(rhs) && |
| time_internal::GetRepLo(lhs) == time_internal::GetRepLo(rhs); |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration operator-(Duration d) { |
| // This is a little interesting because of the special cases. |
| // |
| // If rep_lo_ is zero, we have it easy; it's safe to negate rep_hi_, we're |
| // dealing with an integral number of seconds, and the only special case is |
| // the maximum negative finite duration, which can't be negated. |
| // |
| // Infinities stay infinite, and just change direction. |
| // |
| // Finally we're in the case where rep_lo_ is non-zero, and we can borrow |
| // a second's worth of ticks and avoid overflow (as negating int64_t-min + 1 |
| // is safe). |
| return time_internal::GetRepLo(d) == 0 |
| ? time_internal::GetRepHi(d) == |
| (std::numeric_limits<int64_t>::min)() |
| ? InfiniteDuration() |
| : time_internal::MakeDuration(-time_internal::GetRepHi(d)) |
| : time_internal::IsInfiniteDuration(d) |
| ? time_internal::OppositeInfinity(d) |
| : time_internal::MakeDuration( |
| time_internal::NegateAndSubtractOne( |
| time_internal::GetRepHi(d)), |
| time_internal::kTicksPerSecond - |
| time_internal::GetRepLo(d)); |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration InfiniteDuration() { |
| return time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(), |
| ~uint32_t{0}); |
| } |
| |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::nanoseconds& d) { |
| return time_internal::FromChrono(d); |
| } |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::microseconds& d) { |
| return time_internal::FromChrono(d); |
| } |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::milliseconds& d) { |
| return time_internal::FromChrono(d); |
| } |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::seconds& d) { |
| return time_internal::FromChrono(d); |
| } |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::minutes& d) { |
| return time_internal::FromChrono(d); |
| } |
| ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono( |
| const std::chrono::hours& d) { |
| return time_internal::FromChrono(d); |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixNanos(int64_t ns) { |
| return time_internal::FromUnixDuration(Nanoseconds(ns)); |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixMicros(int64_t us) { |
| return time_internal::FromUnixDuration(Microseconds(us)); |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixMillis(int64_t ms) { |
| return time_internal::FromUnixDuration(Milliseconds(ms)); |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixSeconds(int64_t s) { |
| return time_internal::FromUnixDuration(Seconds(s)); |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromTimeT(time_t t) { |
| return time_internal::FromUnixDuration(Seconds(t)); |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Nanoseconds(Duration d) { |
| if (time_internal::GetRepHi(d) >= 0 && |
| time_internal::GetRepHi(d) >> 33 == 0) { |
| return (time_internal::GetRepHi(d) * 1000 * 1000 * 1000) + |
| (time_internal::GetRepLo(d) / time_internal::kTicksPerNanosecond); |
| } else { |
| return d / Nanoseconds(1); |
| } |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Microseconds( |
| Duration d) { |
| if (time_internal::GetRepHi(d) >= 0 && |
| time_internal::GetRepHi(d) >> 43 == 0) { |
| return (time_internal::GetRepHi(d) * 1000 * 1000) + |
| (time_internal::GetRepLo(d) / |
| (time_internal::kTicksPerNanosecond * 1000)); |
| } else { |
| return d / Microseconds(1); |
| } |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Milliseconds( |
| Duration d) { |
| if (time_internal::GetRepHi(d) >= 0 && |
| time_internal::GetRepHi(d) >> 53 == 0) { |
| return (time_internal::GetRepHi(d) * 1000) + |
| (time_internal::GetRepLo(d) / |
| (time_internal::kTicksPerNanosecond * 1000 * 1000)); |
| } else { |
| return d / Milliseconds(1); |
| } |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Seconds(Duration d) { |
| int64_t hi = time_internal::GetRepHi(d); |
| if (time_internal::IsInfiniteDuration(d)) return hi; |
| if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi; |
| return hi; |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Minutes(Duration d) { |
| int64_t hi = time_internal::GetRepHi(d); |
| if (time_internal::IsInfiniteDuration(d)) return hi; |
| if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi; |
| return hi / 60; |
| } |
| |
| ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Hours(Duration d) { |
| int64_t hi = time_internal::GetRepHi(d); |
| if (time_internal::IsInfiniteDuration(d)) return hi; |
| if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi; |
| return hi / (60 * 60); |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_TIME_TIME_H_ |
| *· |
| |
| tsoong/.intermediates/external/abseil-cpp/absl_log_internal_config_hdrs/gen/my_include_dir/absl/log/internal/config.h¾ // Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/internal/config.h |
| // ----------------------------------------------------------------------------- |
| // |
| |
| #ifndef ABSL_LOG_INTERNAL_CONFIG_H_ |
| #define ABSL_LOG_INTERNAL_CONFIG_H_ |
| |
| #include "absl/base/config.h" |
| |
| #ifdef _WIN32 |
| #include <cstdint> |
| #else |
| #include <sys/types.h> |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace log_internal { |
| |
| #ifdef _WIN32 |
| using Tid = uint32_t; |
| #else |
| using Tid = pid_t; |
| #endif |
| |
| } // namespace log_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_LOG_INTERNAL_CONFIG_H_ |
| * |
| hsoong/.intermediates/external/abseil-cpp/absl_types_variant_hdrs/gen/my_include_dir/absl/types/variant.hÀ// 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. |
| // |
| // ----------------------------------------------------------------------------- |
| // variant.h |
| // ----------------------------------------------------------------------------- |
| // |
| // Historical note: Abseil once provided an implementation of `absl::variant` |
| // as a polyfill for `std::variant` prior to C++17. Now that C++17 is required, |
| // `absl::variant` is an alias for `std::variant`. |
| |
| #ifndef ABSL_TYPES_VARIANT_H_ |
| #define ABSL_TYPES_VARIANT_H_ |
| |
| #include <variant> |
| |
| #include "absl/base/config.h" |
| #include "absl/utility/utility.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| using std::bad_variant_access; |
| using std::get; |
| using std::get_if; |
| using std::holds_alternative; |
| using std::monostate; |
| using std::variant; |
| using std::variant_alternative; |
| using std::variant_alternative_t; |
| using std::variant_npos; |
| using std::variant_size; |
| using std::variant_size_v; |
| using std::visit; |
| |
| namespace variant_internal { |
| // Helper visitor for converting a variant<Ts...>` into another type (mostly |
| // variant) that can be constructed from any type. |
| template <typename To> |
| struct ConversionVisitor { |
| template <typename T> |
| To operator()(T&& v) const { |
| return To(std::forward<T>(v)); |
| } |
| }; |
| } // namespace variant_internal |
| |
| // ConvertVariantTo() |
| // |
| // Helper functions to convert an `absl::variant` to a variant of another set of |
| // types, provided that the alternative type of the new variant type can be |
| // converted from any type in the source variant. |
| // |
| // Example: |
| // |
| // absl::variant<name1, name2, float> InternalReq(const Req&); |
| // |
| // // name1 and name2 are convertible to name |
| // absl::variant<name, float> ExternalReq(const Req& req) { |
| // return absl::ConvertVariantTo<absl::variant<name, float>>( |
| // InternalReq(req)); |
| // } |
| template <typename To, typename Variant> |
| To ConvertVariantTo(Variant&& variant) { |
| return absl::visit(variant_internal::ConversionVisitor<To>{}, |
| std::forward<Variant>(variant)); |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_TYPES_VARIANT_H_ |
| *×P |
| soong/.intermediates/external/abseil-cpp/absl_container_compressed_tuple_hdrs/gen/my_include_dir/absl/container/internal/compressed_tuple.hÆO// 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. |
| // |
| // Helper class to perform the Empty Base Optimization. |
| // Ts can contain classes and non-classes, empty or not. For the ones that |
| // are empty classes, we perform the optimization. If all types in Ts are empty |
| // classes, then CompressedTuple<Ts...> is itself an empty class. |
| // |
| // To access the members, use member get<N>() function. |
| // |
| // Eg: |
| // absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2, |
| // t3); |
| // assert(value.get<0>() == 7); |
| // T1& t1 = value.get<1>(); |
| // const T2& t2 = value.get<2>(); |
| // ... |
| // |
| // https://en.cppreference.com/w/cpp/language/ebo |
| |
| #ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_ |
| #define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_ |
| |
| #include <initializer_list> |
| #include <tuple> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/utility/utility.h" |
| |
| #if defined(_MSC_VER) && !defined(__NVCC__) |
| // We need to mark these classes with this declspec to ensure that |
| // CompressedTuple happens. |
| #define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases) |
| #else |
| #define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace container_internal { |
| |
| template <typename... Ts> |
| class CompressedTuple; |
| |
| namespace internal_compressed_tuple { |
| |
| template <typename D, size_t I> |
| struct Elem; |
| template <typename... B, size_t I> |
| struct Elem<CompressedTuple<B...>, I> |
| : std::tuple_element<I, std::tuple<B...>> {}; |
| template <typename D, size_t I> |
| using ElemT = typename Elem<D, I>::type; |
| |
| // We can't use EBCO on other CompressedTuples because that would mean that we |
| // derive from multiple Storage<> instantiations with the same I parameter, |
| // and potentially from multiple identical Storage<> instantiations. So anytime |
| // we use type inheritance rather than encapsulation, we mark |
| // CompressedTupleImpl, to make this easy to detect. |
| struct uses_inheritance {}; |
| |
| template <typename T> |
| constexpr bool ShouldUseBase() { |
| return std::is_class<T>::value && std::is_empty<T>::value && |
| !std::is_final<T>::value && |
| !std::is_base_of<uses_inheritance, T>::value; |
| } |
| |
| // The storage class provides two specializations: |
| // - For empty classes, it stores T as a base class. |
| // - For everything else, it stores T as a member. |
| template <typename T, size_t I, bool UseBase = ShouldUseBase<T>()> |
| struct Storage { |
| T value; |
| constexpr Storage() = default; |
| template <typename V> |
| explicit constexpr Storage(absl::in_place_t, V&& v) |
| : value(std::forward<V>(v)) {} |
| constexpr const T& get() const& { return value; } |
| constexpr T& get() & { return value; } |
| constexpr const T&& get() const&& { return std::move(*this).value; } |
| constexpr T&& get() && { return std::move(*this).value; } |
| }; |
| |
| template <typename T, size_t I> |
| struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<T, I, true> : T { |
| constexpr Storage() = default; |
| |
| template <typename V> |
| explicit constexpr Storage(absl::in_place_t, V&& v) : T(std::forward<V>(v)) {} |
| |
| constexpr const T& get() const& { return *this; } |
| constexpr T& get() & { return *this; } |
| constexpr const T&& get() const&& { return std::move(*this); } |
| constexpr T&& get() && { return std::move(*this); } |
| }; |
| |
| template <typename D, typename I, bool ShouldAnyUseBase> |
| struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl; |
| |
| template <typename... Ts, size_t... I, bool ShouldAnyUseBase> |
| struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl< |
| CompressedTuple<Ts...>, absl::index_sequence<I...>, ShouldAnyUseBase> |
| // We use the dummy identity function through std::integral_constant to |
| // convince MSVC of accepting and expanding I in that context. Without it |
| // you would get: |
| // error C3548: 'I': parameter pack cannot be used in this context |
| : uses_inheritance, |
| Storage<Ts, std::integral_constant<size_t, I>::value>... { |
| constexpr CompressedTupleImpl() = default; |
| template <typename... Vs> |
| explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args) |
| : Storage<Ts, I>(absl::in_place, std::forward<Vs>(args))... {} |
| friend CompressedTuple<Ts...>; |
| }; |
| |
| template <typename... Ts, size_t... I> |
| struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl< |
| CompressedTuple<Ts...>, absl::index_sequence<I...>, false> |
| // We use the dummy identity function as above... |
| : Storage<Ts, std::integral_constant<size_t, I>::value, false>... { |
| constexpr CompressedTupleImpl() = default; |
| template <typename... Vs> |
| explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args) |
| : Storage<Ts, I, false>(absl::in_place, std::forward<Vs>(args))... {} |
| friend CompressedTuple<Ts...>; |
| }; |
| |
| std::false_type Or(std::initializer_list<std::false_type>); |
| std::true_type Or(std::initializer_list<bool>); |
| |
| // MSVC requires this to be done separately rather than within the declaration |
| // of CompressedTuple below. |
| template <typename... Ts> |
| constexpr bool ShouldAnyUseBase() { |
| return decltype( |
| Or({std::integral_constant<bool, ShouldUseBase<Ts>()>()...})){}; |
| } |
| |
| template <typename T, typename V> |
| using TupleElementMoveConstructible = |
| typename std::conditional<std::is_reference<T>::value, |
| std::is_convertible<V, T>, |
| std::is_constructible<T, V&&>>::type; |
| |
| template <bool SizeMatches, class T, class... Vs> |
| struct TupleMoveConstructible : std::false_type {}; |
| |
| template <class... Ts, class... Vs> |
| struct TupleMoveConstructible<true, CompressedTuple<Ts...>, Vs...> |
| : std::integral_constant< |
| bool, absl::conjunction< |
| TupleElementMoveConstructible<Ts, Vs&&>...>::value> {}; |
| |
| template <typename T> |
| struct compressed_tuple_size; |
| |
| template <typename... Es> |
| struct compressed_tuple_size<CompressedTuple<Es...>> |
| : public std::integral_constant<std::size_t, sizeof...(Es)> {}; |
| |
| template <class T, class... Vs> |
| struct TupleItemsMoveConstructible |
| : std::integral_constant< |
| bool, TupleMoveConstructible<compressed_tuple_size<T>::value == |
| sizeof...(Vs), |
| T, Vs...>::value> {}; |
| |
| } // namespace internal_compressed_tuple |
| |
| // Helper class to perform the Empty Base Class Optimization. |
| // Ts can contain classes and non-classes, empty or not. For the ones that |
| // are empty classes, we perform the CompressedTuple. If all types in Ts are |
| // empty classes, then CompressedTuple<Ts...> is itself an empty class. (This |
| // does not apply when one or more of those empty classes is itself an empty |
| // CompressedTuple.) |
| // |
| // To access the members, use member .get<N>() function. |
| // |
| // Eg: |
| // absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2, |
| // t3); |
| // assert(value.get<0>() == 7); |
| // T1& t1 = value.get<1>(); |
| // const T2& t2 = value.get<2>(); |
| // ... |
| // |
| // https://en.cppreference.com/w/cpp/language/ebo |
| template <typename... Ts> |
| class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple |
| : private internal_compressed_tuple::CompressedTupleImpl< |
| CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>, |
| internal_compressed_tuple::ShouldAnyUseBase<Ts...>()> { |
| private: |
| template <int I> |
| using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>; |
| |
| template <int I> |
| using StorageT = internal_compressed_tuple::Storage<ElemT<I>, I>; |
| |
| public: |
| // There seems to be a bug in MSVC dealing in which using '=default' here will |
| // cause the compiler to ignore the body of other constructors. The work- |
| // around is to explicitly implement the default constructor. |
| #if defined(_MSC_VER) |
| constexpr CompressedTuple() : CompressedTuple::CompressedTupleImpl() {} |
| #else |
| constexpr CompressedTuple() = default; |
| #endif |
| explicit constexpr CompressedTuple(const Ts&... base) |
| : CompressedTuple::CompressedTupleImpl(absl::in_place, base...) {} |
| |
| template <typename First, typename... Vs, |
| absl::enable_if_t< |
| absl::conjunction< |
| // Ensure we are not hiding default copy/move constructors. |
| absl::negation<std::is_same<void(CompressedTuple), |
| void(absl::decay_t<First>)>>, |
| internal_compressed_tuple::TupleItemsMoveConstructible< |
| CompressedTuple<Ts...>, First, Vs...>>::value, |
| bool> = true> |
| explicit constexpr CompressedTuple(First&& first, Vs&&... base) |
| : CompressedTuple::CompressedTupleImpl(absl::in_place, |
| std::forward<First>(first), |
| std::forward<Vs>(base)...) {} |
| |
| template <int I> |
| constexpr ElemT<I>& get() & { |
| return StorageT<I>::get(); |
| } |
| |
| template <int I> |
| constexpr const ElemT<I>& get() const& { |
| return StorageT<I>::get(); |
| } |
| |
| template <int I> |
| constexpr ElemT<I>&& get() && { |
| return std::move(*this).StorageT<I>::get(); |
| } |
| |
| template <int I> |
| constexpr const ElemT<I>&& get() const&& { |
| return std::move(*this).StorageT<I>::get(); |
| } |
| }; |
| |
| // Explicit specialization for a zero-element tuple |
| // (needed to avoid ambiguous overloads for the default constructor). |
| template <> |
| class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {}; |
| |
| } // namespace container_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC |
| |
| #endif // ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_ |
| *¡ |
| soong/.intermediates/external/abseil-cpp/absl_hash_weakly_mixed_integer_hdrs/gen/my_include_dir/absl/hash/internal/weakly_mixed_integer.h |
| // Copyright 2025 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_HASH_INTERNAL_WEAKLY_MIXED_INTEGER_H_ |
| #define ABSL_HASH_INTERNAL_WEAKLY_MIXED_INTEGER_H_ |
| |
| #include <cstddef> |
| |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace hash_internal { |
| |
| // Contains an integer that will be mixed into a hash state more weakly than |
| // regular integers. It is useful for cases in which an integer is a part of a |
| // larger object and needs to be mixed as a supplement. E.g., absl::string_view |
| // and absl::Span are mixing their size wrapped with WeaklyMixedInteger. |
| struct WeaklyMixedInteger { |
| size_t value; |
| }; |
| |
| } // namespace hash_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_HASH_INTERNAL_WEAKLY_MIXED_INTEGER_H_ |
| *Êì |
| bsoong/.intermediates/external/abseil-cpp/absl_types_span_hdrs/gen/my_include_dir/absl/types/span.hâë// |
| // 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. |
| // |
| // ----------------------------------------------------------------------------- |
| // span.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines a `Span<T>` type for holding a reference to existing |
| // array data. The `Span` object, much like the `absl::string_view` object, |
| // does not own such data itself, and the data being referenced by the span must |
| // outlive the span itself. Unlike `view` type references, a span can hold a |
| // reference to mutable data (and can mutate it for underlying types of |
| // non-const T.) A span provides a lightweight way to pass a reference to such |
| // data. |
| // |
| // Additionally, this header file defines `MakeSpan()` and `MakeConstSpan()` |
| // factory functions, for clearly creating spans of type `Span<T>` or read-only |
| // `Span<const T>` when such types may be difficult to identify due to issues |
| // with implicit conversion. |
| // |
| // The C++20 draft standard includes a `std::span` type. As of June 2020, the |
| // differences between `absl::Span` and `std::span` are: |
| // * `absl::Span` has `operator==` (which is likely a design bug, |
| // per https://abseil.io/blog/20180531-regular-types) |
| // * `absl::Span` has the factory functions `MakeSpan()` and |
| // `MakeConstSpan()` |
| // * bounds-checked access to `absl::Span` is accomplished with `at()` |
| // * `absl::Span` has compiler-provided move and copy constructors and |
| // assignment. This is due to them being specified as `constexpr`, but that |
| // implies const in C++11. |
| // * A read-only `absl::Span<const T>` can be implicitly constructed from an |
| // initializer list. |
| // * `absl::Span` has no `bytes()`, `size_bytes()`, `as_bytes()`, or |
| // `as_writable_bytes()` methods |
| // * `absl::Span` has no static extent template parameter, nor constructors |
| // which exist only because of the static extent parameter. |
| // * `absl::Span` has an explicit mutable-reference constructor |
| // |
| // For more information, see the class comments below. |
| #ifndef ABSL_TYPES_SPAN_H_ |
| #define ABSL_TYPES_SPAN_H_ |
| |
| #include <algorithm> |
| #include <cassert> |
| #include <cstddef> |
| #include <initializer_list> |
| #include <iterator> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/throw_delegate.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/optimization.h" |
| #include "absl/base/port.h" // TODO(strel): remove this include |
| #include "absl/hash/internal/weakly_mixed_integer.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/types/internal/span.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| template <typename T> |
| class Span; |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| // Android local modification: some security tests use "#define private public" |
| // to access private implementation details. libc++'s <ranges> is currently not |
| // compatible with that. |
| #if !defined(private) |
| |
| // If std::ranges is available, mark Span as satisfying the `view` and |
| // `borrowed_range` concepts, just like std::span. |
| #if !defined(__has_include) |
| #define __has_include(header) 0 |
| #endif |
| #if __has_include(<version>) |
| #include <version> // NOLINT(misc-include-cleaner) |
| #endif |
| #if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L |
| #include <ranges> // NOLINT(build/c++20) |
| template <typename T> |
| // NOLINTNEXTLINE(build/c++20) |
| inline constexpr bool std::ranges::enable_view<absl::Span<T>> = true; |
| template <typename T> |
| // NOLINTNEXTLINE(build/c++20) |
| inline constexpr bool std::ranges::enable_borrowed_range<absl::Span<T>> = true; |
| #endif |
| |
| #endif // !defined(private) |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| //------------------------------------------------------------------------------ |
| // Span |
| //------------------------------------------------------------------------------ |
| // |
| // A `Span` is an "array reference" type for holding a reference of contiguous |
| // array data; the `Span` object does not and cannot own such data itself. A |
| // span provides an easy way to provide overloads for anything operating on |
| // contiguous sequences without needing to manage pointers and array lengths |
| // manually. |
| |
| // A span is conceptually a pointer (ptr) and a length (size) into an already |
| // existing array of contiguous memory; the array it represents references the |
| // elements "ptr[0] .. ptr[size-1]". Passing a properly-constructed `Span` |
| // instead of raw pointers avoids many issues related to index out of bounds |
| // errors. |
| // |
| // Spans may also be constructed from containers holding contiguous sequences. |
| // Such containers must supply `data()` and `size() const` methods (e.g |
| // `std::vector<T>`, `absl::InlinedVector<T, N>`). All implicit conversions to |
| // `absl::Span` from such containers will create spans of type `const T`; |
| // spans which can mutate their values (of type `T`) must use explicit |
| // constructors. |
| // |
| // A `Span<T>` is somewhat analogous to an `absl::string_view`, but for an array |
| // of elements of type `T`, and unlike an `absl::string_view`, a span can hold a |
| // reference to mutable data. A user of `Span` must ensure that the data being |
| // pointed to outlives the `Span` itself. |
| // |
| // You can construct a `Span<T>` in several ways: |
| // |
| // * Explicitly from a reference to a container type |
| // * Explicitly from a pointer and size |
| // * Implicitly from a container type (but only for spans of type `const T`) |
| // * Using the `MakeSpan()` or `MakeConstSpan()` factory functions. |
| // |
| // Examples: |
| // |
| // // Construct a Span explicitly from a container: |
| // std::vector<int> v = {1, 2, 3, 4, 5}; |
| // auto span = absl::Span<const int>(v); |
| // |
| // // Construct a Span explicitly from a C-style array: |
| // int a[5] = {1, 2, 3, 4, 5}; |
| // auto span = absl::Span<const int>(a); |
| // |
| // // Construct a Span implicitly from a container |
| // void MyRoutine(absl::Span<const int> a) { |
| // ... |
| // } |
| // std::vector v = {1,2,3,4,5}; |
| // MyRoutine(v) // convert to Span<const T> |
| // |
| // Note that `Span` objects, in addition to requiring that the memory they |
| // point to remains alive, must also ensure that such memory does not get |
| // reallocated. Therefore, to avoid undefined behavior, containers with |
| // associated spans should not invoke operations that may reallocate memory |
| // (such as resizing) or invalidate iterators into the container. |
| // |
| // One common use for a `Span` is when passing arguments to a routine that can |
| // accept a variety of array types (e.g. a `std::vector`, `absl::InlinedVector`, |
| // a C-style array, etc.). Instead of creating overloads for each case, you |
| // can simply specify a `Span` as the argument to such a routine. |
| // |
| // Example: |
| // |
| // void MyRoutine(absl::Span<const int> a) { |
| // ... |
| // } |
| // |
| // std::vector v = {1,2,3,4,5}; |
| // MyRoutine(v); |
| // |
| // absl::InlinedVector<int, 4> my_inline_vector; |
| // MyRoutine(my_inline_vector); |
| // |
| // // Explicit constructor from pointer,size |
| // int* my_array = new int[10]; |
| // MyRoutine(absl::Span<const int>(my_array, 10)); |
| template <typename T> |
| class ABSL_ATTRIBUTE_VIEW Span { |
| private: |
| // Used to determine whether a Span can be constructed from a container of |
| // type C. |
| template <typename C> |
| using EnableIfConvertibleFrom = |
| typename std::enable_if<span_internal::HasData<T, C>::value && |
| span_internal::HasSize<C>::value>::type; |
| |
| // Used to SFINAE-enable a function when the slice elements are const. |
| template <typename U> |
| using EnableIfValueIsConst = |
| typename std::enable_if<std::is_const<T>::value, U>::type; |
| |
| // Used to SFINAE-enable a function when the slice elements are mutable. |
| template <typename U> |
| using EnableIfValueIsMutable = |
| typename std::enable_if<!std::is_const<T>::value, U>::type; |
| |
| public: |
| using element_type = T; |
| using value_type = absl::remove_cv_t<T>; |
| // TODO(b/316099902) - pointer should be absl_nullable, but this makes it hard |
| // to recognize foreach loops as safe. absl_nullability_unknown is currently |
| // used to suppress -Wnullability-completeness warnings. |
| using pointer = T* absl_nullability_unknown; |
| using const_pointer = const T* absl_nullability_unknown; |
| using reference = T&; |
| using const_reference = const T&; |
| using iterator = pointer; |
| using const_iterator = const_pointer; |
| using reverse_iterator = std::reverse_iterator<iterator>; |
| using const_reverse_iterator = std::reverse_iterator<const_iterator>; |
| using size_type = size_t; |
| using difference_type = ptrdiff_t; |
| using absl_internal_is_view = std::true_type; |
| |
| // NOLINTNEXTLINE |
| static const size_type npos = ~(size_type(0)); |
| |
| constexpr Span() noexcept : Span(nullptr, 0) {} |
| constexpr Span(pointer array ABSL_ATTRIBUTE_LIFETIME_BOUND, |
| size_type length) noexcept |
| : ptr_(array), len_(length) {} |
| |
| // Implicit conversion constructors |
| template <size_t N> |
| constexpr Span(T( // NOLINT(google-explicit-constructor) |
| &a ABSL_ATTRIBUTE_LIFETIME_BOUND)[N]) noexcept |
| : Span(a, N) {} |
| |
| // Explicit reference constructor for a mutable `Span<T>` type. Can be |
| // replaced with MakeSpan() to infer the type parameter. |
| template <typename V, typename = EnableIfConvertibleFrom<V>, |
| typename = EnableIfValueIsMutable<V>, |
| typename = span_internal::EnableIfNotIsView<V>> |
| explicit Span( |
| V& v |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept // NOLINT(runtime/references) |
| : Span(span_internal::GetData(v), v.size()) {} |
| |
| // Implicit reference constructor for a read-only `Span<const T>` type |
| template <typename V, typename = EnableIfConvertibleFrom<V>, |
| typename = EnableIfValueIsConst<V>, |
| typename = span_internal::EnableIfNotIsView<V>> |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| constexpr Span(const V& v ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept |
| : Span(span_internal::GetData(v), v.size()) {} |
| |
| // Overloads of the above two functions that are only enabled for view types. |
| // This is so we can drop the ABSL_ATTRIBUTE_LIFETIME_BOUND annotation. These |
| // overloads must be made unique by using a different template parameter list |
| // (hence the = 0 for the IsView enabler). |
| template <typename V, typename = EnableIfConvertibleFrom<V>, |
| typename = EnableIfValueIsMutable<V>, |
| span_internal::EnableIfIsView<V> = 0> |
| explicit Span(V& v) noexcept // NOLINT(runtime/references) |
| : Span(span_internal::GetData(v), v.size()) {} |
| template <typename V, typename = EnableIfConvertibleFrom<V>, |
| typename = EnableIfValueIsConst<V>, |
| span_internal::EnableIfIsView<V> = 0> |
| constexpr Span(const V& v) noexcept // NOLINT(google-explicit-constructor) |
| : Span(span_internal::GetData(v), v.size()) {} |
| |
| // Implicit constructor from an initializer list, making it possible to pass a |
| // brace-enclosed initializer list to a function expecting a `Span`. Such |
| // spans constructed from an initializer list must be of type `Span<const T>`. |
| // |
| // void Process(absl::Span<const int> x); |
| // Process({1, 2, 3}); |
| // |
| // Note that as always the array referenced by the span must outlive the span. |
| // Since an initializer list constructor acts as if it is fed a temporary |
| // array (cf. C++ standard [dcl.init.list]/5), it's safe to use this |
| // constructor only when the `std::initializer_list` itself outlives the span. |
| // In order to meet this requirement it's sufficient to ensure that neither |
| // the span nor a copy of it is used outside of the expression in which it's |
| // created: |
| // |
| // // Assume that this function uses the array directly, not retaining any |
| // // copy of the span or pointer to any of its elements. |
| // void Process(absl::Span<const int> ints); |
| // |
| // // Okay: the std::initializer_list<int> will reference a temporary array |
| // // that isn't destroyed until after the call to Process returns. |
| // Process({ 17, 19 }); |
| // |
| // // Not okay: the storage used by the std::initializer_list<int> is not |
| // // allowed to be referenced after the first line. |
| // absl::Span<const int> ints = { 17, 19 }; |
| // Process(ints); |
| // |
| // // Not okay for the same reason as above: even when the elements of the |
| // // initializer list expression are not temporaries the underlying array |
| // // is, so the initializer list must still outlive the span. |
| // const int foo = 17; |
| // absl::Span<const int> ints = { foo }; |
| // Process(ints); |
| // |
| template <typename LazyT = T, |
| typename = EnableIfValueIsConst<LazyT>> |
| Span(std::initializer_list<value_type> v |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept // NOLINT(runtime/explicit) |
| : Span(v.begin(), v.size()) {} |
| |
| // Accessors |
| |
| // Span::data() |
| // |
| // Returns a pointer to the span's underlying array of data (which is held |
| // outside the span). |
| constexpr pointer data() const noexcept { return ptr_; } |
| |
| // Span::size() |
| // |
| // Returns the size of this span. |
| constexpr size_type size() const noexcept { return len_; } |
| |
| // Span::length() |
| // |
| // Returns the length (size) of this span. |
| constexpr size_type length() const noexcept { return size(); } |
| |
| // Span::empty() |
| // |
| // Returns a boolean indicating whether or not this span is considered empty. |
| constexpr bool empty() const noexcept { return size() == 0; } |
| |
| // Span::operator[] |
| // |
| // Returns a reference to the i'th element of this span. |
| constexpr reference operator[](size_type i) const noexcept { |
| ABSL_HARDENING_ASSERT(i < size()); |
| return ptr_[i]; |
| } |
| |
| // Span::at() |
| // |
| // Returns a reference to the i'th element of this span. |
| constexpr reference at(size_type i) const { |
| return ABSL_PREDICT_TRUE(i < size()) // |
| ? *(data() + i) |
| : (base_internal::ThrowStdOutOfRange( |
| "Span::at failed bounds check"), |
| *(data() + i)); |
| } |
| |
| // Span::front() |
| // |
| // Returns a reference to the first element of this span. The span must not |
| // be empty. |
| constexpr reference front() const noexcept { |
| ABSL_HARDENING_ASSERT(size() > 0); |
| return *data(); |
| } |
| |
| // Span::back() |
| // |
| // Returns a reference to the last element of this span. The span must not |
| // be empty. |
| constexpr reference back() const noexcept { |
| ABSL_HARDENING_ASSERT(size() > 0); |
| return *(data() + size() - 1); |
| } |
| |
| // Span::begin() |
| // |
| // Returns an iterator pointing to the first element of this span, or `end()` |
| // if the span is empty. |
| constexpr iterator begin() const noexcept { return data(); } |
| |
| // Span::cbegin() |
| // |
| // Returns a const iterator pointing to the first element of this span, or |
| // `end()` if the span is empty. |
| constexpr const_iterator cbegin() const noexcept { return begin(); } |
| |
| // Span::end() |
| // |
| // Returns an iterator pointing just beyond the last element at the |
| // end of this span. This iterator acts as a placeholder; attempting to |
| // access it results in undefined behavior. |
| constexpr iterator end() const noexcept { return data() + size(); } |
| |
| // Span::cend() |
| // |
| // Returns a const iterator pointing just beyond the last element at the |
| // end of this span. This iterator acts as a placeholder; attempting to |
| // access it results in undefined behavior. |
| constexpr const_iterator cend() const noexcept { return end(); } |
| |
| // Span::rbegin() |
| // |
| // Returns a reverse iterator pointing to the last element at the end of this |
| // span, or `rend()` if the span is empty. |
| constexpr reverse_iterator rbegin() const noexcept { |
| return reverse_iterator(end()); |
| } |
| |
| // Span::crbegin() |
| // |
| // Returns a const reverse iterator pointing to the last element at the end of |
| // this span, or `crend()` if the span is empty. |
| constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } |
| |
| // Span::rend() |
| // |
| // Returns a reverse iterator pointing just before the first element |
| // at the beginning of this span. This pointer acts as a placeholder; |
| // attempting to access its element results in undefined behavior. |
| constexpr reverse_iterator rend() const noexcept { |
| return reverse_iterator(begin()); |
| } |
| |
| // Span::crend() |
| // |
| // Returns a reverse const iterator pointing just before the first element |
| // at the beginning of this span. This pointer acts as a placeholder; |
| // attempting to access its element results in undefined behavior. |
| constexpr const_reverse_iterator crend() const noexcept { return rend(); } |
| |
| // Span mutations |
| |
| // Span::remove_prefix() |
| // |
| // Removes the first `n` elements from the span. |
| void remove_prefix(size_type n) noexcept { |
| ABSL_HARDENING_ASSERT(size() >= n); |
| ptr_ += n; |
| len_ -= n; |
| } |
| |
| // Span::remove_suffix() |
| // |
| // Removes the last `n` elements from the span. |
| void remove_suffix(size_type n) noexcept { |
| ABSL_HARDENING_ASSERT(size() >= n); |
| len_ -= n; |
| } |
| |
| // Span::subspan() |
| // |
| // Returns a `Span` starting at element `pos` and of length `len`. Both `pos` |
| // and `len` are of type `size_type` and thus non-negative. Parameter `pos` |
| // must be <= size(). Any `len` value that points past the end of the span |
| // will be trimmed to at most size() - `pos`. A default `len` value of `npos` |
| // ensures the returned subspan continues until the end of the span. |
| // |
| // Examples: |
| // |
| // std::vector<int> vec = {10, 11, 12, 13}; |
| // absl::MakeSpan(vec).subspan(1, 2); // {11, 12} |
| // absl::MakeSpan(vec).subspan(2, 8); // {12, 13} |
| // absl::MakeSpan(vec).subspan(1); // {11, 12, 13} |
| // absl::MakeSpan(vec).subspan(4); // {} |
| // absl::MakeSpan(vec).subspan(5); // throws std::out_of_range |
| constexpr Span subspan(size_type pos = 0, size_type len = npos) const { |
| return (pos <= size()) |
| ? Span(data() + pos, (std::min)(size() - pos, len)) |
| : (base_internal::ThrowStdOutOfRange("pos > size()"), Span()); |
| } |
| |
| // Span::first() |
| // |
| // Returns a `Span` containing first `len` elements. Parameter `len` is of |
| // type `size_type` and thus non-negative. `len` value must be <= size(). |
| // |
| // Examples: |
| // |
| // std::vector<int> vec = {10, 11, 12, 13}; |
| // absl::MakeSpan(vec).first(1); // {10} |
| // absl::MakeSpan(vec).first(3); // {10, 11, 12} |
| // absl::MakeSpan(vec).first(5); // throws std::out_of_range |
| constexpr Span first(size_type len) const { |
| return (len <= size()) |
| ? Span(data(), len) |
| : (base_internal::ThrowStdOutOfRange("len > size()"), Span()); |
| } |
| |
| // Span::last() |
| // |
| // Returns a `Span` containing last `len` elements. Parameter `len` is of |
| // type `size_type` and thus non-negative. `len` value must be <= size(). |
| // |
| // Examples: |
| // |
| // std::vector<int> vec = {10, 11, 12, 13}; |
| // absl::MakeSpan(vec).last(1); // {13} |
| // absl::MakeSpan(vec).last(3); // {11, 12, 13} |
| // absl::MakeSpan(vec).last(5); // throws std::out_of_range |
| constexpr Span last(size_type len) const { |
| return (len <= size()) |
| ? Span(size() - len + data(), len) |
| : (base_internal::ThrowStdOutOfRange("len > size()"), Span()); |
| } |
| |
| // Support for absl::Hash. |
| template <typename H> |
| friend H AbslHashValue(H h, Span v) { |
| return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()), |
| hash_internal::WeaklyMixedInteger{v.size()}); |
| } |
| |
| private: |
| pointer ptr_; |
| size_type len_; |
| }; |
| |
| template <typename T> |
| const typename Span<T>::size_type Span<T>::npos; |
| |
| // Span relationals |
| |
| // Equality is compared element-by-element, while ordering is lexicographical. |
| // We provide three overloads for each operator to cover any combination on the |
| // left or right hand side of mutable Span<T>, read-only Span<const T>, and |
| // convertible-to-read-only Span<T>. |
| // TODO(zhangxy): Due to MSVC overload resolution bug with partial ordering |
| // template functions, 5 overloads per operator is needed as a workaround. We |
| // should update them to 3 overloads per operator using non-deduced context like |
| // string_view, i.e. |
| // - (Span<T>, Span<T>) |
| // - (Span<T>, non_deduced<Span<const T>>) |
| // - (non_deduced<Span<const T>>, Span<T>) |
| |
| // operator== |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<T> a, Span<T> b) { |
| return span_internal::EqualImpl<Span, const T>(a, b); |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<const T> a, |
| Span<T> b) { |
| return span_internal::EqualImpl<Span, const T>(a, b); |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<T> a, |
| Span<const T> b) { |
| return span_internal::EqualImpl<Span, const T>(a, b); |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(const U& a, Span<T> b) { |
| return span_internal::EqualImpl<Span, const T>(a, b); |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<T> a, const U& b) { |
| return span_internal::EqualImpl<Span, const T>(a, b); |
| } |
| |
| // operator!= |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<T> a, Span<T> b) { |
| return !(a == b); |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<const T> a, |
| Span<T> b) { |
| return !(a == b); |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<T> a, |
| Span<const T> b) { |
| return !(a == b); |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(const U& a, Span<T> b) { |
| return !(a == b); |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<T> a, const U& b) { |
| return !(a == b); |
| } |
| |
| // operator< |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<T> a, Span<T> b) { |
| return span_internal::LessThanImpl<Span, const T>(a, b); |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<const T> a, Span<T> b) { |
| return span_internal::LessThanImpl<Span, const T>(a, b); |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<T> a, Span<const T> b) { |
| return span_internal::LessThanImpl<Span, const T>(a, b); |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(const U& a, Span<T> b) { |
| return span_internal::LessThanImpl<Span, const T>(a, b); |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<T> a, const U& b) { |
| return span_internal::LessThanImpl<Span, const T>(a, b); |
| } |
| |
| // operator> |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<T> a, Span<T> b) { |
| return b < a; |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<const T> a, Span<T> b) { |
| return b < a; |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<T> a, Span<const T> b) { |
| return b < a; |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(const U& a, Span<T> b) { |
| return b < a; |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<T> a, const U& b) { |
| return b < a; |
| } |
| |
| // operator<= |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<T> a, Span<T> b) { |
| return !(b < a); |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<const T> a, |
| Span<T> b) { |
| return !(b < a); |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<T> a, |
| Span<const T> b) { |
| return !(b < a); |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(const U& a, Span<T> b) { |
| return !(b < a); |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<T> a, const U& b) { |
| return !(b < a); |
| } |
| |
| // operator>= |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<T> a, Span<T> b) { |
| return !(a < b); |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<const T> a, |
| Span<T> b) { |
| return !(a < b); |
| } |
| template <typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<T> a, |
| Span<const T> b) { |
| return !(a < b); |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(const U& a, Span<T> b) { |
| return !(a < b); |
| } |
| template < |
| typename T, typename U, |
| typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<T> a, const U& b) { |
| return !(a < b); |
| } |
| |
| // MakeSpan() |
| // |
| // Constructs a mutable `Span<T>`, deducing `T` automatically from either a |
| // container or pointer+size. |
| // |
| // Because a read-only `Span<const T>` is implicitly constructed from container |
| // types regardless of whether the container itself is a const container, |
| // constructing mutable spans of type `Span<T>` from containers requires |
| // explicit constructors. The container-accepting version of `MakeSpan()` |
| // deduces the type of `T` by the constness of the pointer received from the |
| // container's `data()` member. Similarly, the pointer-accepting version returns |
| // a `Span<const T>` if `T` is `const`, and a `Span<T>` otherwise. |
| // |
| // Examples: |
| // |
| // void MyRoutine(absl::Span<MyComplicatedType> a) { |
| // ... |
| // }; |
| // // my_vector is a container of non-const types |
| // std::vector<MyComplicatedType> my_vector; |
| // |
| // // Constructing a Span implicitly attempts to create a Span of type |
| // // `Span<const T>` |
| // MyRoutine(my_vector); // error, type mismatch |
| // |
| // // Explicitly constructing the Span is verbose |
| // MyRoutine(absl::Span<MyComplicatedType>(my_vector)); |
| // |
| // // Use MakeSpan() to make an absl::Span<T> |
| // MyRoutine(absl::MakeSpan(my_vector)); |
| // |
| // // Construct a span from an array ptr+size |
| // absl::Span<T> my_span() { |
| // return absl::MakeSpan(&array[0], num_elements_); |
| // } |
| // |
| template <int&... ExplicitArgumentBarrier, typename T> |
| constexpr Span<T> MakeSpan(T* absl_nullable ptr, size_t size) noexcept { |
| return Span<T>(ptr, size); |
| } |
| |
| template <int&... ExplicitArgumentBarrier, typename T> |
| Span<T> MakeSpan(T* absl_nullable begin, T* absl_nullable end) noexcept { |
| ABSL_HARDENING_ASSERT(begin <= end); |
| return Span<T>(begin, static_cast<size_t>(end - begin)); |
| } |
| |
| template <int&... ExplicitArgumentBarrier, typename C> |
| constexpr auto MakeSpan(C& c) noexcept // NOLINT(runtime/references) |
| -> decltype(absl::MakeSpan(span_internal::GetData(c), c.size())) { |
| return MakeSpan(span_internal::GetData(c), c.size()); |
| } |
| |
| template <int&... ExplicitArgumentBarrier, typename T, size_t N> |
| constexpr Span<T> MakeSpan(T (&array)[N]) noexcept { |
| return Span<T>(array, N); |
| } |
| |
| // MakeConstSpan() |
| // |
| // Constructs a `Span<const T>` as with `MakeSpan`, deducing `T` automatically, |
| // but always returning a `Span<const T>`. |
| // |
| // Examples: |
| // |
| // void ProcessInts(absl::Span<const int> some_ints); |
| // |
| // // Call with a pointer and size. |
| // int array[3] = { 0, 0, 0 }; |
| // ProcessInts(absl::MakeConstSpan(&array[0], 3)); |
| // |
| // // Call with a [begin, end) pair. |
| // ProcessInts(absl::MakeConstSpan(&array[0], &array[3])); |
| // |
| // // Call directly with an array. |
| // ProcessInts(absl::MakeConstSpan(array)); |
| // |
| // // Call with a contiguous container. |
| // std::vector<int> some_ints = ...; |
| // ProcessInts(absl::MakeConstSpan(some_ints)); |
| // ProcessInts(absl::MakeConstSpan(std::vector<int>{ 0, 0, 0 })); |
| // |
| template <int&... ExplicitArgumentBarrier, typename T> |
| constexpr Span<const T> MakeConstSpan(T* absl_nullable ptr, |
| size_t size) noexcept { |
| return Span<const T>(ptr, size); |
| } |
| |
| template <int&... ExplicitArgumentBarrier, typename T> |
| Span<const T> MakeConstSpan(T* absl_nullable begin, |
| T* absl_nullable end) noexcept { |
| ABSL_HARDENING_ASSERT(begin <= end); |
| return Span<const T>(begin, end - begin); |
| } |
| |
| template <int&... ExplicitArgumentBarrier, typename C> |
| constexpr auto MakeConstSpan(const C& c) noexcept -> decltype(MakeSpan(c)) { |
| return MakeSpan(c); |
| } |
| |
| template <int&... ExplicitArgumentBarrier, typename T, size_t N> |
| constexpr Span<const T> MakeConstSpan(const T (&array)[N]) noexcept { |
| return Span<const T>(array, N); |
| } |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| #endif // ABSL_TYPES_SPAN_H_ |
| *ì |
| nsoong/.intermediates/external/abseil-cpp/absl_meta_type_traits_hdrs/gen/my_include_dir/absl/meta/type_traits.hø// |
| // 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. |
| // |
| // ----------------------------------------------------------------------------- |
| // type_traits.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This file contains C++11-compatible versions of standard <type_traits> API |
| // functions for determining the characteristics of types. Such traits can |
| // support type inference, classification, and transformation, as well as |
| // make it easier to write templates based on generic type behavior. |
| // |
| // See https://en.cppreference.com/w/cpp/header/type_traits |
| // |
| // WARNING: use of many of the constructs in this header will count as "complex |
| // template metaprogramming", so before proceeding, please carefully consider |
| // https://google.github.io/styleguide/cppguide.html#Template_metaprogramming |
| // |
| // WARNING: using template metaprogramming to detect or depend on API |
| // features is brittle and not guaranteed. Neither the standard library nor |
| // Abseil provides any guarantee that APIs are stable in the face of template |
| // metaprogramming. Use with caution. |
| #ifndef ABSL_META_TYPE_TRAITS_H_ |
| #define ABSL_META_TYPE_TRAITS_H_ |
| |
| #include <cstddef> |
| #include <functional> |
| #include <string> |
| #include <string_view> |
| #include <type_traits> |
| #include <vector> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| |
| #ifdef __cpp_lib_span |
| #include <span> // NOLINT(build/c++20) |
| #endif |
| |
| // Defines the default alignment. `__STDCPP_DEFAULT_NEW_ALIGNMENT__` is a C++17 |
| // feature. |
| #if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) |
| #define ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT __STDCPP_DEFAULT_NEW_ALIGNMENT__ |
| #else // defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) |
| #define ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT alignof(std::max_align_t) |
| #endif // defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| namespace type_traits_internal { |
| |
| template <typename... Ts> |
| struct VoidTImpl { |
| using type = void; |
| }; |
| |
| //////////////////////////////// |
| // Library Fundamentals V2 TS // |
| //////////////////////////////// |
| |
| // NOTE: The `is_detected` family of templates here differ from the library |
| // fundamentals specification in that for library fundamentals, `Op<Args...>` is |
| // evaluated as soon as the type `is_detected<Op, Args...>` undergoes |
| // substitution, regardless of whether or not the `::value` is accessed. That |
| // is inconsistent with all other standard traits and prevents lazy evaluation |
| // in larger contexts (such as if the `is_detected` check is a trailing argument |
| // of a `conjunction`. This implementation opts to instead be lazy in the same |
| // way that the standard traits are (this "defect" of the detection idiom |
| // specifications has been reported). |
| |
| template <class Enabler, template <class...> class Op, class... Args> |
| struct is_detected_impl { |
| using type = std::false_type; |
| }; |
| |
| template <template <class...> class Op, class... Args> |
| struct is_detected_impl<typename VoidTImpl<Op<Args...>>::type, Op, Args...> { |
| using type = std::true_type; |
| }; |
| |
| template <template <class...> class Op, class... Args> |
| struct is_detected : is_detected_impl<void, Op, Args...>::type {}; |
| |
| } // namespace type_traits_internal |
| |
| // void_t() |
| // |
| // Ignores the type of any its arguments and returns `void`. In general, this |
| // metafunction allows you to create a general case that maps to `void` while |
| // allowing specializations that map to specific types. |
| // |
| // This metafunction is not 100% compatible with the C++17 `std::void_t` |
| // metafunction. It has slightly different behavior, such as when ordering |
| // partial specializations. It is recommended to use `std::void_t` instead. |
| template <typename... Ts> |
| using void_t = typename type_traits_internal::VoidTImpl<Ts...>::type; |
| |
| // Historical note: Abseil once provided implementations of these type traits |
| // for platforms that lacked full support. New code should prefer to use the |
| // std variants. |
| // |
| // See the documentation for the STL <type_traits> header for more information: |
| // https://en.cppreference.com/w/cpp/header/type_traits |
| using std::add_const_t; |
| using std::add_cv_t; |
| using std::add_lvalue_reference_t; |
| using std::add_pointer_t; |
| using std::add_rvalue_reference_t; |
| using std::add_volatile_t; |
| using std::common_type_t; |
| using std::conditional_t; |
| using std::conjunction; |
| using std::decay_t; |
| using std::enable_if_t; |
| using std::disjunction; |
| using std::is_copy_assignable; |
| using std::is_function; |
| using std::is_move_assignable; |
| using std::is_trivially_copy_assignable; |
| using std::is_trivially_copy_constructible; |
| using std::is_trivially_default_constructible; |
| using std::is_trivially_destructible; |
| using std::is_trivially_move_assignable; |
| using std::is_trivially_move_constructible; |
| using std::make_signed_t; |
| using std::make_unsigned_t; |
| using std::negation; |
| using std::remove_all_extents_t; |
| using std::remove_const_t; |
| using std::remove_cv_t; |
| using std::remove_extent_t; |
| using std::remove_pointer_t; |
| using std::remove_reference_t; |
| using std::remove_volatile_t; |
| using std::underlying_type_t; |
| |
| #if defined(__cpp_lib_remove_cvref) && __cpp_lib_remove_cvref >= 201711L |
| template <typename T> |
| using remove_cvref = std::remove_cvref<T>; |
| |
| template <typename T> |
| using remove_cvref_t = typename std::remove_cvref<T>::type; |
| #else |
| // remove_cvref() |
| // |
| // C++11 compatible implementation of std::remove_cvref which was added in |
| // C++20. |
| template <typename T> |
| struct remove_cvref { |
| using type = |
| typename std::remove_cv<typename std::remove_reference<T>::type>::type; |
| }; |
| |
| template <typename T> |
| using remove_cvref_t = typename remove_cvref<T>::type; |
| #endif |
| |
| namespace type_traits_internal { |
| |
| #if (defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703L) || \ |
| (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) |
| // std::result_of is deprecated (C++17) or removed (C++20) |
| template <typename> |
| struct result_of; |
| template <typename F, typename... Args> |
| struct result_of<F(Args...)> : std::invoke_result<F, Args...> {}; |
| #else |
| template <typename F> |
| using result_of = std::result_of<F>; |
| #endif |
| |
| } // namespace type_traits_internal |
| |
| template <typename F> |
| using result_of_t = typename type_traits_internal::result_of<F>::type; |
| |
| namespace type_traits_internal { |
| // In MSVC we can't probe std::hash or stdext::hash because it triggers a |
| // static_assert instead of failing substitution. Libc++ prior to 4.0 |
| // also used a static_assert. |
| // |
| #if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \ |
| _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11) |
| #define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0 |
| #else |
| #define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1 |
| #endif |
| |
| #if !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ |
| template <typename Key, typename = size_t> |
| struct IsHashable : std::true_type {}; |
| #else // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ |
| template <typename Key, typename = void> |
| struct IsHashable : std::false_type {}; |
| |
| template <typename Key> |
| struct IsHashable< |
| Key, |
| absl::enable_if_t<std::is_convertible< |
| decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())), |
| std::size_t>::value>> : std::true_type {}; |
| #endif // !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ |
| |
| struct AssertHashEnabledHelper { |
| private: |
| static void Sink(...) {} |
| struct NAT {}; |
| |
| template <class Key> |
| static auto GetReturnType(int) |
| -> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>())); |
| template <class Key> |
| static NAT GetReturnType(...); |
| |
| template <class Key> |
| static std::nullptr_t DoIt() { |
| static_assert(IsHashable<Key>::value, |
| "std::hash<Key> does not provide a call operator"); |
| static_assert( |
| std::is_default_constructible<std::hash<Key>>::value, |
| "std::hash<Key> must be default constructible when it is enabled"); |
| static_assert( |
| std::is_copy_constructible<std::hash<Key>>::value, |
| "std::hash<Key> must be copy constructible when it is enabled"); |
| static_assert(absl::is_copy_assignable<std::hash<Key>>::value, |
| "std::hash<Key> must be copy assignable when it is enabled"); |
| // is_destructible is unchecked as it's implied by each of the |
| // is_constructible checks. |
| using ReturnType = decltype(GetReturnType<Key>(0)); |
| static_assert(std::is_same<ReturnType, NAT>::value || |
| std::is_same<ReturnType, size_t>::value, |
| "std::hash<Key> must return size_t"); |
| return nullptr; |
| } |
| |
| template <class... Ts> |
| friend void AssertHashEnabled(); |
| }; |
| |
| template <class... Ts> |
| inline void AssertHashEnabled() { |
| using Helper = AssertHashEnabledHelper; |
| Helper::Sink(Helper::DoIt<Ts>()...); |
| } |
| |
| } // namespace type_traits_internal |
| |
| // An internal namespace that is required to implement the C++17 swap traits. |
| // It is not further nested in type_traits_internal to avoid long symbol names. |
| namespace swap_internal { |
| |
| // Necessary for the traits. |
| using std::swap; |
| |
| // This declaration prevents global `swap` and `absl::swap` overloads from being |
| // considered unless ADL picks them up. |
| void swap(); |
| |
| template <class T> |
| using IsSwappableImpl = decltype(swap(std::declval<T&>(), std::declval<T&>())); |
| |
| // NOTE: This dance with the default template parameter is for MSVC. |
| template <class T, |
| class IsNoexcept = std::integral_constant< |
| bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))>> |
| using IsNothrowSwappableImpl = typename std::enable_if<IsNoexcept::value>::type; |
| |
| // IsSwappable |
| // |
| // Determines whether the standard swap idiom is a valid expression for |
| // arguments of type `T`. |
| template <class T> |
| struct IsSwappable |
| : absl::type_traits_internal::is_detected<IsSwappableImpl, T> {}; |
| |
| // IsNothrowSwappable |
| // |
| // Determines whether the standard swap idiom is a valid expression for |
| // arguments of type `T` and is noexcept. |
| template <class T> |
| struct IsNothrowSwappable |
| : absl::type_traits_internal::is_detected<IsNothrowSwappableImpl, T> {}; |
| |
| // Swap() |
| // |
| // Performs the swap idiom from a namespace where valid candidates may only be |
| // found in `std` or via ADL. |
| template <class T, absl::enable_if_t<IsSwappable<T>::value, int> = 0> |
| void Swap(T& lhs, T& rhs) noexcept(IsNothrowSwappable<T>::value) { |
| swap(lhs, rhs); |
| } |
| |
| // StdSwapIsUnconstrained |
| // |
| // Some standard library implementations are broken in that they do not |
| // constrain `std::swap`. This will effectively tell us if we are dealing with |
| // one of those implementations. |
| using StdSwapIsUnconstrained = IsSwappable<void()>; |
| |
| } // namespace swap_internal |
| |
| namespace type_traits_internal { |
| |
| // Make the swap-related traits/function accessible from this namespace. |
| using swap_internal::IsNothrowSwappable; |
| using swap_internal::IsSwappable; |
| using swap_internal::StdSwapIsUnconstrained; |
| using swap_internal::Swap; |
| |
| } // namespace type_traits_internal |
| |
| // absl::is_trivially_relocatable<T> |
| // |
| // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2786r11.html |
| // |
| // Detects whether a type is known to be "trivially relocatable" -- meaning it |
| // can be relocated from one place to another as if by memcpy/memmove. |
| // This implies that its object representation doesn't depend on its address, |
| // and also none of its special member functions do anything strange. |
| // |
| // Note that when relocating the caller code should ensure that if the object is |
| // polymorphic, the dynamic type is of the most derived type. Padding bytes |
| // should not be copied. |
| // |
| // This trait is conservative. If it's true then the type is definitely |
| // trivially relocatable, but if it's false then the type may or may not be. For |
| // example, std::vector<int> is trivially relocatable on every known STL |
| // implementation, but absl::is_trivially_relocatable<std::vector<int>> remains |
| // false. |
| // |
| // Example: |
| // |
| // if constexpr (absl::is_trivially_relocatable<T>::value) { |
| // memcpy(new_location, old_location, sizeof(T)); |
| // } else { |
| // new(new_location) T(std::move(*old_location)); |
| // old_location->~T(); |
| // } |
| // |
| // Upstream documentation: |
| // |
| // https://clang.llvm.org/docs/LanguageExtensions.html#:~:text=__builtin_is_cpp_trivially_relocatable |
| // |
| // Clang on Windows has the builtin, but it falsely claims types with a |
| // user-provided destructor are trivial (http://b/275003464). So we opt out |
| // there. |
| // |
| // TODO(b/275003464): remove the opt-out once the bug is fixed. |
| // |
| // Starting with Xcode 15, the Apple compiler will falsely say a type |
| // with a user-provided move constructor is trivially relocatable |
| // (b/324278148). We will opt out without a version check, due to |
| // the fluidity of Apple versions. |
| // |
| // TODO(b/324278148): If all versions we use have the bug fixed, then |
| // remove the condition. |
| // |
| // Clang on all platforms fails to detect that a type with a user-provided |
| // move-assignment operator is not trivially relocatable so we also check for |
| // is_trivially_move_assignable for Clang. |
| // |
| // TODO(b/325479096): Remove the Clang is_trivially_move_assignable version once |
| // Clang's behavior is fixed. |
| // |
| // According to https://github.com/abseil/abseil-cpp/issues/1479, this does not |
| // work with NVCC either. |
| #if ABSL_HAVE_BUILTIN(__builtin_is_cpp_trivially_relocatable) |
| // https://github.com/llvm/llvm-project/pull/127636#pullrequestreview-2637005293 |
| // In the current implementation, __builtin_is_cpp_trivially_relocatable will |
| // only return true for types that are trivially relocatable according to the |
| // standard. Notably, this means that marking a type [[clang::trivial_abi]] aka |
| // ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI will have no effect on this trait. |
| template <class T> |
| struct is_trivially_relocatable |
| : std::integral_constant<bool, __builtin_is_cpp_trivially_relocatable(T)> { |
| }; |
| #elif ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && defined(__clang__) && \ |
| !(defined(_WIN32) || defined(_WIN64)) && !defined(__APPLE__) && \ |
| !defined(__NVCC__) |
| // https://github.com/llvm/llvm-project/pull/139061 |
| // __is_trivially_relocatable is deprecated. |
| // TODO(b/325479096): Remove this case. |
| template <class T> |
| struct is_trivially_relocatable |
| : std::integral_constant< |
| bool, std::is_trivially_copyable<T>::value || |
| (__is_trivially_relocatable(T) && |
| std::is_trivially_move_assignable<T>::value)> {}; |
| #else |
| // Otherwise we use a fallback that detects only those types we can feasibly |
| // detect. Any type that is trivially copyable is by definition trivially |
| // relocatable. |
| template <class T> |
| struct is_trivially_relocatable : std::is_trivially_copyable<T> {}; |
| #endif |
| |
| // absl::is_constant_evaluated() |
| // |
| // Detects whether the function call occurs within a constant-evaluated context. |
| // Returns true if the evaluation of the call occurs within the evaluation of an |
| // expression or conversion that is manifestly constant-evaluated; otherwise |
| // returns false. |
| // |
| // This function is implemented in terms of `std::is_constant_evaluated` for |
| // c++20 and up. For older c++ versions, the function is implemented in terms |
| // of `__builtin_is_constant_evaluated` if available, otherwise the function |
| // will fail to compile. |
| // |
| // Applications can inspect `ABSL_HAVE_CONSTANT_EVALUATED` at compile time |
| // to check if this function is supported. |
| // |
| // Example: |
| // |
| // constexpr MyClass::MyClass(int param) { |
| // #ifdef ABSL_HAVE_CONSTANT_EVALUATED |
| // if (!absl::is_constant_evaluated()) { |
| // ABSL_LOG(INFO) << "MyClass(" << param << ")"; |
| // } |
| // #endif // ABSL_HAVE_CONSTANT_EVALUATED |
| // } |
| // |
| // Upstream documentation: |
| // |
| // http://en.cppreference.com/w/cpp/types/is_constant_evaluated |
| // http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#:~:text=__builtin_is_constant_evaluated |
| // |
| #if defined(ABSL_HAVE_CONSTANT_EVALUATED) |
| constexpr bool is_constant_evaluated() noexcept { |
| #ifdef __cpp_lib_is_constant_evaluated |
| return std::is_constant_evaluated(); |
| #elif ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated) |
| return __builtin_is_constant_evaluated(); |
| #endif |
| } |
| #endif // ABSL_HAVE_CONSTANT_EVALUATED |
| |
| namespace type_traits_internal { |
| |
| // Detects if a class's definition has declared itself to be an owner by |
| // declaring |
| // using absl_internal_is_view = std::true_type; |
| // as a member. |
| // Types that don't want either must either omit this declaration entirely, or |
| // (if e.g. inheriting from a base class) define the member to something that |
| // isn't a Boolean trait class, such as `void`. |
| // Do not specialize or use this directly. It's an implementation detail. |
| template <typename T, typename = void> |
| struct IsOwnerImpl : std::false_type { |
| static_assert(std::is_same<T, absl::remove_cvref_t<T>>::value, |
| "type must lack qualifiers"); |
| }; |
| |
| template <typename T> |
| struct IsOwnerImpl< |
| T, |
| std::enable_if_t<std::is_class<typename T::absl_internal_is_view>::value>> |
| : absl::negation<typename T::absl_internal_is_view> {}; |
| |
| // A trait to determine whether a type is an owner. |
| // Do *not* depend on the correctness of this trait for correct code behavior. |
| // It is only a safety feature and its value may change in the future. |
| // Do not specialize this; instead, define the member trait inside your type so |
| // that it can be auto-detected, and to prevent ODR violations. |
| // If it ever becomes possible to detect [[gsl::Owner]], we should leverage it: |
| // https://wg21.link/p1179 |
| template <typename T> |
| struct IsOwner : IsOwnerImpl<T> {}; |
| |
| template <typename T, typename Traits, typename Alloc> |
| struct IsOwner<std::basic_string<T, Traits, Alloc>> : std::true_type {}; |
| |
| template <typename T, typename Alloc> |
| struct IsOwner<std::vector<T, Alloc>> : std::true_type {}; |
| |
| // Detects if a class's definition has declared itself to be a view by declaring |
| // using absl_internal_is_view = std::true_type; |
| // as a member. |
| // Do not specialize or use this directly. |
| template <typename T, typename = void> |
| struct IsViewImpl : std::false_type { |
| static_assert(std::is_same<T, absl::remove_cvref_t<T>>::value, |
| "type must lack qualifiers"); |
| }; |
| |
| template <typename T> |
| struct IsViewImpl< |
| T, |
| std::enable_if_t<std::is_class<typename T::absl_internal_is_view>::value>> |
| : T::absl_internal_is_view {}; |
| |
| // A trait to determine whether a type is a view. |
| // Do *not* depend on the correctness of this trait for correct code behavior. |
| // It is only a safety feature, and its value may change in the future. |
| // Do not specialize this trait. Instead, define the member |
| // using absl_internal_is_view = std::true_type; |
| // in your class to allow its detection while preventing ODR violations. |
| // If it ever becomes possible to detect [[gsl::Pointer]], we should leverage |
| // it: https://wg21.link/p1179 |
| template <typename T> |
| struct IsView : std::integral_constant<bool, std::is_pointer<T>::value || |
| IsViewImpl<T>::value> {}; |
| |
| template <typename Char, typename Traits> |
| struct IsView<std::basic_string_view<Char, Traits>> : std::true_type {}; |
| |
| #ifdef __cpp_lib_span |
| template <typename T> |
| struct IsView<std::span<T>> : std::true_type {}; |
| #endif |
| |
| // Determines whether the assignment of the given types is lifetime-bound. |
| // Do *not* depend on the correctness of this trait for correct code behavior. |
| // It is only a safety feature and its value may change in the future. |
| // If it ever becomes possible to detect [[clang::lifetimebound]] directly, |
| // we should change the implementation to leverage that. |
| // Until then, we consider an assignment from an "owner" (such as std::string) |
| // to a "view" (such as std::string_view) to be a lifetime-bound assignment. |
| template <typename T, typename U> |
| using IsLifetimeBoundAssignment = absl::conjunction< |
| std::integral_constant<bool, !std::is_lvalue_reference<U>::value>, |
| IsOwner<absl::remove_cvref_t<U>>, IsView<absl::remove_cvref_t<T>>>; |
| |
| } // namespace type_traits_internal |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_META_TYPE_TRAITS_H_ |
| *ð |
| vsoong/.intermediates/external/abseil-cpp/absl_base_base_internal_hdrs/gen/my_include_dir/absl/base/internal/identity.hõ// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #ifndef ABSL_BASE_INTERNAL_IDENTITY_H_ |
| #define ABSL_BASE_INTERNAL_IDENTITY_H_ |
| |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace internal { |
| |
| // This is a back-fill of C++20's `std::type_identity`. |
| template <typename T> |
| struct type_identity { |
| typedef T type; |
| }; |
| |
| // This is a back-fill of C++20's `std::type_identity_t`. |
| template <typename T> |
| using type_identity_t = typename type_identity<T>::type; |
| |
| } // namespace internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_IDENTITY_H_ |
| *8 |
| \soong/.intermediates/external/abseil-cpp/absl_base_hdrs/gen/my_include_dir/absl/base/casts.h±7// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: casts.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines casting templates to fit use cases not covered by |
| // the standard casts provided in the C++ standard. As with all cast operations, |
| // use these with caution and only if alternatives do not exist. |
| |
| #ifndef ABSL_BASE_CASTS_H_ |
| #define ABSL_BASE_CASTS_H_ |
| |
| #include <cstring> |
| #include <memory> |
| #include <type_traits> |
| #include <utility> |
| |
| #if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L |
| #include <bit> // For std::bit_cast. |
| #endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L |
| |
| #include "absl/base/internal/identity.h" |
| #include "absl/base/macros.h" |
| #include "absl/meta/type_traits.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // implicit_cast() |
| // |
| // Performs an implicit conversion between types following the language |
| // rules for implicit conversion; if an implicit conversion is otherwise |
| // allowed by the language in the given context, this function performs such an |
| // implicit conversion. |
| // |
| // Example: |
| // |
| // // If the context allows implicit conversion: |
| // From from; |
| // To to = from; |
| // |
| // // Such code can be replaced by: |
| // implicit_cast<To>(from); |
| // |
| // An `implicit_cast()` may also be used to annotate numeric type conversions |
| // that, although safe, may produce compiler warnings (such as `long` to `int`). |
| // Additionally, an `implicit_cast()` is also useful within return statements to |
| // indicate a specific implicit conversion is being undertaken. |
| // |
| // Example: |
| // |
| // return implicit_cast<double>(size_in_bytes) / capacity_; |
| // |
| // Annotating code with `implicit_cast()` allows you to explicitly select |
| // particular overloads and template instantiations, while providing a safer |
| // cast than `reinterpret_cast()` or `static_cast()`. |
| // |
| // Additionally, an `implicit_cast()` can be used to allow upcasting within a |
| // type hierarchy where incorrect use of `static_cast()` could accidentally |
| // allow downcasting. |
| // |
| // Finally, an `implicit_cast()` can be used to perform implicit conversions |
| // from unrelated types that otherwise couldn't be implicitly cast directly; |
| // C++ will normally only implicitly cast "one step" in such conversions. |
| // |
| // That is, if C is a type which can be implicitly converted to B, with B being |
| // a type that can be implicitly converted to A, an `implicit_cast()` can be |
| // used to convert C to B (which the compiler can then implicitly convert to A |
| // using language rules). |
| // |
| // Example: |
| // |
| // // Assume an object C is convertible to B, which is implicitly convertible |
| // // to A |
| // A a = implicit_cast<B>(C); |
| // |
| // Such implicit cast chaining may be useful within template logic. |
| template <typename To> |
| constexpr To implicit_cast(typename absl::internal::type_identity_t<To> to) { |
| return to; |
| } |
| |
| // bit_cast() |
| // |
| // Creates a value of the new type `Dest` whose representation is the same as |
| // that of the argument, which is of (deduced) type `Source` (a "bitwise cast"; |
| // every bit in the value representation of the result is equal to the |
| // corresponding bit in the object representation of the source). Source and |
| // destination types must be of the same size, and both types must be trivially |
| // copyable. |
| // |
| // As with most casts, use with caution. A `bit_cast()` might be needed when you |
| // need to treat a value as the value of some other type, for example, to access |
| // the individual bits of an object which are not normally accessible through |
| // the object's type, such as for working with the binary representation of a |
| // floating point value: |
| // |
| // float f = 3.14159265358979; |
| // int i = bit_cast<int>(f); |
| // // i = 0x40490fdb |
| // |
| // Reinterpreting and accessing a value directly as a different type (as shown |
| // below) usually results in undefined behavior. |
| // |
| // Example: |
| // |
| // // WRONG |
| // float f = 3.14159265358979; |
| // int i = reinterpret_cast<int&>(f); // Wrong |
| // int j = *reinterpret_cast<int*>(&f); // Equally wrong |
| // int k = *bit_cast<int*>(&f); // Equally wrong |
| // |
| // Reinterpret-casting results in undefined behavior according to the ISO C++ |
| // specification, section [basic.lval]. Roughly, this section says: if an object |
| // in memory has one type, and a program accesses it with a different type, the |
| // result is undefined behavior for most "different type". |
| // |
| // Using bit_cast on a pointer and then dereferencing it is no better than using |
| // reinterpret_cast. You should only use bit_cast on the value itself. |
| // |
| // Such casting results in type punning: holding an object in memory of one type |
| // and reading its bits back using a different type. A `bit_cast()` avoids this |
| // issue by copying the object representation to a new value, which avoids |
| // introducing this undefined behavior (since the original value is never |
| // accessed in the wrong way). |
| // |
| // The requirements of `absl::bit_cast` are more strict than that of |
| // `std::bit_cast` unless compiler support is available. Specifically, without |
| // compiler support, this implementation also requires `Dest` to be |
| // default-constructible. In C++20, `absl::bit_cast` is replaced by |
| // `std::bit_cast`. |
| #if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L |
| |
| using std::bit_cast; |
| |
| #else // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L |
| |
| template < |
| typename Dest, typename Source, |
| typename std::enable_if<sizeof(Dest) == sizeof(Source) && |
| std::is_trivially_copyable<Source>::value && |
| std::is_trivially_copyable<Dest>::value |
| #if !ABSL_HAVE_BUILTIN(__builtin_bit_cast) |
| && std::is_default_constructible<Dest>::value |
| #endif // !ABSL_HAVE_BUILTIN(__builtin_bit_cast) |
| , |
| int>::type = 0> |
| #if ABSL_HAVE_BUILTIN(__builtin_bit_cast) |
| inline constexpr Dest bit_cast(const Source& source) { |
| return __builtin_bit_cast(Dest, source); |
| } |
| #else // ABSL_HAVE_BUILTIN(__builtin_bit_cast) |
| inline Dest bit_cast(const Source& source) { |
| Dest dest; |
| memcpy(static_cast<void*>(std::addressof(dest)), |
| static_cast<const void*>(std::addressof(source)), sizeof(dest)); |
| return dest; |
| } |
| #endif // ABSL_HAVE_BUILTIN(__builtin_bit_cast) |
| |
| #endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_CASTS_H_ |
| * |
| soong/.intermediates/external/abseil-cpp/absl_log_internal_structured_proto_hdrs/gen/my_include_dir/absl/log/internal/structured_proto.h// Copyright 2024 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: log/internal/structured_proto.h |
| // ----------------------------------------------------------------------------- |
| |
| #ifndef ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_ |
| #define ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_ |
| |
| #include <cstddef> |
| #include <cstdint> |
| |
| #include "absl/base/config.h" |
| #include "absl/log/internal/proto.h" |
| #include "absl/types/span.h" |
| #include "absl/types/variant.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace log_internal { |
| |
| // Sum type holding a single valid protobuf field suitable for encoding. |
| struct StructuredProtoField final { |
| // Numeric type encoded with varint encoding: |
| // https://protobuf.dev/programming-guides/encoding/#varints |
| using Varint = absl::variant<uint64_t, int64_t, uint32_t, int32_t, bool>; |
| |
| // Fixed-length 64-bit integer encoding: |
| // https://protobuf.dev/programming-guides/encoding/#non-varints |
| using I64 = absl::variant<uint64_t, int64_t, double>; |
| |
| // Length-delimited record type (string, sub-message): |
| // https://protobuf.dev/programming-guides/encoding/#length-types |
| using LengthDelimited = absl::Span<const char>; |
| |
| // Fixed-length 32-bit integer encoding: |
| // https://protobuf.dev/programming-guides/encoding/#non-varints |
| using I32 = absl::variant<uint32_t, int32_t, float>; |
| |
| // Valid record type: |
| // https://protobuf.dev/programming-guides/encoding/#structure |
| using Value = absl::variant<Varint, I64, LengthDelimited, I32>; |
| |
| // Field number for the protobuf value. |
| uint64_t field_number; |
| |
| // Value to encode. |
| Value value; |
| }; |
| |
| // Estimates the number of bytes needed to encode `field` using |
| // protobuf encoding. |
| // |
| // The returned value might be larger than the actual number of bytes needed. |
| inline size_t BufferSizeForStructuredProtoField(StructuredProtoField field) { |
| // Visitor to estimate the number of bytes of one of the types contained |
| // inside `StructuredProtoField`. |
| struct BufferSizeVisitor final { |
| size_t operator()(StructuredProtoField::Varint /*unused*/) { |
| return BufferSizeFor(field_number, WireType::kVarint); |
| } |
| |
| size_t operator()(StructuredProtoField::I64 /*unused*/) { |
| return BufferSizeFor(field_number, WireType::k64Bit); |
| } |
| |
| size_t operator()(StructuredProtoField::LengthDelimited length_delimited) { |
| return BufferSizeFor(field_number, WireType::kLengthDelimited) + |
| length_delimited.size(); |
| } |
| |
| size_t operator()(StructuredProtoField::I32 /*unused*/) { |
| return BufferSizeFor(field_number, WireType::k32Bit); |
| } |
| |
| uint64_t field_number; |
| }; |
| |
| return absl::visit(BufferSizeVisitor{field.field_number}, field.value); |
| } |
| |
| // Encodes `field` into `buf` using protobuf encoding. |
| // |
| // On success, returns `true` and advances `buf` to the end of |
| // the bytes consumed. |
| // |
| // On failure (if `buf` was too small), returns `false`. |
| bool EncodeStructuredProtoField(StructuredProtoField field, |
| absl::Span<char>& buf); |
| |
| } // namespace log_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_ |
| * |
| zsoong/.intermediates/external/abseil-cpp/absl_log_internal_nullguard_hdrs/gen/my_include_dir/absl/log/internal/nullguard.h// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/internal/nullguard.h |
| // ----------------------------------------------------------------------------- |
| // |
| // NullGuard exists such that NullGuard<T>::Guard(v) returns v, unless passed a |
| // nullptr_t, or a null char* or const char*, in which case it returns "(null)". |
| // This allows streaming NullGuard<T>::Guard(v) to an output stream without |
| // hitting undefined behavior for null values. |
| |
| #ifndef ABSL_LOG_INTERNAL_NULLGUARD_H_ |
| #define ABSL_LOG_INTERNAL_NULLGUARD_H_ |
| |
| #include <array> |
| #include <cstddef> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace log_internal { |
| |
| ABSL_CONST_INIT ABSL_DLL extern const std::array<char, 7> kCharNull; |
| ABSL_CONST_INIT ABSL_DLL extern const std::array<signed char, 7> |
| kSignedCharNull; |
| ABSL_CONST_INIT ABSL_DLL extern const std::array<unsigned char, 7> |
| kUnsignedCharNull; |
| |
| template <typename T> |
| struct NullGuard final { |
| static const T& Guard(const T& v) { return v; } |
| }; |
| template <> |
| struct NullGuard<char*> final { |
| static const char* Guard(const char* v) { return v ? v : kCharNull.data(); } |
| }; |
| template <> |
| struct NullGuard<const char*> final { |
| static const char* Guard(const char* v) { return v ? v : kCharNull.data(); } |
| }; |
| template <> |
| struct NullGuard<signed char*> final { |
| static const signed char* Guard(const signed char* v) { |
| return v ? v : kSignedCharNull.data(); |
| } |
| }; |
| template <> |
| struct NullGuard<const signed char*> final { |
| static const signed char* Guard(const signed char* v) { |
| return v ? v : kSignedCharNull.data(); |
| } |
| }; |
| template <> |
| struct NullGuard<unsigned char*> final { |
| static const unsigned char* Guard(const unsigned char* v) { |
| return v ? v : kUnsignedCharNull.data(); |
| } |
| }; |
| template <> |
| struct NullGuard<const unsigned char*> final { |
| static const unsigned char* Guard(const unsigned char* v) { |
| return v ? v : kUnsignedCharNull.data(); |
| } |
| }; |
| template <> |
| struct NullGuard<std::nullptr_t> final { |
| static const char* Guard(const std::nullptr_t&) { return kCharNull.data(); } |
| }; |
| |
| } // namespace log_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_LOG_INTERNAL_NULLGUARD_H_ |
| * |
| soong/.intermediates/external/abseil-cpp/absl_synchronization_hdrs/gen/my_include_dir/absl/synchronization/internal/create_thread_identity.hð/* |
| * 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. |
| */ |
| |
| // Interface for getting the current ThreadIdentity, creating one if necessary. |
| // See thread_identity.h. |
| // |
| // This file is separate from thread_identity.h because creating a new |
| // ThreadIdentity requires slightly higher level libraries (per_thread_sem |
| // and low_level_alloc) than accessing an existing one. This separation allows |
| // us to have a smaller //absl/base:base. |
| |
| #ifndef ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_ |
| #define ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_ |
| |
| #include "absl/base/internal/thread_identity.h" |
| #include "absl/base/port.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace synchronization_internal { |
| |
| // Allocates and attaches a ThreadIdentity object for the calling thread. |
| // For private use only. |
| base_internal::ThreadIdentity* CreateThreadIdentity(); |
| |
| // Returns the ThreadIdentity object representing the calling thread; guaranteed |
| // to be unique for its lifetime. The returned object will remain valid for the |
| // program's lifetime; although it may be re-assigned to a subsequent thread. |
| // If one does not exist for the calling thread, allocate it now. |
| inline base_internal::ThreadIdentity* GetOrCreateCurrentThreadIdentity() { |
| base_internal::ThreadIdentity* identity = |
| base_internal::CurrentThreadIdentityIfPresent(); |
| if (ABSL_PREDICT_FALSE(identity == nullptr)) { |
| return CreateThreadIdentity(); |
| } |
| return identity; |
| } |
| |
| } // namespace synchronization_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_ |
| *© |
| ~soong/.intermediates/external/abseil-cpp/absl_log_internal_log_message_hdrs/gen/my_include_dir/absl/log/internal/log_message.h¥// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/internal/log_message.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This file declares `class absl::log_internal::LogMessage`. This class more or |
| // less represents a particular log message. LOG/CHECK macros create a temporary |
| // instance of `LogMessage` and then stream values to it. At the end of the |
| // LOG/CHECK statement, the LogMessage is voidified by operator&&, and `Flush()` |
| // directs the message to the registered log sinks. Heap-allocation of |
| // `LogMessage` is unsupported. Construction outside of a `LOG` macro is |
| // unsupported. |
| |
| #ifndef ABSL_LOG_INTERNAL_LOG_MESSAGE_H_ |
| #define ABSL_LOG_INTERNAL_LOG_MESSAGE_H_ |
| |
| #include <wchar.h> |
| |
| #include <cstddef> |
| #include <ios> |
| #include <memory> |
| #include <ostream> |
| #include <streambuf> |
| #include <string> |
| #include <string_view> |
| #include <type_traits> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/errno_saver.h" |
| #include "absl/base/log_severity.h" |
| #include "absl/base/nullability.h" |
| #include "absl/log/internal/nullguard.h" |
| #include "absl/log/internal/structured_proto.h" |
| #include "absl/log/log_entry.h" |
| #include "absl/log/log_sink.h" |
| #include "absl/strings/has_absl_stringify.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/time/time.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace log_internal { |
| constexpr int kLogMessageBufferSize = 15000; |
| |
| enum class StructuredStringType; |
| |
| class LogMessage { |
| public: |
| struct InfoTag {}; |
| struct WarningTag {}; |
| struct ErrorTag {}; |
| |
| // Used for `LOG`. |
| LogMessage(const char* absl_nonnull file, int line, |
| absl::LogSeverity severity) ABSL_ATTRIBUTE_COLD; |
| // These constructors are slightly smaller/faster to call; the severity is |
| // curried into the function pointer. |
| LogMessage(const char* absl_nonnull file, int line, |
| InfoTag) ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE; |
| LogMessage(const char* absl_nonnull file, int line, |
| WarningTag) ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE; |
| LogMessage(const char* absl_nonnull file, int line, |
| ErrorTag) ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE; |
| LogMessage(const LogMessage&) = delete; |
| LogMessage& operator=(const LogMessage&) = delete; |
| ~LogMessage() ABSL_ATTRIBUTE_COLD; |
| |
| // Overrides the location inferred from the callsite. The string pointed to |
| // by `file` must be valid until the end of the statement. |
| LogMessage& AtLocation(absl::string_view file, int line); |
| // Omits the prefix from this line. The prefix includes metadata about the |
| // logged data such as source code location and timestamp. |
| LogMessage& NoPrefix(); |
| // Sets the verbosity field of the logged message as if it was logged by |
| // `VLOG(verbose_level)`. Unlike `VLOG`, this method does not affect |
| // evaluation of the statement when the specified `verbose_level` has been |
| // disabled. The only effect is on `absl::LogSink` implementations which |
| // make use of the `absl::LogSink::verbosity()` value. The value |
| // `absl::LogEntry::kNoVerbosityLevel` can be specified to mark the message |
| // not verbose. |
| LogMessage& WithVerbosity(int verbose_level); |
| // Uses the specified timestamp instead of one collected in the constructor. |
| LogMessage& WithTimestamp(absl::Time timestamp); |
| // Uses the specified thread ID instead of one collected in the constructor. |
| LogMessage& WithThreadID(absl::LogEntry::tid_t tid); |
| // Copies all metadata (but no data) from the specified `absl::LogEntry`. |
| LogMessage& WithMetadataFrom(const absl::LogEntry& entry); |
| // Appends to the logged message a colon, a space, a textual description of |
| // the current value of `errno` (as by strerror(3)), and the numerical value |
| // of `errno`. |
| LogMessage& WithPerror(); |
| // Sends this message to `*sink` in addition to whatever other sinks it would |
| // otherwise have been sent to. |
| LogMessage& ToSinkAlso(absl::LogSink* absl_nonnull sink); |
| // Sends this message to `*sink` and no others. |
| LogMessage& ToSinkOnly(absl::LogSink* absl_nonnull sink); |
| |
| // Don't call this method from outside this library. |
| LogMessage& InternalStream() { return *this; } |
| |
| // By-value overloads for small, common types let us overlook common failures |
| // to define globals and static data members (i.e. in a .cc file). |
| // NOLINTBEGIN(runtime/int) |
| // NOLINTBEGIN(google-runtime-int) |
| // clang-format off: The CUDA toolchain cannot handle these <<<'s |
| LogMessage& operator<<(char v) { return operator<< <char>(v); } |
| LogMessage& operator<<(signed char v) { return operator<< <signed char>(v); } |
| LogMessage& operator<<(unsigned char v) { |
| return operator<< <unsigned char>(v); |
| } |
| LogMessage& operator<<(signed short v) { |
| return operator<< <signed short>(v); |
| } |
| LogMessage& operator<<(signed int v) { return operator<< <signed int>(v); } |
| LogMessage& operator<<(signed long v) { |
| return operator<< <signed long>(v); |
| } |
| LogMessage& operator<<(signed long long v) { |
| return operator<< <signed long long>(v); |
| } |
| LogMessage& operator<<(unsigned short v) { |
| return operator<< <unsigned short>(v); |
| } |
| LogMessage& operator<<(unsigned int v) { |
| return operator<< <unsigned int>(v); |
| } |
| LogMessage& operator<<(unsigned long v) { |
| return operator<< <unsigned long>(v); |
| } |
| LogMessage& operator<<(unsigned long long v) { |
| return operator<< <unsigned long long>(v); |
| } |
| LogMessage& operator<<(void* absl_nullable v) { |
| return operator<< <void*>(v); |
| } |
| LogMessage& operator<<(const void* absl_nullable v) { |
| return operator<< <const void*>(v); |
| } |
| LogMessage& operator<<(float v) { return operator<< <float>(v); } |
| LogMessage& operator<<(double v) { return operator<< <double>(v); } |
| LogMessage& operator<<(bool v) { return operator<< <bool>(v); } |
| // clang-format on |
| // NOLINTEND(google-runtime-int) |
| // NOLINTEND(runtime/int) |
| |
| // These overloads are more efficient since no `ostream` is involved. |
| LogMessage& operator<<(const std::string& v); |
| LogMessage& operator<<(absl::string_view v); |
| |
| // Wide string overloads (since std::ostream does not provide them). |
| LogMessage& operator<<(const std::wstring& v); |
| LogMessage& operator<<(std::wstring_view v); |
| // `const wchar_t*` is handled by `operator<< <const wchar_t*>`. |
| LogMessage& operator<<(wchar_t* absl_nullable v); |
| LogMessage& operator<<(wchar_t v); |
| |
| // Handle stream manipulators e.g. std::endl. |
| LogMessage& operator<<(std::ostream& (*absl_nonnull m)(std::ostream& os)); |
| LogMessage& operator<<(std::ios_base& (*absl_nonnull m)(std::ios_base& os)); |
| |
| // Literal strings. This allows us to record C string literals as literals in |
| // the logging.proto.Value. |
| // |
| // Allow this overload to be inlined to prevent generating instantiations of |
| // this template for every value of `SIZE` encountered in each source code |
| // file. That significantly increases linker input sizes. Inlining is cheap |
| // because the argument to this overload is almost always a string literal so |
| // the call to `strlen` can be replaced at compile time. The overloads for |
| // `char[]`/`wchar_t[]` below should not be inlined. The compiler typically |
| // does not have the string at compile time and cannot replace the call to |
| // `strlen` so inlining it increases the binary size. See the discussion on |
| // cl/107527369. |
| template <int SIZE> |
| LogMessage& operator<<(const char (&buf)[SIZE]); |
| template <int SIZE> |
| LogMessage& operator<<(const wchar_t (&buf)[SIZE]); |
| |
| // This prevents non-const `char[]` arrays from looking like literals. |
| template <int SIZE> |
| LogMessage& operator<<(char (&buf)[SIZE]) ABSL_ATTRIBUTE_NOINLINE; |
| // `wchar_t[SIZE]` is handled by `operator<< <const wchar_t*>`. |
| |
| // Types that support `AbslStringify()` are serialized that way. |
| // Types that don't support `AbslStringify()` but do support streaming into a |
| // `std::ostream&` are serialized that way. |
| template <typename T> |
| LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE; |
| |
| // Dispatches the completed `absl::LogEntry` to applicable `absl::LogSink`s. |
| void Flush(); |
| |
| // Note: We explicitly do not support `operator<<` for non-const references |
| // because it breaks logging of non-integer bitfield types (i.e., enums). |
| |
| protected: |
| // Call `abort()` or similar to perform `LOG(FATAL)` crash. It is assumed |
| // that the caller has already generated and written the trace as appropriate. |
| [[noreturn]] static void FailWithoutStackTrace(); |
| |
| // Similar to `FailWithoutStackTrace()`, but without `abort()`. Terminates |
| // the process with an error exit code. |
| [[noreturn]] static void FailQuietly(); |
| |
| // After this is called, failures are done as quiet as possible for this log |
| // message. |
| void SetFailQuietly(); |
| |
| private: |
| struct LogMessageData; // Opaque type containing message state |
| friend class AsLiteralImpl; |
| friend class StringifySink; |
| template <StructuredStringType str_type> |
| friend class AsStructuredStringTypeImpl; |
| template <typename T> |
| friend class AsStructuredValueImpl; |
| |
| // This streambuf writes directly into the structured logging buffer so that |
| // arbitrary types can be encoded as string data (using |
| // `operator<<(std::ostream &, ...)` without any extra allocation or copying. |
| // Space is reserved before the data to store the length field, which is |
| // filled in by `~OstreamView`. |
| class OstreamView final : public std::streambuf { |
| public: |
| explicit OstreamView(LogMessageData& message_data); |
| ~OstreamView() override; |
| OstreamView(const OstreamView&) = delete; |
| OstreamView& operator=(const OstreamView&) = delete; |
| std::ostream& stream(); |
| |
| private: |
| LogMessageData& data_; |
| absl::Span<char> encoded_remaining_copy_; |
| absl::Span<char> message_start_; |
| absl::Span<char> string_start_; |
| }; |
| |
| enum class StringType { |
| kLiteral, |
| kNotLiteral, |
| }; |
| template <StringType str_type> |
| void CopyToEncodedBuffer(absl::string_view str) ABSL_ATTRIBUTE_NOINLINE; |
| template <StringType str_type> |
| void CopyToEncodedBuffer(char ch, size_t num) ABSL_ATTRIBUTE_NOINLINE; |
| template <StringType str_type> |
| void CopyToEncodedBuffer(std::wstring_view str) ABSL_ATTRIBUTE_NOINLINE; |
| |
| // Copies `field` to the encoded buffer, then appends `str` after it |
| // (truncating `str` if necessary to fit). |
| template <StringType str_type> |
| void CopyToEncodedBufferWithStructuredProtoField(StructuredProtoField field, |
| absl::string_view str) |
| ABSL_ATTRIBUTE_NOINLINE; |
| |
| // Returns `true` if the message is fatal or enabled debug-fatal. |
| bool IsFatal() const; |
| |
| // Records some tombstone-type data in anticipation of `Die`. |
| void PrepareToDie(); |
| void Die(); |
| |
| void SendToLog(); |
| |
| // Checks `FLAGS_log_backtrace_at` and appends a backtrace if appropriate. |
| void LogBacktraceIfNeeded(); |
| |
| // This should be the first data member so that its initializer captures errno |
| // before any other initializers alter it (e.g. with calls to new) and so that |
| // no other destructors run afterward an alter it (e.g. with calls to delete). |
| absl::base_internal::ErrnoSaver errno_saver_; |
| |
| // We keep the data in a separate struct so that each instance of `LogMessage` |
| // uses less stack space. |
| absl_nonnull std::unique_ptr<LogMessageData> data_; |
| }; |
| |
| // Explicitly specializes the generic operator<< for `const wchar_t*` |
| // arguments. |
| // |
| // This method is used instead of a non-template `const wchar_t*` overload, |
| // as the latter was found to take precedence over the array template |
| // (`operator<<(const wchar_t(&)[SIZE])`) when handling string literals. |
| // This specialization ensures the array template now correctly processes |
| // literals. |
| template <> |
| LogMessage& LogMessage::operator<< <const wchar_t*>( |
| const wchar_t* absl_nullable const& v); |
| |
| inline LogMessage& LogMessage::operator<<(wchar_t* absl_nullable v) { |
| return operator<<(const_cast<const wchar_t*>(v)); |
| } |
| |
| // Helper class so that `AbslStringify()` can modify the LogMessage. |
| class StringifySink final { |
| public: |
| explicit StringifySink(LogMessage& message) : message_(message) {} |
| |
| void Append(size_t count, char ch) { |
| message_.CopyToEncodedBuffer<LogMessage::StringType::kNotLiteral>(ch, |
| count); |
| } |
| |
| void Append(absl::string_view v) { |
| message_.CopyToEncodedBuffer<LogMessage::StringType::kNotLiteral>(v); |
| } |
| |
| // For types that implement `AbslStringify` using `absl::Format()`. |
| friend void AbslFormatFlush(StringifySink* absl_nonnull sink, |
| absl::string_view v) { |
| sink->Append(v); |
| } |
| |
| private: |
| LogMessage& message_; |
| }; |
| |
| // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE` |
| template <typename T> |
| LogMessage& LogMessage::operator<<(const T& v) { |
| if constexpr (absl::HasAbslStringify<T>::value) { |
| StringifySink sink(*this); |
| // Replace with public API. |
| AbslStringify(sink, v); |
| } else { |
| OstreamView view(*data_); |
| view.stream() << log_internal::NullGuard<T>().Guard(v); |
| } |
| return *this; |
| } |
| |
| template <int SIZE> |
| LogMessage& LogMessage::operator<<(const char (&buf)[SIZE]) { |
| CopyToEncodedBuffer<StringType::kLiteral>(buf); |
| return *this; |
| } |
| |
| template <int SIZE> |
| LogMessage& LogMessage::operator<<(const wchar_t (&buf)[SIZE]) { |
| CopyToEncodedBuffer<StringType::kLiteral>(buf); |
| return *this; |
| } |
| |
| // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE` |
| template <int SIZE> |
| LogMessage& LogMessage::operator<<(char (&buf)[SIZE]) { |
| CopyToEncodedBuffer<StringType::kNotLiteral>(buf); |
| return *this; |
| } |
| // We instantiate these specializations in the library's TU to save space in |
| // other TUs. Since the template is marked `ABSL_ATTRIBUTE_NOINLINE` we will be |
| // emitting a function call either way. |
| // NOLINTBEGIN(runtime/int) |
| // NOLINTBEGIN(google-runtime-int) |
| extern template LogMessage& LogMessage::operator<<(const char& v); |
| extern template LogMessage& LogMessage::operator<<(const signed char& v); |
| extern template LogMessage& LogMessage::operator<<(const unsigned char& v); |
| extern template LogMessage& LogMessage::operator<<(const short& v); |
| extern template LogMessage& LogMessage::operator<<(const unsigned short& v); |
| extern template LogMessage& LogMessage::operator<<(const int& v); |
| extern template LogMessage& LogMessage::operator<<(const unsigned int& v); |
| extern template LogMessage& LogMessage::operator<<(const long& v); |
| extern template LogMessage& LogMessage::operator<<(const unsigned long& v); |
| extern template LogMessage& LogMessage::operator<<(const long long& v); |
| extern template LogMessage& LogMessage::operator<<(const unsigned long long& v); |
| extern template LogMessage& LogMessage::operator<<( |
| void* absl_nullable const& v); |
| extern template LogMessage& LogMessage::operator<<( |
| const void* absl_nullable const& v); |
| extern template LogMessage& LogMessage::operator<<(const float& v); |
| extern template LogMessage& LogMessage::operator<<(const double& v); |
| extern template LogMessage& LogMessage::operator<<(const bool& v); |
| // NOLINTEND(google-runtime-int) |
| // NOLINTEND(runtime/int) |
| |
| extern template void LogMessage::CopyToEncodedBuffer< |
| LogMessage::StringType::kLiteral>(absl::string_view str); |
| extern template void LogMessage::CopyToEncodedBuffer< |
| LogMessage::StringType::kNotLiteral>(absl::string_view str); |
| extern template void |
| LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>(char ch, |
| size_t num); |
| extern template void LogMessage::CopyToEncodedBuffer< |
| LogMessage::StringType::kNotLiteral>(char ch, size_t num); |
| extern template void LogMessage::CopyToEncodedBuffer< |
| LogMessage::StringType::kLiteral>(std::wstring_view str); |
| extern template void LogMessage::CopyToEncodedBuffer< |
| LogMessage::StringType::kNotLiteral>(std::wstring_view str); |
| |
| // `LogMessageFatal` ensures the process will exit in failure after logging this |
| // message. |
| class LogMessageFatal final : public LogMessage { |
| public: |
| LogMessageFatal(const char* absl_nonnull file, int line) ABSL_ATTRIBUTE_COLD; |
| LogMessageFatal(const char* absl_nonnull file, int line, |
| const char* absl_nonnull failure_msg) ABSL_ATTRIBUTE_COLD; |
| [[noreturn]] ~LogMessageFatal(); |
| }; |
| |
| // `LogMessageDebugFatal` ensures the process will exit in failure after logging |
| // this message. It matches LogMessageFatal but is not [[noreturn]] as it's used |
| // for DLOG(FATAL) variants. |
| class LogMessageDebugFatal final : public LogMessage { |
| public: |
| LogMessageDebugFatal(const char* absl_nonnull file, |
| int line) ABSL_ATTRIBUTE_COLD; |
| ~LogMessageDebugFatal(); |
| }; |
| |
| class LogMessageQuietlyDebugFatal final : public LogMessage { |
| public: |
| // DLOG(QFATAL) calls this instead of LogMessageQuietlyFatal to make sure the |
| // destructor is not [[noreturn]] even if this is always FATAL as this is only |
| // invoked when DLOG() is enabled. |
| LogMessageQuietlyDebugFatal(const char* absl_nonnull file, |
| int line) ABSL_ATTRIBUTE_COLD; |
| ~LogMessageQuietlyDebugFatal(); |
| }; |
| |
| // Used for LOG(QFATAL) to make sure it's properly understood as [[noreturn]]. |
| class LogMessageQuietlyFatal final : public LogMessage { |
| public: |
| LogMessageQuietlyFatal(const char* absl_nonnull file, |
| int line) ABSL_ATTRIBUTE_COLD; |
| LogMessageQuietlyFatal(const char* absl_nonnull file, int line, |
| const char* absl_nonnull failure_msg) |
| ABSL_ATTRIBUTE_COLD; |
| [[noreturn]] ~LogMessageQuietlyFatal(); |
| }; |
| |
| } // namespace log_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| extern "C" ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL( |
| AbslInternalOnFatalLogMessage)(const absl::LogEntry&); |
| |
| #endif // ABSL_LOG_INTERNAL_LOG_MESSAGE_H_ |
| *ì |
| }soong/.intermediates/external/abseil-cpp/absl_base_base_internal_hdrs/gen/my_include_dir/absl/base/internal/scheduling_mode.hê// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // Core interfaces and definitions used by by low-level interfaces such as |
| // SpinLock. |
| |
| #ifndef ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_ |
| #define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_ |
| |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace base_internal { |
| |
| // Used to describe how a thread may be scheduled. Typically associated with |
| // the declaration of a resource supporting synchronized access. |
| // |
| // SCHEDULE_COOPERATIVE_AND_KERNEL: |
| // Specifies that when waiting, a cooperative thread (e.g. a Fiber) may |
| // reschedule (using base::scheduling semantics); allowing other cooperative |
| // threads to proceed. |
| // |
| // SCHEDULE_KERNEL_ONLY: (Also described as "non-cooperative") |
| // Specifies that no cooperative scheduling semantics may be used, even if the |
| // current thread is itself cooperatively scheduled. This means that |
| // cooperative threads will NOT allow other cooperative threads to execute in |
| // their place while waiting for a resource of this type. Host operating system |
| // semantics (e.g. a futex) may still be used. |
| // |
| // When optional, clients should strongly prefer SCHEDULE_COOPERATIVE_AND_KERNEL |
| // by default. SCHEDULE_KERNEL_ONLY should only be used for resources on which |
| // base::scheduling (e.g. the implementation of a Scheduler) may depend. |
| // |
| // NOTE: Cooperative resources may not be nested below non-cooperative ones. |
| // This means that it is invalid to to acquire a SCHEDULE_COOPERATIVE_AND_KERNEL |
| // resource if a SCHEDULE_KERNEL_ONLY resource is already held. |
| enum SchedulingMode { |
| SCHEDULE_KERNEL_ONLY = 0, // Allow scheduling only the host OS. |
| SCHEDULE_COOPERATIVE_AND_KERNEL, // Also allow cooperative scheduling. |
| }; |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_ |
| *] |
| |soong/.intermediates/external/abseil-cpp/absl_log_internal_conditions_hdrs/gen/my_include_dir/absl/log/internal/conditions.h\// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/internal/conditions.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This file contains implementation of conditional log statements, like LOG_IF |
| // including all the ABSL_LOG_INTERNAL_..._CONDITION_... macros and |
| // various condition classes like LogEveryNState. |
| |
| #ifndef ABSL_LOG_INTERNAL_CONDITIONS_H_ |
| #define ABSL_LOG_INTERNAL_CONDITIONS_H_ |
| |
| #if defined(_WIN32) || defined(__hexagon__) |
| #include <cstdlib> |
| #else |
| #include <unistd.h> |
| #endif |
| #include <stdlib.h> |
| |
| #include <atomic> |
| #include <cstdint> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/log/internal/voidify.h" |
| |
| // `ABSL_LOG_INTERNAL_CONDITION` prefixes another macro that expands to a |
| // temporary `LogMessage` instantiation followed by zero or more streamed |
| // expressions. This definition is tricky to read correctly. It evaluates to |
| // either |
| // |
| // (void)0; |
| // |
| // or |
| // |
| // ::absl::log_internal::Voidify() && |
| // ::absl::log_internal::LogMessage(...) << "the user's message"; |
| // |
| // If the condition is evaluable at compile time, as is often the case, it |
| // compiles away to just one side or the other. |
| // |
| // Although this is not used anywhere a statement (e.g. `if`) could not go, |
| // the ternary expression does a better job avoiding spurious diagnostics |
| // (dangling else, missing switch case) and preserving noreturn semantics (e.g. |
| // on `LOG(FATAL)`) without requiring braces. |
| // |
| // The `switch` ensures that this expansion is the beginning of a statement (as |
| // opposed to an expression) and prevents shenanigans like |
| // `AFunction(LOG(INFO))` and `decltype(LOG(INFO))`. The apparently-redundant |
| // `default` case makes the condition more amenable to Clang dataflow analysis. |
| #define ABSL_LOG_INTERNAL_STATELESS_CONDITION(condition) \ |
| switch (0) \ |
| case 0: \ |
| default: \ |
| !(condition) ? (void)0 : ::absl::log_internal::Voidify() && |
| |
| // `ABSL_LOG_INTERNAL_STATEFUL_CONDITION` applies a condition like |
| // `ABSL_LOG_INTERNAL_STATELESS_CONDITION` but adds to that a series of variable |
| // declarations, including a local static object which stores the state needed |
| // to implement the stateful macros like `LOG_EVERY_N`. |
| // |
| // `for`-loops are used to declare scoped variables without braces (to permit |
| // streaming into the macro's expansion) and without the dangling-`else` |
| // problems/diagnostics that come with `if`. |
| // |
| // Two more variables are declared in separate `for`-loops: |
| // |
| // * `COUNTER` implements a streamable token whose value when streamed is the |
| // number of times execution has passed through the macro. |
| // * A boolean flag is used to prevent any of the `for`-loops from ever actually |
| // looping. |
| #define ABSL_LOG_INTERNAL_STATEFUL_CONDITION(condition) \ |
| for (bool absl_log_internal_stateful_condition_do_log(condition); \ |
| absl_log_internal_stateful_condition_do_log; \ |
| absl_log_internal_stateful_condition_do_log = false) \ |
| ABSL_LOG_INTERNAL_STATEFUL_CONDITION_IMPL |
| #define ABSL_LOG_INTERNAL_STATEFUL_CONDITION_IMPL(kind, ...) \ |
| for (static ::absl::log_internal::Log##kind##State \ |
| absl_log_internal_stateful_condition_state; \ |
| absl_log_internal_stateful_condition_do_log && \ |
| absl_log_internal_stateful_condition_state.ShouldLog(__VA_ARGS__); \ |
| absl_log_internal_stateful_condition_do_log = false) \ |
| for (const uint32_t COUNTER ABSL_ATTRIBUTE_UNUSED = \ |
| absl_log_internal_stateful_condition_state.counter(); \ |
| absl_log_internal_stateful_condition_do_log; \ |
| absl_log_internal_stateful_condition_do_log = false) \ |
| ::absl::log_internal::Voidify() && |
| |
| // `ABSL_LOG_INTERNAL_CONDITION_*` serve to combine any conditions from the |
| // macro (e.g. `LOG_IF` or `VLOG`) with inherent conditions (e.g. |
| // `ABSL_MIN_LOG_LEVEL`) into a single boolean expression. We could chain |
| // ternary operators instead, however some versions of Clang sometimes issue |
| // spurious diagnostics after such expressions due to a control flow analysis |
| // bug. |
| #ifdef ABSL_MIN_LOG_LEVEL |
| #define ABSL_LOG_INTERNAL_CONDITION_INFO(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION( \ |
| (condition) && ::absl::LogSeverity::kInfo >= \ |
| static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL)) |
| #define ABSL_LOG_INTERNAL_CONDITION_WARNING(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION( \ |
| (condition) && ::absl::LogSeverity::kWarning >= \ |
| static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL)) |
| #define ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION( \ |
| (condition) && ::absl::LogSeverity::kError >= \ |
| static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL)) |
| #define ABSL_LOG_INTERNAL_CONDITION_DO_NOT_SUBMIT(type, condition) \ |
| ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition) |
| // NOTE: Use ternary operators instead of short-circuiting to mitigate |
| // https://bugs.llvm.org/show_bug.cgi?id=51928. |
| #define ABSL_LOG_INTERNAL_CONDITION_FATAL(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION( \ |
| ((condition) \ |
| ? (::absl::LogSeverity::kFatal >= \ |
| static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) \ |
| ? true \ |
| : (::absl::log_internal::AbortQuietly(), false)) \ |
| : false)) |
| // NOTE: Use ternary operators instead of short-circuiting to mitigate |
| // https://bugs.llvm.org/show_bug.cgi?id=51928. |
| #define ABSL_LOG_INTERNAL_CONDITION_QFATAL(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION( \ |
| ((condition) \ |
| ? (::absl::LogSeverity::kFatal >= \ |
| static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) \ |
| ? true \ |
| : (::absl::log_internal::ExitQuietly(), false)) \ |
| : false)) |
| #define ABSL_LOG_INTERNAL_CONDITION_DFATAL(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION( \ |
| (ABSL_ASSUME(absl::kLogDebugFatal == absl::LogSeverity::kError || \ |
| absl::kLogDebugFatal == absl::LogSeverity::kFatal), \ |
| (condition) && \ |
| (::absl::kLogDebugFatal >= \ |
| static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) || \ |
| (::absl::kLogDebugFatal == ::absl::LogSeverity::kFatal && \ |
| (::absl::log_internal::AbortQuietly(), false))))) |
| |
| #define ABSL_LOG_INTERNAL_CONDITION_LEVEL(severity) \ |
| for (int absl_log_internal_severity_loop = 1; \ |
| absl_log_internal_severity_loop; absl_log_internal_severity_loop = 0) \ |
| for (const absl::LogSeverity absl_log_internal_severity = \ |
| ::absl::NormalizeLogSeverity(severity); \ |
| absl_log_internal_severity_loop; absl_log_internal_severity_loop = 0) \ |
| ABSL_LOG_INTERNAL_CONDITION_LEVEL_IMPL |
| #define ABSL_LOG_INTERNAL_CONDITION_LEVEL_IMPL(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION(( \ |
| (condition) && \ |
| (absl_log_internal_severity >= \ |
| static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) || \ |
| (absl_log_internal_severity == ::absl::LogSeverity::kFatal && \ |
| (::absl::log_internal::AbortQuietly(), false))))) |
| #else // ndef ABSL_MIN_LOG_LEVEL |
| #define ABSL_LOG_INTERNAL_CONDITION_INFO(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION(condition) |
| #define ABSL_LOG_INTERNAL_CONDITION_WARNING(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION(condition) |
| #define ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION(condition) |
| #define ABSL_LOG_INTERNAL_CONDITION_DO_NOT_SUBMIT(type, condition) \ |
| ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition) |
| #define ABSL_LOG_INTERNAL_CONDITION_FATAL(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION(condition) |
| #define ABSL_LOG_INTERNAL_CONDITION_QFATAL(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION(condition) |
| #define ABSL_LOG_INTERNAL_CONDITION_DFATAL(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION(condition) |
| #define ABSL_LOG_INTERNAL_CONDITION_LEVEL(severity) \ |
| for (int absl_log_internal_severity_loop = 1; \ |
| absl_log_internal_severity_loop; absl_log_internal_severity_loop = 0) \ |
| for (const absl::LogSeverity absl_log_internal_severity = \ |
| ::absl::NormalizeLogSeverity(severity); \ |
| absl_log_internal_severity_loop; absl_log_internal_severity_loop = 0) \ |
| ABSL_LOG_INTERNAL_CONDITION_LEVEL_IMPL |
| #define ABSL_LOG_INTERNAL_CONDITION_LEVEL_IMPL(type, condition) \ |
| ABSL_LOG_INTERNAL_##type##_CONDITION(condition) |
| #endif // ndef ABSL_MIN_LOG_LEVEL |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace log_internal { |
| |
| // Stateful condition class name should be "Log" + name + "State". |
| class LogEveryNState final { |
| public: |
| bool ShouldLog(int n); |
| uint32_t counter() { return counter_.load(std::memory_order_relaxed); } |
| |
| private: |
| std::atomic<uint32_t> counter_{0}; |
| }; |
| |
| class LogFirstNState final { |
| public: |
| bool ShouldLog(int n); |
| uint32_t counter() { return counter_.load(std::memory_order_relaxed); } |
| |
| private: |
| std::atomic<uint32_t> counter_{0}; |
| }; |
| |
| class LogEveryPow2State final { |
| public: |
| bool ShouldLog(); |
| uint32_t counter() { return counter_.load(std::memory_order_relaxed); } |
| |
| private: |
| std::atomic<uint32_t> counter_{0}; |
| }; |
| |
| class LogEveryNSecState final { |
| public: |
| bool ShouldLog(double seconds); |
| uint32_t counter() { return counter_.load(std::memory_order_relaxed); } |
| |
| private: |
| std::atomic<uint32_t> counter_{0}; |
| // Cycle count according to CycleClock that we should next log at. |
| std::atomic<int64_t> next_log_time_cycles_{0}; |
| }; |
| |
| // Helper routines to abort the application quietly |
| |
| [[noreturn]] inline void AbortQuietly() { abort(); } |
| [[noreturn]] inline void ExitQuietly() { _exit(1); } |
| } // namespace log_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_LOG_INTERNAL_CONDITIONS_H_ |
| *í |
| hsoong/.intermediates/external/abseil-cpp/absl_base_core_headers_hdrs/gen/my_include_dir/absl/base/port.h// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // This files is a forwarding header for other headers containing various |
| // portability macros and functions. |
| |
| #ifndef ABSL_BASE_PORT_H_ |
| #define ABSL_BASE_PORT_H_ |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/optimization.h" |
| |
| #endif // ABSL_BASE_PORT_H_ |
| *úC |
| jsoong/.intermediates/external/abseil-cpp/absl_base_core_headers_hdrs/gen/my_include_dir/absl/base/macros.hC// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: macros.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines the set of language macros used within Abseil code. |
| // For the set of macros used to determine supported compilers and platforms, |
| // see absl/base/config.h instead. |
| // |
| // This code is compiled directly on many platforms, including client |
| // platforms like Windows, Mac, and embedded systems. Before making |
| // any changes here, make sure that you're not breaking any platforms. |
| |
| #ifndef ABSL_BASE_MACROS_H_ |
| #define ABSL_BASE_MACROS_H_ |
| |
| #include <cassert> |
| #include <cstddef> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/optimization.h" |
| #include "absl/base/options.h" |
| #include "absl/base/port.h" |
| |
| // ABSL_ARRAYSIZE() |
| // |
| // Returns the number of elements in an array as a compile-time constant, which |
| // can be used in defining new arrays. If you use this macro on a pointer by |
| // mistake, you will get a compile-time error. |
| #define ABSL_ARRAYSIZE(array) \ |
| (sizeof(::absl::macros_internal::ArraySizeHelper(array))) |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace macros_internal { |
| // Note: this internal template function declaration is used by ABSL_ARRAYSIZE. |
| // The function doesn't need a definition, as we only use its type. |
| template <typename T, size_t N> |
| auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N]; |
| } // namespace macros_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| // ABSL_BAD_CALL_IF() |
| // |
| // Used on a function overload to trap bad calls: any call that matches the |
| // overload will cause a compile-time error. This macro uses a clang-specific |
| // "enable_if" attribute, as described at |
| // https://clang.llvm.org/docs/AttributeReference.html#enable-if |
| // |
| // Overloads which use this macro should be bracketed by |
| // `#ifdef ABSL_BAD_CALL_IF`. |
| // |
| // Example: |
| // |
| // int isdigit(int c); |
| // #ifdef ABSL_BAD_CALL_IF |
| // int isdigit(int c) |
| // ABSL_BAD_CALL_IF(c <= -1 || c > 255, |
| // "'c' must have the value of an unsigned char or EOF"); |
| // #endif // ABSL_BAD_CALL_IF |
| #if ABSL_HAVE_ATTRIBUTE(enable_if) |
| #define ABSL_BAD_CALL_IF(expr, msg) \ |
| __attribute__((enable_if(expr, "Bad call trap"), unavailable(msg))) |
| #endif |
| |
| // ABSL_ASSERT() |
| // |
| // In C++11, `assert` can't be used portably within constexpr functions. |
| // `assert` also generates spurious unused-symbol warnings. |
| // ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr |
| // functions, and maintains references to symbols. Example: |
| // |
| // constexpr double Divide(double a, double b) { |
| // return ABSL_ASSERT(b != 0), a / b; |
| // } |
| // |
| // This macro is inspired by |
| // https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/ |
| #if defined(NDEBUG) |
| #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L |
| // We use `decltype` here to avoid generating unnecessary code that the |
| // optimizer then has to optimize away. |
| // This not only improves compilation performance by reducing codegen bloat |
| // and optimization work, but also guarantees fast run-time performance without |
| // having to rely on the optimizer. |
| #define ABSL_ASSERT(expr) (decltype((expr) ? void() : void())()) |
| #else |
| // Pre-C++20, lambdas can't be inside unevaluated operands, so we're forced to |
| // rely on the optimizer. |
| #define ABSL_ASSERT(expr) (false ? ((expr) ? void() : void()) : void()) |
| #endif |
| #else |
| #define ABSL_ASSERT(expr) \ |
| (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \ |
| : [] { assert(false && #expr); }()) // NOLINT |
| #endif |
| |
| // `ABSL_INTERNAL_HARDENING_ABORT()` controls how `ABSL_HARDENING_ASSERT()` |
| // aborts the program in release mode (when NDEBUG is defined). The |
| // implementation should abort the program as quickly as possible and ideally it |
| // should not be possible to ignore the abort request. |
| #define ABSL_INTERNAL_HARDENING_ABORT() \ |
| do { \ |
| ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL(); \ |
| ABSL_INTERNAL_UNREACHABLE_IMPL(); \ |
| } while (false) |
| |
| // ABSL_HARDENING_ASSERT() |
| // |
| // `ABSL_HARDENING_ASSERT()` is like `ABSL_ASSERT()`, but used to implement |
| // runtime assertions that should be enabled in hardened builds even when |
| // `NDEBUG` is defined. |
| // |
| // When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT()` is identical to |
| // `ABSL_ASSERT()`. |
| // |
| // See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on |
| // hardened mode. |
| #if (ABSL_OPTION_HARDENED == 1 || ABSL_OPTION_HARDENED == 2) && defined(NDEBUG) |
| #define ABSL_HARDENING_ASSERT(expr) \ |
| (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \ |
| : [] { ABSL_INTERNAL_HARDENING_ABORT(); }()) |
| #else |
| #define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr) |
| #endif |
| |
| // ABSL_HARDENING_ASSERT_SLOW() |
| // |
| // `ABSL_HARDENING_ASSERT()` is like `ABSL_HARDENING_ASSERT()`, |
| // but specifically for assertions whose predicates are too slow |
| // to be enabled in many applications. |
| // |
| // When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT_SLOW()` is identical to |
| // `ABSL_ASSERT()`. |
| // |
| // See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on |
| // hardened mode. |
| #if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG) |
| #define ABSL_HARDENING_ASSERT_SLOW(expr) \ |
| (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \ |
| : [] { ABSL_INTERNAL_HARDENING_ABORT(); }()) |
| #else |
| #define ABSL_HARDENING_ASSERT_SLOW(expr) ABSL_ASSERT(expr) |
| #endif |
| |
| #ifdef ABSL_HAVE_EXCEPTIONS |
| #define ABSL_INTERNAL_TRY try |
| #define ABSL_INTERNAL_CATCH_ANY catch (...) |
| #define ABSL_INTERNAL_RETHROW do { throw; } while (false) |
| #else // ABSL_HAVE_EXCEPTIONS |
| #define ABSL_INTERNAL_TRY if (true) |
| #define ABSL_INTERNAL_CATCH_ANY else if (false) |
| #define ABSL_INTERNAL_RETHROW do {} while (false) |
| #endif // ABSL_HAVE_EXCEPTIONS |
| |
| // ABSL_DEPRECATE_AND_INLINE() |
| // |
| // Marks a function or type alias as deprecated and tags it to be picked up for |
| // automated refactoring by go/cpp-inliner. It can added to inline function |
| // definitions or type aliases. It should only be used within a header file. It |
| // differs from `ABSL_DEPRECATED` in the following ways: |
| // |
| // 1. New uses of the function or type will be discouraged via Tricorder |
| // warnings. |
| // 2. If enabled via `METADATA`, automated changes will be sent out inlining the |
| // functions's body or replacing the type where it is used. |
| // |
| // For example: |
| // |
| // ABSL_DEPRECATE_AND_INLINE() inline int OldFunc(int x) { |
| // return NewFunc(x, 0); |
| // } |
| // |
| // will mark `OldFunc` as deprecated, and the go/cpp-inliner service will |
| // replace calls to `OldFunc(x)` with calls to `NewFunc(x, 0)`. Once all calls |
| // to `OldFunc` have been replaced, `OldFunc` can be deleted. |
| // |
| // See go/cpp-inliner for more information. |
| // |
| // Note: go/cpp-inliner is Google-internal service for automated refactoring. |
| // While open-source users do not have access to this service, the macro is |
| // provided for compatibility, and so that users receive deprecation warnings. |
| #if ABSL_HAVE_CPP_ATTRIBUTE(deprecated) && \ |
| ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) |
| #define ABSL_DEPRECATE_AND_INLINE() [[deprecated, clang::annotate("inline-me")]] |
| #elif ABSL_HAVE_CPP_ATTRIBUTE(deprecated) |
| #define ABSL_DEPRECATE_AND_INLINE() [[deprecated]] |
| #else |
| #define ABSL_DEPRECATE_AND_INLINE() |
| #endif |
| |
| // Requires the compiler to prove that the size of the given object is at least |
| // the expected amount. |
| #if ABSL_HAVE_ATTRIBUTE(diagnose_if) && ABSL_HAVE_BUILTIN(__builtin_object_size) |
| #define ABSL_INTERNAL_NEED_MIN_SIZE(Obj, N) \ |
| __attribute__((diagnose_if(__builtin_object_size(Obj, 0) < N, \ |
| "object size provably too small " \ |
| "(this would corrupt memory)", \ |
| "error"))) |
| #else |
| #define ABSL_INTERNAL_NEED_MIN_SIZE(Obj, N) |
| #endif |
| |
| #endif // ABSL_BASE_MACROS_H_ |
| *
|
| }soong/.intermediates/external/abseil-cpp/absl_base_throw_delegate_hdrs/gen/my_include_dir/absl/base/internal/throw_delegate.h// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #ifndef ABSL_BASE_INTERNAL_THROW_DELEGATE_H_ |
| #define ABSL_BASE_INTERNAL_THROW_DELEGATE_H_ |
| |
| #include <string> |
| |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace base_internal { |
| |
| // Helper functions that allow throwing exceptions consistently from anywhere. |
| // The main use case is for header-based libraries (eg templates), as they will |
| // be built by many different targets with their own compiler options. |
| // In particular, this will allow a safe way to throw exceptions even if the |
| // caller is compiled with -fno-exceptions. This is intended for implementing |
| // things like map<>::at(), which the standard documents as throwing an |
| // exception on error. |
| // |
| // Using other techniques like #if tricks could lead to ODR violations. |
| // |
| // You shouldn't use it unless you're writing code that you know will be built |
| // both with and without exceptions and you need to conform to an interface |
| // that uses exceptions. |
| |
| [[noreturn]] void ThrowStdLogicError(const std::string& what_arg); |
| [[noreturn]] void ThrowStdLogicError(const char* what_arg); |
| [[noreturn]] void ThrowStdInvalidArgument(const std::string& what_arg); |
| [[noreturn]] void ThrowStdInvalidArgument(const char* what_arg); |
| [[noreturn]] void ThrowStdDomainError(const std::string& what_arg); |
| [[noreturn]] void ThrowStdDomainError(const char* what_arg); |
| [[noreturn]] void ThrowStdLengthError(const std::string& what_arg); |
| [[noreturn]] void ThrowStdLengthError(const char* what_arg); |
| [[noreturn]] void ThrowStdOutOfRange(const std::string& what_arg); |
| [[noreturn]] void ThrowStdOutOfRange(const char* what_arg); |
| [[noreturn]] void ThrowStdRuntimeError(const std::string& what_arg); |
| [[noreturn]] void ThrowStdRuntimeError(const char* what_arg); |
| [[noreturn]] void ThrowStdRangeError(const std::string& what_arg); |
| [[noreturn]] void ThrowStdRangeError(const char* what_arg); |
| [[noreturn]] void ThrowStdOverflowError(const std::string& what_arg); |
| [[noreturn]] void ThrowStdOverflowError(const char* what_arg); |
| [[noreturn]] void ThrowStdUnderflowError(const std::string& what_arg); |
| [[noreturn]] void ThrowStdUnderflowError(const char* what_arg); |
| |
| [[noreturn]] void ThrowStdBadFunctionCall(); |
| [[noreturn]] void ThrowStdBadAlloc(); |
| |
| // ThrowStdBadArrayNewLength() cannot be consistently supported because |
| // std::bad_array_new_length is missing in libstdc++ until 4.9.0. |
| // https://gcc.gnu.org/onlinedocs/gcc-4.8.3/libstdc++/api/a01379_source.html |
| // https://gcc.gnu.org/onlinedocs/gcc-4.9.0/libstdc++/api/a01327_source.html |
| // libcxx (as of 3.2) and msvc (as of 2015) both have it. |
| // [[noreturn]] void ThrowStdBadArrayNewLength(); |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_ |
| *^ |
| vsoong/.intermediates/external/abseil-cpp/absl_base_core_headers_hdrs/gen/my_include_dir/absl/base/thread_annotations.h]// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: thread_annotations.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file contains macro definitions for thread safety annotations |
| // that allow developers to document the locking policies of multi-threaded |
| // code. The annotations can also help program analysis tools to identify |
| // potential thread safety issues. |
| // |
| // These annotations are implemented using compiler attributes. Using the macros |
| // defined here instead of raw attributes allow for portability and future |
| // compatibility. |
| // |
| // When referring to mutexes in the arguments of the attributes, you should |
| // use variable names or more complex expressions (e.g. my_object->mutex_) |
| // that evaluate to a concrete mutex object whenever possible. If the mutex |
| // you want to refer to is not in scope, you may use a member pointer |
| // (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object. |
| |
| #ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_ |
| #define ABSL_BASE_THREAD_ANNOTATIONS_H_ |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| |
| // ABSL_GUARDED_BY() |
| // |
| // Documents if a shared field or global variable needs to be protected by a |
| // mutex. ABSL_GUARDED_BY() allows the user to specify a particular mutex that |
| // should be held when accessing the annotated variable. |
| // |
| // Although this annotation (and ABSL_PT_GUARDED_BY, below) cannot be applied to |
| // local variables, a local variable and its associated mutex can often be |
| // combined into a small class or struct, thereby allowing the annotation. |
| // |
| // Example: |
| // |
| // class Foo { |
| // Mutex mu_; |
| // int p1_ ABSL_GUARDED_BY(mu_); |
| // ... |
| // }; |
| #if ABSL_HAVE_ATTRIBUTE(guarded_by) |
| #define ABSL_GUARDED_BY(x) __attribute__((guarded_by(x))) |
| #else |
| #define ABSL_GUARDED_BY(x) |
| #endif |
| |
| // ABSL_PT_GUARDED_BY() |
| // |
| // Documents if the memory location pointed to by a pointer should be guarded |
| // by a mutex when dereferencing the pointer. |
| // |
| // Example: |
| // class Foo { |
| // Mutex mu_; |
| // int *p1_ ABSL_PT_GUARDED_BY(mu_); |
| // ... |
| // }; |
| // |
| // Note that a pointer variable to a shared memory location could itself be a |
| // shared variable. |
| // |
| // Example: |
| // |
| // // `q_`, guarded by `mu1_`, points to a shared memory location that is |
| // // guarded by `mu2_`: |
| // int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_); |
| #if ABSL_HAVE_ATTRIBUTE(pt_guarded_by) |
| #define ABSL_PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x))) |
| #else |
| #define ABSL_PT_GUARDED_BY(x) |
| #endif |
| |
| // ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE() |
| // |
| // Documents the acquisition order between locks that can be held |
| // simultaneously by a thread. For any two locks that need to be annotated |
| // to establish an acquisition order, only one of them needs the annotation. |
| // (i.e. You don't have to annotate both locks with both ABSL_ACQUIRED_AFTER |
| // and ABSL_ACQUIRED_BEFORE.) |
| // |
| // As with ABSL_GUARDED_BY, this is only applicable to mutexes that are shared |
| // fields or global variables. |
| // |
| // Example: |
| // |
| // Mutex m1_; |
| // Mutex m2_ ABSL_ACQUIRED_AFTER(m1_); |
| #if ABSL_HAVE_ATTRIBUTE(acquired_after) |
| #define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__))) |
| #else |
| #define ABSL_ACQUIRED_AFTER(...) |
| #endif |
| |
| #if ABSL_HAVE_ATTRIBUTE(acquired_before) |
| #define ABSL_ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__))) |
| #else |
| #define ABSL_ACQUIRED_BEFORE(...) |
| #endif |
| |
| // ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED() |
| // |
| // Documents a function that expects a mutex to be held prior to entry. |
| // The mutex is expected to be held both on entry to, and exit from, the |
| // function. |
| // |
| // An exclusive lock allows read-write access to the guarded data member(s), and |
| // only one thread can acquire a lock exclusively at any one time. A shared lock |
| // allows read-only access, and any number of threads can acquire a shared lock |
| // concurrently. |
| // |
| // Generally, non-const methods should be annotated with |
| // ABSL_EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with |
| // ABSL_SHARED_LOCKS_REQUIRED. |
| // |
| // Example: |
| // |
| // Mutex mu1, mu2; |
| // int a ABSL_GUARDED_BY(mu1); |
| // int b ABSL_GUARDED_BY(mu2); |
| // |
| // void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... } |
| // void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... } |
| #if ABSL_HAVE_ATTRIBUTE(exclusive_locks_required) |
| #define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \ |
| __attribute__((exclusive_locks_required(__VA_ARGS__))) |
| #else |
| #define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) |
| #endif |
| |
| #if ABSL_HAVE_ATTRIBUTE(shared_locks_required) |
| #define ABSL_SHARED_LOCKS_REQUIRED(...) \ |
| __attribute__((shared_locks_required(__VA_ARGS__))) |
| #else |
| #define ABSL_SHARED_LOCKS_REQUIRED(...) |
| #endif |
| |
| // ABSL_LOCKS_EXCLUDED() |
| // |
| // Documents the locks that cannot be held by callers of this function, as they |
| // might be acquired by this function (Abseil's `Mutex` locks are |
| // non-reentrant). |
| #if ABSL_HAVE_ATTRIBUTE(locks_excluded) |
| #define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__))) |
| #else |
| #define ABSL_LOCKS_EXCLUDED(...) |
| #endif |
| |
| // ABSL_LOCK_RETURNED() |
| // |
| // Documents a function that returns a mutex without acquiring it. For example, |
| // a public getter method that returns a pointer to a private mutex should |
| // be annotated with ABSL_LOCK_RETURNED. |
| #if ABSL_HAVE_ATTRIBUTE(lock_returned) |
| #define ABSL_LOCK_RETURNED(x) __attribute__((lock_returned(x))) |
| #else |
| #define ABSL_LOCK_RETURNED(x) |
| #endif |
| |
| // ABSL_LOCKABLE |
| // |
| // Documents if a class/type is a lockable type (such as the `Mutex` class). |
| #if ABSL_HAVE_ATTRIBUTE(lockable) |
| #define ABSL_LOCKABLE __attribute__((lockable)) |
| #else |
| #define ABSL_LOCKABLE |
| #endif |
| |
| // ABSL_SCOPED_LOCKABLE |
| // |
| // Documents if a class does RAII locking (such as the `MutexLock` class). |
| // The constructor should use `LOCK_FUNCTION()` to specify the mutex that is |
| // acquired, and the destructor should use `UNLOCK_FUNCTION()` with no |
| // arguments; the analysis will assume that the destructor unlocks whatever the |
| // constructor locked. |
| #if ABSL_HAVE_ATTRIBUTE(scoped_lockable) |
| #define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable)) |
| #else |
| #define ABSL_SCOPED_LOCKABLE |
| #endif |
| |
| // ABSL_EXCLUSIVE_LOCK_FUNCTION() |
| // |
| // Documents functions that acquire a lock in the body of a function, and do |
| // not release it. |
| #if ABSL_HAVE_ATTRIBUTE(exclusive_lock_function) |
| #define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \ |
| __attribute__((exclusive_lock_function(__VA_ARGS__))) |
| #else |
| #define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) |
| #endif |
| |
| // ABSL_SHARED_LOCK_FUNCTION() |
| // |
| // Documents functions that acquire a shared (reader) lock in the body of a |
| // function, and do not release it. |
| #if ABSL_HAVE_ATTRIBUTE(shared_lock_function) |
| #define ABSL_SHARED_LOCK_FUNCTION(...) \ |
| __attribute__((shared_lock_function(__VA_ARGS__))) |
| #else |
| #define ABSL_SHARED_LOCK_FUNCTION(...) |
| #endif |
| |
| // ABSL_UNLOCK_FUNCTION() |
| // |
| // Documents functions that expect a lock to be held on entry to the function, |
| // and release it in the body of the function. |
| #if ABSL_HAVE_ATTRIBUTE(unlock_function) |
| #define ABSL_UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__))) |
| #else |
| #define ABSL_UNLOCK_FUNCTION(...) |
| #endif |
| |
| // ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION() |
| // |
| // Documents functions that try to acquire a lock, and return success or failure |
| // (or a non-boolean value that can be interpreted as a boolean). |
| // The first argument should be `true` for functions that return `true` on |
| // success, or `false` for functions that return `false` on success. The second |
| // argument specifies the mutex that is locked on success. If unspecified, this |
| // mutex is assumed to be `this`. |
| #if ABSL_HAVE_ATTRIBUTE(exclusive_trylock_function) |
| #define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \ |
| __attribute__((exclusive_trylock_function(__VA_ARGS__))) |
| #else |
| #define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) |
| #endif |
| |
| #if ABSL_HAVE_ATTRIBUTE(shared_trylock_function) |
| #define ABSL_SHARED_TRYLOCK_FUNCTION(...) \ |
| __attribute__((shared_trylock_function(__VA_ARGS__))) |
| #else |
| #define ABSL_SHARED_TRYLOCK_FUNCTION(...) |
| #endif |
| |
| // ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK() |
| // |
| // Documents functions that dynamically check to see if a lock is held, and fail |
| // if it is not held. |
| #if ABSL_HAVE_ATTRIBUTE(assert_exclusive_lock) |
| #define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \ |
| __attribute__((assert_exclusive_lock(__VA_ARGS__))) |
| #else |
| #define ABSL_ASSERT_EXCLUSIVE_LOCK(...) |
| #endif |
| |
| #if ABSL_HAVE_ATTRIBUTE(assert_shared_lock) |
| #define ABSL_ASSERT_SHARED_LOCK(...) \ |
| __attribute__((assert_shared_lock(__VA_ARGS__))) |
| #else |
| #define ABSL_ASSERT_SHARED_LOCK(...) |
| #endif |
| |
| // ABSL_NO_THREAD_SAFETY_ANALYSIS |
| // |
| // Turns off thread safety checking within the body of a particular function. |
| // This annotation is used to mark functions that are known to be correct, but |
| // the locking behavior is more complicated than the analyzer can handle. |
| #if ABSL_HAVE_ATTRIBUTE(no_thread_safety_analysis) |
| #define ABSL_NO_THREAD_SAFETY_ANALYSIS \ |
| __attribute__((no_thread_safety_analysis)) |
| #else |
| #define ABSL_NO_THREAD_SAFETY_ANALYSIS |
| #endif |
| |
| //------------------------------------------------------------------------------ |
| // Tool-Supplied Annotations |
| //------------------------------------------------------------------------------ |
| |
| // ABSL_TS_UNCHECKED should be placed around lock expressions that are not valid |
| // C++ syntax, but which are present for documentation purposes. These |
| // annotations will be ignored by the analysis. |
| #define ABSL_TS_UNCHECKED(x) "" |
| |
| // ABSL_TS_FIXME is used to mark lock expressions that are not valid C++ syntax. |
| // It is used by automated tools to mark and disable invalid expressions. |
| // The annotation should either be fixed, or changed to ABSL_TS_UNCHECKED. |
| #define ABSL_TS_FIXME(x) "" |
| |
| // Like ABSL_NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body |
| // of a particular function. However, this attribute is used to mark functions |
| // that are incorrect and need to be fixed. It is used by automated tools to |
| // avoid breaking the build when the analysis is updated. |
| // Code owners are expected to eventually fix the routine. |
| #define ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME ABSL_NO_THREAD_SAFETY_ANALYSIS |
| |
| // Similar to ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a |
| // ABSL_GUARDED_BY annotation that needs to be fixed, because it is producing |
| // thread safety warning. It disables the ABSL_GUARDED_BY. |
| #define ABSL_GUARDED_BY_FIXME(x) |
| |
| // Disables warnings for a single read operation. This can be used to avoid |
| // warnings when it is known that the read is not actually involved in a race, |
| // but the compiler cannot confirm that. |
| #define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::ts_unchecked_read(x) |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace base_internal { |
| |
| // Takes a reference to a guarded data member, and returns an unguarded |
| // reference. |
| // Do not use this function directly, use ABSL_TS_UNCHECKED_READ instead. |
| template <typename T> |
| inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS { |
| return v; |
| } |
| |
| template <typename T> |
| inline T& ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS { |
| return v; |
| } |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_THREAD_ANNOTATIONS_H_ |
| *þÔ |
| nsoong/.intermediates/external/abseil-cpp/absl_base_core_headers_hdrs/gen/my_include_dir/absl/base/attributes.hÔ// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // This header file defines macros for declaring attributes for functions, |
| // types, and variables. |
| // |
| // These macros are used within Abseil and allow the compiler to optimize, where |
| // applicable, certain function calls. |
| // |
| // Most macros here are exposing GCC or Clang features, and are stubbed out for |
| // other compilers. |
| // |
| // GCC attributes documentation: |
| // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html |
| // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html |
| // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html |
| // |
| // Most attributes in this file are already supported by GCC 4.7. However, some |
| // of them are not supported in older version of Clang. Thus, we check |
| // `__has_attribute()` first. If the check fails, we check if we are on GCC and |
| // assume the attribute exists on GCC (which is verified on GCC 4.7). |
| |
| // SKIP_ABSL_INLINE_NAMESPACE_CHECK |
| |
| #ifndef ABSL_BASE_ATTRIBUTES_H_ |
| #define ABSL_BASE_ATTRIBUTES_H_ |
| |
| #include "absl/base/config.h" |
| |
| // ABSL_HAVE_ATTRIBUTE |
| // |
| // A function-like feature checking macro that is a wrapper around |
| // `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a |
| // nonzero constant integer if the attribute is supported or 0 if not. |
| // |
| // It evaluates to zero if `__has_attribute` is not defined by the compiler. |
| // |
| // GCC: https://gcc.gnu.org/gcc-5/changes.html |
| // Clang: https://clang.llvm.org/docs/LanguageExtensions.html |
| #ifdef __has_attribute |
| #define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x) |
| #else |
| #define ABSL_HAVE_ATTRIBUTE(x) 0 |
| #endif |
| |
| // ABSL_HAVE_CPP_ATTRIBUTE |
| // |
| // A function-like feature checking macro that accepts C++11 style attributes. |
| // It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6 |
| // (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't |
| // find `__has_cpp_attribute`, will evaluate to 0. |
| #if defined(__cplusplus) && defined(__has_cpp_attribute) |
| // NOTE: requiring __cplusplus above should not be necessary, but |
| // works around https://bugs.llvm.org/show_bug.cgi?id=23435. |
| #define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) |
| #else |
| #define ABSL_HAVE_CPP_ATTRIBUTE(x) 0 |
| #endif |
| |
| // ----------------------------------------------------------------------------- |
| // Function Attributes |
| // ----------------------------------------------------------------------------- |
| // |
| // GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html |
| // Clang: https://clang.llvm.org/docs/AttributeReference.html |
| |
| // ABSL_PRINTF_ATTRIBUTE |
| // ABSL_SCANF_ATTRIBUTE |
| // |
| // Tells the compiler to perform `printf` format string checking if the |
| // compiler supports it; see the 'format' attribute in |
| // <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>. |
| // |
| // Note: As the GCC manual states, "[s]ince non-static C++ methods |
| // have an implicit 'this' argument, the arguments of such methods |
| // should be counted from two, not one." |
| #if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \ |
| __attribute__((__format__(__printf__, string_index, first_to_check))) |
| #define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \ |
| __attribute__((__format__(__scanf__, string_index, first_to_check))) |
| #else |
| #define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) |
| #define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) |
| #endif |
| |
| // ABSL_ATTRIBUTE_ALWAYS_INLINE |
| // ABSL_ATTRIBUTE_NOINLINE |
| // |
| // Forces functions to either inline or not inline. Introduced in gcc 3.1. |
| #if ABSL_HAVE_ATTRIBUTE(always_inline) || \ |
| (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) |
| #define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1 |
| #else |
| #define ABSL_ATTRIBUTE_ALWAYS_INLINE |
| #endif |
| |
| #if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline)) |
| #define ABSL_HAVE_ATTRIBUTE_NOINLINE 1 |
| #else |
| #define ABSL_ATTRIBUTE_NOINLINE |
| #endif |
| |
| // ABSL_ATTRIBUTE_NO_TAIL_CALL |
| // |
| // Prevents the compiler from optimizing away stack frames for functions which |
| // end in a call to another function. |
| #if ABSL_HAVE_ATTRIBUTE(disable_tail_calls) |
| #define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1 |
| #define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls)) |
| #elif defined(__GNUC__) && !defined(__clang__) && !defined(__e2k__) |
| #define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1 |
| #define ABSL_ATTRIBUTE_NO_TAIL_CALL \ |
| __attribute__((optimize("no-optimize-sibling-calls"))) |
| #else |
| #define ABSL_ATTRIBUTE_NO_TAIL_CALL |
| #define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0 |
| #endif |
| |
| // ABSL_ATTRIBUTE_WEAK |
| // |
| // Tags a function as weak for the purposes of compilation and linking. |
| // Weak attributes did not work properly in LLVM's Windows backend before |
| // 9.0.0, so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598 |
| // for further information. Weak attributes do not work across DLL boundary. |
| // The MinGW compiler doesn't complain about the weak attribute until the link |
| // step, presumably because Windows doesn't use ELF binaries. |
| #if (ABSL_HAVE_ATTRIBUTE(weak) || \ |
| (defined(__GNUC__) && !defined(__clang__))) && \ |
| (!defined(_WIN32) || \ |
| (defined(__clang__) && __clang_major__ >= 9 && \ |
| !defined(ABSL_BUILD_DLL) && !defined(ABSL_CONSUME_DLL))) && \ |
| !defined(__MINGW32__) |
| #undef ABSL_ATTRIBUTE_WEAK |
| #define ABSL_ATTRIBUTE_WEAK __attribute__((weak)) |
| #define ABSL_HAVE_ATTRIBUTE_WEAK 1 |
| #else |
| #define ABSL_ATTRIBUTE_WEAK |
| #define ABSL_HAVE_ATTRIBUTE_WEAK 0 |
| #endif |
| |
| // ABSL_ATTRIBUTE_NONNULL |
| // |
| // Tells the compiler either (a) that a particular function parameter |
| // should be a non-null pointer, or (b) that all pointer arguments should |
| // be non-null. |
| // |
| // Note: As the GCC manual states, "[s]ince non-static C++ methods |
| // have an implicit 'this' argument, the arguments of such methods |
| // should be counted from two, not one." |
| // |
| // Args are indexed starting at 1. |
| // |
| // For non-static class member functions, the implicit `this` argument |
| // is arg 1, and the first explicit argument is arg 2. For static class member |
| // functions, there is no implicit `this`, and the first explicit argument is |
| // arg 1. |
| // |
| // Example: |
| // |
| // /* arg_a cannot be null, but arg_b can */ |
| // void Function(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(1); |
| // |
| // class C { |
| // /* arg_a cannot be null, but arg_b can */ |
| // void Method(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(2); |
| // |
| // /* arg_a cannot be null, but arg_b can */ |
| // static void StaticMethod(void* arg_a, void* arg_b) |
| // ABSL_ATTRIBUTE_NONNULL(1); |
| // }; |
| // |
| // If no arguments are provided, then all pointer arguments should be non-null. |
| // |
| // /* No pointer arguments may be null. */ |
| // void Function(void* arg_a, void* arg_b, int arg_c) ABSL_ATTRIBUTE_NONNULL(); |
| // |
| // NOTE: The GCC nonnull attribute actually accepts a list of arguments, but |
| // ABSL_ATTRIBUTE_NONNULL does not. |
| #if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index))) |
| #else |
| #define ABSL_ATTRIBUTE_NONNULL(...) |
| #endif |
| |
| // ABSL_ATTRIBUTE_NORETURN |
| // |
| // Tells the compiler that a given function never returns. |
| // |
| // Deprecated: Prefer the `[[noreturn]]` attribute standardized by C++11 over |
| // this macro. |
| #if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn)) |
| #elif defined(_MSC_VER) |
| #define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn) |
| #else |
| #define ABSL_ATTRIBUTE_NORETURN |
| #endif |
| |
| // ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS |
| // |
| // Tells the AddressSanitizer (or other memory testing tools) to ignore a given |
| // function. Useful for cases when a function reads random locations on stack, |
| // calls _exit from a cloned subprocess, deliberately accesses buffer |
| // out of bounds or does other scary things with memory. |
| // NOTE: GCC supports AddressSanitizer(asan) since 4.8. |
| // https://gcc.gnu.org/gcc-4.8/changes.html |
| #if defined(ABSL_HAVE_ADDRESS_SANITIZER) && \ |
| ABSL_HAVE_ATTRIBUTE(no_sanitize_address) |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) |
| #elif defined(ABSL_HAVE_ADDRESS_SANITIZER) && defined(_MSC_VER) && \ |
| _MSC_VER >= 1928 |
| // https://docs.microsoft.com/en-us/cpp/cpp/no-sanitize-address |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __declspec(no_sanitize_address) |
| #elif defined(ABSL_HAVE_HWADDRESS_SANITIZER) && ABSL_HAVE_ATTRIBUTE(no_sanitize) |
| // HWAddressSanitizer is a sanitizer similar to AddressSanitizer, which uses CPU |
| // features to detect similar bugs with less CPU and memory overhead. |
| // NOTE: GCC supports HWAddressSanitizer(hwasan) since 11. |
| // https://gcc.gnu.org/gcc-11/changes.html |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS \ |
| __attribute__((no_sanitize("hwaddress"))) |
| #else |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS |
| #endif |
| |
| // ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY |
| // |
| // Tells the MemorySanitizer to relax the handling of a given function. All "Use |
| // of uninitialized value" warnings from such functions will be suppressed, and |
| // all values loaded from memory will be considered fully initialized. This |
| // attribute is similar to the ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS attribute |
| // above, but deals with initialized-ness rather than addressability issues. |
| // NOTE: MemorySanitizer(msan) is supported by Clang but not GCC. |
| #if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory) |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) |
| #else |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY |
| #endif |
| |
| // ABSL_ATTRIBUTE_NO_SANITIZE_THREAD |
| // |
| // Tells the ThreadSanitizer to not instrument a given function. |
| // NOTE: GCC supports ThreadSanitizer(tsan) since 4.8. |
| // https://gcc.gnu.org/gcc-4.8/changes.html |
| #if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread) |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread)) |
| #else |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD |
| #endif |
| |
| // ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED |
| // |
| // Tells the UndefinedSanitizer to ignore a given function. Useful for cases |
| // where certain behavior (eg. division by zero) is being used intentionally. |
| // NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9. |
| // https://gcc.gnu.org/gcc-4.9/changes.html |
| #if ABSL_HAVE_ATTRIBUTE(no_sanitize_undefined) |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \ |
| __attribute__((no_sanitize_undefined)) |
| #elif ABSL_HAVE_ATTRIBUTE(no_sanitize) |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \ |
| __attribute__((no_sanitize("undefined"))) |
| #else |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED |
| #endif |
| |
| // Android local modification: add attribute for disabling unsigned overflow |
| // sanitization for code where it's intentional, to support vendor code that |
| // enables it. |
| #if ABSL_HAVE_ATTRIBUTE(no_sanitize) |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_UNSIGNED_OVERFLOW \ |
| __attribute__((no_sanitize("unsigned-integer-overflow"))) |
| #else |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_UNSIGNED_OVERFLOW |
| #endif |
| |
| // ABSL_ATTRIBUTE_NO_SANITIZE_CFI |
| // |
| // Tells the ControlFlowIntegrity sanitizer to not instrument a given function. |
| // See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details. |
| #if ABSL_HAVE_ATTRIBUTE(no_sanitize) && defined(__llvm__) |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi"))) |
| #else |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI |
| #endif |
| |
| // ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK |
| // |
| // Tells the SafeStack to not instrument a given function. |
| // See https://clang.llvm.org/docs/SafeStack.html for details. |
| #if ABSL_HAVE_ATTRIBUTE(no_sanitize) |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \ |
| __attribute__((no_sanitize("safe-stack"))) |
| #else |
| #define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK |
| #endif |
| |
| // ABSL_ATTRIBUTE_RETURNS_NONNULL |
| // |
| // Tells the compiler that a particular function never returns a null pointer. |
| #if ABSL_HAVE_ATTRIBUTE(returns_nonnull) |
| #define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull)) |
| #else |
| #define ABSL_ATTRIBUTE_RETURNS_NONNULL |
| #endif |
| |
| // ABSL_HAVE_ATTRIBUTE_SECTION |
| // |
| // Indicates whether labeled sections are supported. Weak symbol support is |
| // a prerequisite. Labeled sections are not supported on Darwin/iOS. |
| #ifdef ABSL_HAVE_ATTRIBUTE_SECTION |
| #error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set |
| #elif (ABSL_HAVE_ATTRIBUTE(section) || \ |
| (defined(__GNUC__) && !defined(__clang__))) && \ |
| !defined(__APPLE__) && ABSL_HAVE_ATTRIBUTE_WEAK |
| #define ABSL_HAVE_ATTRIBUTE_SECTION 1 |
| |
| // ABSL_ATTRIBUTE_SECTION |
| // |
| // Tells the compiler/linker to put a given function into a section and define |
| // `__start_ ## name` and `__stop_ ## name` symbols to bracket the section. |
| // This functionality is supported by GNU linker. Any function annotated with |
| // `ABSL_ATTRIBUTE_SECTION` must not be inlined, or it will be placed into |
| // whatever section its caller is placed into. |
| // |
| #ifndef ABSL_ATTRIBUTE_SECTION |
| #define ABSL_ATTRIBUTE_SECTION(name) \ |
| __attribute__((section(#name))) __attribute__((noinline)) |
| #endif |
| |
| // ABSL_ATTRIBUTE_SECTION_VARIABLE |
| // |
| // Tells the compiler/linker to put a given variable into a section and define |
| // `__start_ ## name` and `__stop_ ## name` symbols to bracket the section. |
| // This functionality is supported by GNU linker. |
| #ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE |
| #ifdef _AIX |
| // __attribute__((section(#name))) on AIX is achieved by using the `.csect` |
| // pseudo op which includes an additional integer as part of its syntax |
| // indicating alignment. If data fall under different alignments then you might |
| // get a compilation error indicating a `Section type conflict`. |
| #define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) |
| #else |
| #define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name))) |
| #endif |
| #endif |
| |
| // ABSL_DECLARE_ATTRIBUTE_SECTION_VARS |
| // |
| // A weak section declaration to be used as a global declaration |
| // for ABSL_ATTRIBUTE_SECTION_START|STOP(name) to compile and link |
| // even without functions with ABSL_ATTRIBUTE_SECTION(name). |
| // ABSL_DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's |
| // a no-op on ELF but not on Mach-O. |
| // |
| #ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS |
| #define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \ |
| extern char __start_##name[] ABSL_ATTRIBUTE_WEAK; \ |
| extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK |
| #endif |
| #ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS |
| #define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name) |
| #define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name) |
| #endif |
| |
| // ABSL_ATTRIBUTE_SECTION_START |
| // |
| // Returns `void*` pointers to start/end of a section of code with |
| // functions having ABSL_ATTRIBUTE_SECTION(name). |
| // Returns 0 if no such functions exist. |
| // One must ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and |
| // link. |
| // |
| #define ABSL_ATTRIBUTE_SECTION_START(name) \ |
| (reinterpret_cast<void *>(__start_##name)) |
| #define ABSL_ATTRIBUTE_SECTION_STOP(name) \ |
| (reinterpret_cast<void *>(__stop_##name)) |
| |
| #else // !ABSL_HAVE_ATTRIBUTE_SECTION |
| |
| #define ABSL_HAVE_ATTRIBUTE_SECTION 0 |
| |
| // provide dummy definitions |
| #define ABSL_ATTRIBUTE_SECTION(name) |
| #define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) |
| #define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name) |
| #define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name) |
| #define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) |
| #define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0)) |
| #define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0)) |
| |
| #endif // ABSL_ATTRIBUTE_SECTION |
| |
| // ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC |
| // |
| // Support for aligning the stack on 32-bit x86. |
| #if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || \ |
| (defined(__GNUC__) && !defined(__clang__)) |
| #if defined(__i386__) |
| #define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \ |
| __attribute__((force_align_arg_pointer)) |
| #define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0) |
| #elif defined(__x86_64__) |
| #define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1) |
| #define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC |
| #else // !__i386__ && !__x86_64 |
| #define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0) |
| #define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC |
| #endif // __i386__ |
| #else |
| #define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC |
| #define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0) |
| #endif |
| |
| // ABSL_MUST_USE_RESULT |
| // |
| // Tells the compiler to warn about unused results. |
| // |
| // For code or headers that are assured to only build with C++17 and up, prefer |
| // just using the standard `[[nodiscard]]` directly over this macro. |
| // |
| // When annotating a function, it must appear as the first part of the |
| // declaration or definition. The compiler will warn if the return value from |
| // such a function is unused: |
| // |
| // ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket(); |
| // AllocateSprocket(); // Triggers a warning. |
| // |
| // When annotating a class, it is equivalent to annotating every function which |
| // returns an instance. |
| // |
| // class ABSL_MUST_USE_RESULT Sprocket {}; |
| // Sprocket(); // Triggers a warning. |
| // |
| // Sprocket MakeSprocket(); |
| // MakeSprocket(); // Triggers a warning. |
| // |
| // Note that references and pointers are not instances: |
| // |
| // Sprocket* SprocketPointer(); |
| // SprocketPointer(); // Does *not* trigger a warning. |
| // |
| // ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result |
| // warning. For that, warn_unused_result is used only for clang but not for gcc. |
| // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 |
| // |
| // Note: past advice was to place the macro after the argument list. |
| // |
| // TODO(b/176172494): Use ABSL_HAVE_CPP_ATTRIBUTE(nodiscard) when all code is |
| // compliant with the stricter [[nodiscard]]. |
| #if defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result) |
| #define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result)) |
| #else |
| #define ABSL_MUST_USE_RESULT |
| #endif |
| |
| // ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD |
| // |
| // Tells GCC that a function is hot or cold. GCC can use this information to |
| // improve static analysis, i.e. a conditional branch to a cold function |
| // is likely to be not-taken. |
| // This annotation is used for function declarations. |
| // |
| // Example: |
| // |
| // int foo() ABSL_ATTRIBUTE_HOT; |
| #if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_ATTRIBUTE_HOT __attribute__((hot)) |
| #else |
| #define ABSL_ATTRIBUTE_HOT |
| #endif |
| |
| #if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_ATTRIBUTE_COLD __attribute__((cold)) |
| #else |
| #define ABSL_ATTRIBUTE_COLD |
| #endif |
| |
| // ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS |
| // |
| // We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT |
| // macro used as an attribute to mark functions that must always or never be |
| // instrumented by XRay. Currently, this is only supported in Clang/LLVM. |
| // |
| // For reference on the LLVM XRay instrumentation, see |
| // http://llvm.org/docs/XRay.html. |
| // |
| // A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration |
| // will always get the XRay instrumentation sleds. These sleds may introduce |
| // some binary size and runtime overhead and must be used sparingly. |
| // |
| // These attributes only take effect when the following conditions are met: |
| // |
| // * The file/target is built in at least C++11 mode, with a Clang compiler |
| // that supports XRay attributes. |
| // * The file/target is built with the -fxray-instrument flag set for the |
| // Clang/LLVM compiler. |
| // * The function is defined in the translation unit (the compiler honors the |
| // attribute in either the definition or the declaration, and must match). |
| // |
| // There are cases when, even when building with XRay instrumentation, users |
| // might want to control specifically which functions are instrumented for a |
| // particular build using special-case lists provided to the compiler. These |
| // special case lists are provided to Clang via the |
| // -fxray-always-instrument=... and -fxray-never-instrument=... flags. The |
| // attributes in source take precedence over these special-case lists. |
| // |
| // To disable the XRay attributes at build-time, users may define |
| // ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific |
| // packages/targets, as this may lead to conflicting definitions of functions at |
| // link-time. |
| // |
| // XRay isn't currently supported on Android: |
| // https://github.com/android/ndk/issues/368 |
| #if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \ |
| !defined(ABSL_NO_XRAY_ATTRIBUTES) && !defined(__ANDROID__) |
| #define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]] |
| #define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]] |
| #if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args) |
| #define ABSL_XRAY_LOG_ARGS(N) \ |
| [[clang::xray_always_instrument, clang::xray_log_args(N)]] |
| #else |
| #define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]] |
| #endif |
| #else |
| #define ABSL_XRAY_ALWAYS_INSTRUMENT |
| #define ABSL_XRAY_NEVER_INSTRUMENT |
| #define ABSL_XRAY_LOG_ARGS(N) |
| #endif |
| |
| // ABSL_ATTRIBUTE_REINITIALIZES |
| // |
| // Indicates that a member function reinitializes the entire object to a known |
| // state, independent of the previous state of the object. |
| // |
| // The clang-tidy check bugprone-use-after-move allows member functions marked |
| // with this attribute to be called on objects that have been moved from; |
| // without the attribute, this would result in a use-after-move warning. |
| #if ABSL_HAVE_CPP_ATTRIBUTE(clang::reinitializes) |
| #define ABSL_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]] |
| #else |
| #define ABSL_ATTRIBUTE_REINITIALIZES |
| #endif |
| |
| // ----------------------------------------------------------------------------- |
| // Variable Attributes |
| // ----------------------------------------------------------------------------- |
| |
| // ABSL_ATTRIBUTE_UNUSED |
| // |
| // Prevents the compiler from complaining about variables that appear unused. |
| // |
| // Deprecated: Use the standard C++17 `[[maybe_unused]` instead. |
| // |
| // Due to differences in positioning requirements between the old, compiler |
| // specific __attribute__ syntax and the now standard `[[maybe_unused]]`, this |
| // macro does not attempt to take advantage of `[[maybe_unused]]`. |
| #if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__)) |
| #undef ABSL_ATTRIBUTE_UNUSED |
| #define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__)) |
| #else |
| #define ABSL_ATTRIBUTE_UNUSED |
| #endif |
| |
| // ABSL_ATTRIBUTE_INITIAL_EXEC |
| // |
| // Tells the compiler to use "initial-exec" mode for a thread-local variable. |
| // See http://people.redhat.com/drepper/tls.pdf for the gory details. |
| #if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec"))) |
| #else |
| #define ABSL_ATTRIBUTE_INITIAL_EXEC |
| #endif |
| |
| // ABSL_ATTRIBUTE_PACKED |
| // |
| // Instructs the compiler not to use natural alignment for a tagged data |
| // structure, but instead to reduce its alignment to 1. |
| // |
| // Therefore, DO NOT APPLY THIS ATTRIBUTE TO STRUCTS CONTAINING ATOMICS. Doing |
| // so can cause atomic variables to be mis-aligned and silently violate |
| // atomicity on x86. |
| // |
| // This attribute can either be applied to members of a structure or to a |
| // structure in its entirety. Applying this attribute (judiciously) to a |
| // structure in its entirety to optimize the memory footprint of very |
| // commonly-used structs is fine. Do not apply this attribute to a structure in |
| // its entirety if the purpose is to control the offsets of the members in the |
| // structure. Instead, apply this attribute only to structure members that need |
| // it. |
| // |
| // When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the |
| // natural alignment of structure members not annotated is preserved. Aligned |
| // member accesses are faster than non-aligned member accesses even if the |
| // targeted microprocessor supports non-aligned accesses. |
| #if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__)) |
| #else |
| #define ABSL_ATTRIBUTE_PACKED |
| #endif |
| |
| // ABSL_ATTRIBUTE_FUNC_ALIGN |
| // |
| // Tells the compiler to align the function start at least to certain |
| // alignment boundary |
| #if ABSL_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes))) |
| #else |
| #define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) |
| #endif |
| |
| // ABSL_FALLTHROUGH_INTENDED |
| // |
| // Annotates implicit fall-through between switch labels, allowing a case to |
| // indicate intentional fallthrough and turn off warnings about any lack of a |
| // `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by |
| // a semicolon and can be used in most places where `break` can, provided that |
| // no statements exist between it and the next switch label. |
| // |
| // Example: |
| // |
| // switch (x) { |
| // case 40: |
| // case 41: |
| // if (truth_is_out_there) { |
| // ++x; |
| // ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations |
| // // in comments |
| // } else { |
| // return x; |
| // } |
| // case 42: |
| // ... |
| // |
| // Notes: When supported, GCC and Clang can issue a warning on switch labels |
| // with unannotated fallthrough using the warning `-Wimplicit-fallthrough`. See |
| // clang documentation on language extensions for details: |
| // https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough |
| // |
| // When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro has |
| // no effect on diagnostics. In any case this macro has no effect on runtime |
| // behavior and performance of code. |
| |
| #ifdef ABSL_FALLTHROUGH_INTENDED |
| #error "ABSL_FALLTHROUGH_INTENDED should not be defined." |
| #elif ABSL_HAVE_CPP_ATTRIBUTE(fallthrough) |
| #define ABSL_FALLTHROUGH_INTENDED [[fallthrough]] |
| #elif ABSL_HAVE_CPP_ATTRIBUTE(clang::fallthrough) |
| #define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]] |
| #elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::fallthrough) |
| #define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]] |
| #else |
| #define ABSL_FALLTHROUGH_INTENDED \ |
| do { \ |
| } while (0) |
| #endif |
| |
| // ABSL_DEPRECATED() |
| // |
| // Marks a deprecated class, struct, enum, function, method and variable |
| // declarations. The macro argument is used as a custom diagnostic message (e.g. |
| // suggestion of a better alternative). |
| // |
| // For code or headers that are assured to only build with C++14 and up, prefer |
| // just using the standard `[[deprecated("message")]]` directly over this macro. |
| // |
| // Examples: |
| // |
| // class ABSL_DEPRECATED("Use Bar instead") Foo {...}; |
| // |
| // ABSL_DEPRECATED("Use Baz() instead") void Bar() {...} |
| // |
| // template <typename T> |
| // ABSL_DEPRECATED("Use DoThat() instead") |
| // void DoThis(); |
| // |
| // enum FooEnum { |
| // kBar ABSL_DEPRECATED("Use kBaz instead"), |
| // }; |
| // |
| // Every usage of a deprecated entity will trigger a warning when compiled with |
| // GCC/Clang's `-Wdeprecated-declarations` option. Google's production toolchain |
| // turns this warning off by default, instead relying on clang-tidy to report |
| // new uses of deprecated code. |
| #if ABSL_HAVE_ATTRIBUTE(deprecated) |
| #define ABSL_DEPRECATED(message) __attribute__((deprecated(message))) |
| #else |
| #define ABSL_DEPRECATED(message) |
| #endif |
| |
| // When deprecating Abseil code, it is sometimes necessary to turn off the |
| // warning within Abseil, until the deprecated code is actually removed. The |
| // deprecated code can be surrounded with these directives to achieve that |
| // result. |
| // |
| // class ABSL_DEPRECATED("Use Bar instead") Foo; |
| // |
| // ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING |
| // Baz ComputeBazFromFoo(Foo f); |
| // ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING |
| #if defined(__GNUC__) || defined(__clang__) |
| // Clang also supports these GCC pragmas. |
| #define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING \ |
| _Pragma("GCC diagnostic push") \ |
| _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") |
| #define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING \ |
| _Pragma("GCC diagnostic pop") |
| #elif defined(_MSC_VER) |
| #define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING \ |
| _Pragma("warning(push)") _Pragma("warning(disable: 4996)") |
| #define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING \ |
| _Pragma("warning(pop)") |
| #else |
| #define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING |
| #define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING |
| #endif // defined(__GNUC__) || defined(__clang__) |
| |
| // ABSL_CONST_INIT |
| // |
| // A variable declaration annotated with the `ABSL_CONST_INIT` attribute will |
| // not compile (on supported platforms) unless the variable has a constant |
| // initializer. This is useful for variables with static and thread storage |
| // duration, because it guarantees that they will not suffer from the so-called |
| // "static init order fiasco". |
| // |
| // This attribute must be placed on the initializing declaration of the |
| // variable. Some compilers will give a -Wmissing-constinit warning when this |
| // attribute is placed on some other declaration but missing from the |
| // initializing declaration. |
| // |
| // In some cases (notably with thread_local variables), `ABSL_CONST_INIT` can |
| // also be used in a non-initializing declaration to tell the compiler that a |
| // variable is already initialized, reducing overhead that would otherwise be |
| // incurred by a hidden guard variable. Thus annotating all declarations with |
| // this attribute is recommended to potentially enhance optimization. |
| // |
| // Example: |
| // |
| // class MyClass { |
| // public: |
| // ABSL_CONST_INIT static MyType my_var; |
| // }; |
| // |
| // ABSL_CONST_INIT MyType MyClass::my_var = MakeMyType(...); |
| // |
| // For code or headers that are assured to only build with C++20 and up, prefer |
| // just using the standard `constinit` keyword directly over this macro. |
| // |
| // Note that this attribute is redundant if the variable is declared constexpr. |
| #if defined(__cpp_constinit) && __cpp_constinit >= 201907L |
| #define ABSL_CONST_INIT constinit |
| #elif ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization) |
| #define ABSL_CONST_INIT [[clang::require_constant_initialization]] |
| #else |
| #define ABSL_CONST_INIT |
| #endif |
| |
| // ABSL_REQUIRE_EXPLICIT_INIT |
| // |
| // ABSL_REQUIRE_EXPLICIT_INIT is placed *after* the data members of an aggregate |
| // type to indicate that the annotated member must be explicitly initialized by |
| // the user whenever the aggregate is constructed. For example: |
| // |
| // struct Coord { |
| // int x ABSL_REQUIRE_EXPLICIT_INIT; |
| // int y ABSL_REQUIRE_EXPLICIT_INIT; |
| // }; |
| // Coord coord = {1}; // warning: field 'y' is not explicitly initialized |
| // |
| // Note that usage on C arrays is not supported in C++. |
| // Use a struct (such as std::array) to wrap the array member instead. |
| // |
| // Avoid applying this attribute to the members of non-aggregate types. |
| // The behavior within non-aggregates is unspecified and subject to change. |
| // |
| // Do NOT attempt to suppress or demote the error generated by this attribute. |
| // Just like with a missing function argument, it is a hard error by design. |
| // |
| // See the upstream documentation for more details: |
| // https://clang.llvm.org/docs/AttributeReference.html#require-explicit-initialization |
| #ifdef __cplusplus |
| #if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_explicit_initialization) |
| // clang-format off |
| #define ABSL_REQUIRE_EXPLICIT_INIT \ |
| [[clang::require_explicit_initialization]] = \ |
| AbslInternal_YouForgotToExplicitlyInitializeAField::v |
| #else |
| #define ABSL_REQUIRE_EXPLICIT_INIT \ |
| = AbslInternal_YouForgotToExplicitlyInitializeAField::v |
| #endif |
| // clang-format on |
| #else |
| // clang-format off |
| #if ABSL_HAVE_ATTRIBUTE(require_explicit_initialization) |
| #define ABSL_REQUIRE_EXPLICIT_INIT \ |
| __attribute__((require_explicit_initialization)) |
| #else |
| #define ABSL_REQUIRE_EXPLICIT_INIT \ |
| /* No portable fallback for C is available */ |
| #endif |
| // clang-format on |
| #endif |
| |
| #ifdef __cplusplus |
| struct AbslInternal_YouForgotToExplicitlyInitializeAField { |
| // A portable version of [[clang::require_explicit_initialization]] that |
| // never builds, as a last resort for all toolchains. |
| // The error messages are poor, so we don't rely on this unless we have to. |
| template <class T> |
| #if !defined(SWIG) |
| constexpr |
| #endif |
| operator T() const /* NOLINT */ { |
| const void *volatile deliberately_volatile_ptr = nullptr; |
| // Infinite loop to prevent constexpr compilation |
| for (;;) { |
| // This assignment ensures the 'this' pointer is not optimized away, so |
| // that linking always fails. |
| deliberately_volatile_ptr = this; // Deliberately not constexpr |
| (void)deliberately_volatile_ptr; |
| } |
| } |
| // This is deliberately left undefined to prevent linking |
| static AbslInternal_YouForgotToExplicitlyInitializeAField v; |
| }; |
| #endif |
| |
| // ABSL_ATTRIBUTE_PURE_FUNCTION |
| // |
| // ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure" |
| // functions. A function is pure if its return value is only a function of its |
| // arguments. The pure attribute prohibits a function from modifying the state |
| // of the program that is observable by means other than inspecting the |
| // function's return value. Declaring such functions with the pure attribute |
| // allows the compiler to avoid emitting some calls in repeated invocations of |
| // the function with the same argument values. |
| // |
| // Example: |
| // |
| // ABSL_ATTRIBUTE_PURE_FUNCTION std::string FormatTime(Time t); |
| #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 |
| // If the attribute isn't defined, we'll fallback to ABSL_MUST_USE_RESULT since |
| // pure functions are useless if its return is ignored. |
| #define ABSL_ATTRIBUTE_PURE_FUNCTION ABSL_MUST_USE_RESULT |
| #endif |
| |
| // ABSL_ATTRIBUTE_CONST_FUNCTION |
| // |
| // ABSL_ATTRIBUTE_CONST_FUNCTION is used to annotate declarations of "const" |
| // functions. A const function is similar to a pure function, with one |
| // exception: Pure functions may return value that depend on a non-volatile |
| // object that isn't provided as a function argument, while the const function |
| // is guaranteed to return the same result given the same arguments. |
| // |
| // Example: |
| // |
| // ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Milliseconds(Duration d); |
| #if defined(_MSC_VER) && !defined(__clang__) |
| // Put the MSVC case first since MSVC seems to parse const as a C++ keyword. |
| #define ABSL_ATTRIBUTE_CONST_FUNCTION ABSL_ATTRIBUTE_PURE_FUNCTION |
| #elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::const) |
| #define ABSL_ATTRIBUTE_CONST_FUNCTION [[gnu::const]] |
| #elif ABSL_HAVE_ATTRIBUTE(const) |
| #define ABSL_ATTRIBUTE_CONST_FUNCTION __attribute__((const)) |
| #else |
| // Since const functions are more restrictive pure function, we'll fallback to a |
| // pure function if the const attribute is not handled. |
| #define ABSL_ATTRIBUTE_CONST_FUNCTION 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 |
| // https://learn.microsoft.com/en-us/cpp/code-quality/c26816?view=msvc-170 |
| #if ABSL_HAVE_CPP_ATTRIBUTE(clang::lifetimebound) |
| #define ABSL_ATTRIBUTE_LIFETIME_BOUND [[clang::lifetimebound]] |
| #elif ABSL_HAVE_CPP_ATTRIBUTE(msvc::lifetimebound) |
| #define ABSL_ATTRIBUTE_LIFETIME_BOUND [[msvc::lifetimebound]] |
| #elif ABSL_HAVE_ATTRIBUTE(lifetimebound) |
| #define ABSL_ATTRIBUTE_LIFETIME_BOUND __attribute__((lifetimebound)) |
| #else |
| #define ABSL_ATTRIBUTE_LIFETIME_BOUND |
| #endif |
| |
| // Internal attribute; name and documentation TBD. |
| // |
| // See the upstream documentation: |
| // https://clang.llvm.org/docs/AttributeReference.html#lifetime_capture_by |
| #if ABSL_HAVE_CPP_ATTRIBUTE(clang::lifetime_capture_by) |
| #define ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(Owner) \ |
| [[clang::lifetime_capture_by(Owner)]] |
| #else |
| #define ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(Owner) |
| #endif |
| |
| // ABSL_ATTRIBUTE_VIEW indicates that a type is solely a "view" of data that it |
| // points to, similarly to a span, string_view, or other non-owning reference |
| // type. |
| // This enables diagnosing certain lifetime issues similar to those enabled by |
| // ABSL_ATTRIBUTE_LIFETIME_BOUND, such as: |
| // |
| // struct ABSL_ATTRIBUTE_VIEW StringView { |
| // template<class R> |
| // StringView(const R&); |
| // }; |
| // |
| // StringView f(std::string s) { |
| // return s; // warning: address of stack memory returned |
| // } |
| // |
| // We disable this on Clang versions < 13 because of the following |
| // false-positive: |
| // |
| // absl::string_view f(absl::optional<absl::string_view> sv) { return *sv; } |
| // |
| // See the following links for details: |
| // https://reviews.llvm.org/D64448 |
| // https://lists.llvm.org/pipermail/cfe-dev/2018-November/060355.html |
| #if ABSL_HAVE_CPP_ATTRIBUTE(gsl::Pointer) && \ |
| (!defined(__clang_major__) || __clang_major__ >= 13) |
| #define ABSL_ATTRIBUTE_VIEW [[gsl::Pointer]] |
| #else |
| #define ABSL_ATTRIBUTE_VIEW |
| #endif |
| |
| // ABSL_ATTRIBUTE_OWNER indicates that a type is a container, smart pointer, or |
| // similar class that owns all the data that it points to. |
| // This enables diagnosing certain lifetime issues similar to those enabled by |
| // ABSL_ATTRIBUTE_LIFETIME_BOUND, such as: |
| // |
| // struct ABSL_ATTRIBUTE_VIEW StringView { |
| // template<class R> |
| // StringView(const R&); |
| // }; |
| // |
| // struct ABSL_ATTRIBUTE_OWNER String {}; |
| // |
| // StringView f(String s) { |
| // return s; // warning: address of stack memory returned |
| // } |
| // |
| // We disable this on Clang versions < 13 because of the following |
| // false-positive: |
| // |
| // absl::string_view f(absl::optional<absl::string_view> sv) { return *sv; } |
| // |
| // See the following links for details: |
| // https://reviews.llvm.org/D64448 |
| // https://lists.llvm.org/pipermail/cfe-dev/2018-November/060355.html |
| #if ABSL_HAVE_CPP_ATTRIBUTE(gsl::Owner) && \ |
| (!defined(__clang_major__) || __clang_major__ >= 13) |
| #define ABSL_ATTRIBUTE_OWNER [[gsl::Owner]] |
| #else |
| #define ABSL_ATTRIBUTE_OWNER |
| #endif |
| |
| // ABSL_ATTRIBUTE_TRIVIAL_ABI |
| // Indicates that a type is "trivially relocatable" -- meaning it can be |
| // relocated without invoking the constructor/destructor, using a form of move |
| // elision. |
| // |
| // From a memory safety point of view, putting aside destructor ordering, it's |
| // safe to apply ABSL_ATTRIBUTE_TRIVIAL_ABI if an object's location |
| // can change over the course of its lifetime: if a constructor can be run one |
| // place, and then the object magically teleports to another place where some |
| // methods are run, and then the object teleports to yet another place where it |
| // is destroyed. This is notably not true for self-referential types, where the |
| // move-constructor must keep the self-reference up to date. If the type changed |
| // location without invoking the move constructor, it would have a dangling |
| // self-reference. |
| // |
| // The use of this teleporting machinery means that the number of paired |
| // move/destroy operations can change, and so it is a bad idea to apply this to |
| // a type meant to count the number of moves. |
| // |
| // Warning: applying this can, rarely, break callers. Objects passed by value |
| // will be destroyed at the end of the call, instead of the end of the |
| // full-expression containing the call. In addition, it changes the ABI |
| // of functions accepting this type by value (e.g. to pass in registers). |
| // |
| // See also the upstream documentation: |
| // https://clang.llvm.org/docs/AttributeReference.html#trivial-abi |
| // |
| // b/321691395 - This is currently disabled in open-source builds since |
| // compiler support differs. If system libraries compiled with GCC are mixed |
| // with libraries compiled with Clang, types will have different ideas about |
| // their ABI, leading to hard to debug crashes. |
| #define ABSL_ATTRIBUTE_TRIVIAL_ABI |
| |
| // ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS |
| // |
| // Indicates a data member can be optimized to occupy no space (if it is empty) |
| // and/or its tail padding can be used for other members. |
| // |
| // For code that is assured to only build with C++20 or later, prefer using |
| // the standard attribute `[[no_unique_address]]` directly instead of this |
| // macro. |
| // |
| // https://devblogs.microsoft.com/cppblog/msvc-cpp20-and-the-std-cpp20-switch/#c20-no_unique_address |
| // Current versions of MSVC have disabled `[[no_unique_address]]` since it |
| // breaks ABI compatibility, but offers `[[msvc::no_unique_address]]` for |
| // situations when it can be assured that it is desired. Since Abseil does not |
| // claim ABI compatibility in mixed builds, we can offer it unconditionally. |
| #if defined(_MSC_VER) && _MSC_VER >= 1929 |
| #define ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] |
| #elif ABSL_HAVE_CPP_ATTRIBUTE(no_unique_address) |
| #define ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS [[no_unique_address]] |
| #else |
| #define ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS |
| #endif |
| |
| // ABSL_ATTRIBUTE_UNINITIALIZED |
| // |
| // GCC and Clang support a flag `-ftrivial-auto-var-init=<option>` (<option> |
| // can be "zero" or "pattern") that can be used to initialize automatic stack |
| // variables. Variables with this attribute will be left uninitialized, |
| // overriding the compiler flag. |
| // |
| // See https://clang.llvm.org/docs/AttributeReference.html#uninitialized |
| // and https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-uninitialized-variable-attribute |
| #if ABSL_HAVE_CPP_ATTRIBUTE(clang::uninitialized) |
| #define ABSL_ATTRIBUTE_UNINITIALIZED [[clang::uninitialized]] |
| #elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::uninitialized) |
| #define ABSL_ATTRIBUTE_UNINITIALIZED [[gnu::uninitialized]] |
| #elif ABSL_HAVE_ATTRIBUTE(uninitialized) |
| #define ABSL_ATTRIBUTE_UNINITIALIZED __attribute__((uninitialized)) |
| #else |
| #define ABSL_ATTRIBUTE_UNINITIALIZED |
| #endif |
| |
| // ABSL_ATTRIBUTE_WARN_UNUSED |
| // |
| // Compilers routinely warn about trivial variables that are unused. For |
| // non-trivial types, this warning is suppressed since the |
| // constructor/destructor may be intentional and load-bearing, for example, with |
| // a RAII scoped lock. |
| // |
| // For example: |
| // |
| // class ABSL_ATTRIBUTE_WARN_UNUSED MyType { |
| // public: |
| // MyType(); |
| // ~MyType(); |
| // }; |
| // |
| // void foo() { |
| // // Warns with ABSL_ATTRIBUTE_WARN_UNUSED attribute present. |
| // MyType unused; |
| // } |
| // |
| // See https://clang.llvm.org/docs/AttributeReference.html#warn-unused and |
| // https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html#index-warn_005funused-type-attribute |
| #if ABSL_HAVE_CPP_ATTRIBUTE(gnu::warn_unused) |
| #define ABSL_ATTRIBUTE_WARN_UNUSED [[gnu::warn_unused]] |
| #else |
| #define ABSL_ATTRIBUTE_WARN_UNUSED |
| #endif |
| |
| #endif // ABSL_BASE_ATTRIBUTES_H_ |
| *µq |
| xsoong/.intermediates/external/abseil-cpp/absl_log_internal_log_impl_hdrs/gen/my_include_dir/absl/log/internal/log_impl.h¸p// Copyright 2022 The Abseil Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_LOG_INTERNAL_LOG_IMPL_H_ |
| #define ABSL_LOG_INTERNAL_LOG_IMPL_H_ |
| |
| #include "absl/log/absl_vlog_is_on.h" |
| #include "absl/log/internal/conditions.h" |
| #include "absl/log/internal/log_message.h" |
| #include "absl/log/internal/strip.h" |
| |
| // ABSL_LOG() |
| #define ABSL_LOG_INTERNAL_LOG_IMPL(severity) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, true) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() |
| |
| // ABSL_PLOG() |
| #define ABSL_LOG_INTERNAL_PLOG_IMPL(severity) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, true) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ |
| .WithPerror() |
| |
| // ABSL_DLOG() |
| #ifndef NDEBUG |
| #define ABSL_LOG_INTERNAL_DLOG_IMPL(severity) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, true) \ |
| ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| #else |
| #define ABSL_LOG_INTERNAL_DLOG_IMPL(severity) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, false) \ |
| ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| #endif |
| |
| // The `switch` ensures that this expansion is the beginning of a statement (as |
| // opposed to an expression). The use of both `case 0` and `default` is to |
| // suppress a compiler warning. |
| #define ABSL_LOG_INTERNAL_VLOG_IMPL(verbose_level) \ |
| switch (const int absl_logging_internal_verbose_level = (verbose_level)) \ |
| case 0: \ |
| default: \ |
| ABSL_LOG_INTERNAL_LOG_IF_IMPL( \ |
| _INFO, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level)) \ |
| .WithVerbosity(absl_logging_internal_verbose_level) |
| |
| #ifndef NDEBUG |
| #define ABSL_LOG_INTERNAL_DVLOG_IMPL(verbose_level) \ |
| switch (const int absl_logging_internal_verbose_level = (verbose_level)) \ |
| case 0: \ |
| default: \ |
| ABSL_LOG_INTERNAL_DLOG_IF_IMPL( \ |
| _INFO, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level)) \ |
| .WithVerbosity(absl_logging_internal_verbose_level) |
| #else |
| #define ABSL_LOG_INTERNAL_DVLOG_IMPL(verbose_level) \ |
| switch (const int absl_logging_internal_verbose_level = (verbose_level)) \ |
| case 0: \ |
| default: \ |
| ABSL_LOG_INTERNAL_DLOG_IF_IMPL( \ |
| _INFO, false && ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level)) \ |
| .WithVerbosity(absl_logging_internal_verbose_level) |
| #endif |
| |
| #define ABSL_LOG_INTERNAL_LOG_IF_IMPL(severity, condition) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, condition) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() |
| #define ABSL_LOG_INTERNAL_PLOG_IF_IMPL(severity, condition) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, condition) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ |
| .WithPerror() |
| |
| #ifndef NDEBUG |
| #define ABSL_LOG_INTERNAL_DLOG_IF_IMPL(severity, condition) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, condition) \ |
| ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| #else |
| #define ABSL_LOG_INTERNAL_DLOG_IF_IMPL(severity, condition) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, false && (condition)) \ |
| ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| #endif |
| |
| // ABSL_LOG_EVERY_N |
| #define ABSL_LOG_INTERNAL_LOG_EVERY_N_IMPL(severity, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryN, n) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() |
| |
| // ABSL_LOG_FIRST_N |
| #define ABSL_LOG_INTERNAL_LOG_FIRST_N_IMPL(severity, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(FirstN, n) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() |
| |
| // ABSL_LOG_EVERY_POW_2 |
| #define ABSL_LOG_INTERNAL_LOG_EVERY_POW_2_IMPL(severity) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryPow2) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() |
| |
| // ABSL_LOG_EVERY_N_SEC |
| #define ABSL_LOG_INTERNAL_LOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryNSec, n_seconds) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_PLOG_EVERY_N_IMPL(severity, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryN, n) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ |
| .WithPerror() |
| |
| #define ABSL_LOG_INTERNAL_PLOG_FIRST_N_IMPL(severity, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(FirstN, n) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ |
| .WithPerror() |
| |
| #define ABSL_LOG_INTERNAL_PLOG_EVERY_POW_2_IMPL(severity) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryPow2) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ |
| .WithPerror() |
| |
| #define ABSL_LOG_INTERNAL_PLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryNSec, n_seconds) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ |
| .WithPerror() |
| |
| #ifndef NDEBUG |
| #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_IMPL(severity, n) \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ |
| (EveryN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_FIRST_N_IMPL(severity, n) \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ |
| (FirstN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_EVERY_POW_2_IMPL(severity) \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ |
| (EveryPow2) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ |
| (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #else // def NDEBUG |
| #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_IMPL(severity, n) \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ |
| (EveryN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_FIRST_N_IMPL(severity, n) \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ |
| (FirstN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_EVERY_POW_2_IMPL(severity) \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ |
| (EveryPow2) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ |
| (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| #endif // def NDEBUG |
| |
| #define ABSL_LOG_INTERNAL_VLOG_EVERY_N_IMPL(verbose_level, n) \ |
| switch (const int absl_logging_internal_verbose_level = (verbose_level)) \ |
| case 0: \ |
| default: \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO( \ |
| STATEFUL, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level)) \ |
| (EveryN, n) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \ |
| absl_logging_internal_verbose_level) |
| |
| #define ABSL_LOG_INTERNAL_VLOG_FIRST_N_IMPL(verbose_level, n) \ |
| switch (const int absl_logging_internal_verbose_level = (verbose_level)) \ |
| case 0: \ |
| default: \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO( \ |
| STATEFUL, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level)) \ |
| (FirstN, n) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \ |
| absl_logging_internal_verbose_level) |
| |
| #define ABSL_LOG_INTERNAL_VLOG_EVERY_POW_2_IMPL(verbose_level) \ |
| switch (const int absl_logging_internal_verbose_level = (verbose_level)) \ |
| case 0: \ |
| default: \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO( \ |
| STATEFUL, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level)) \ |
| (EveryPow2) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream().WithVerbosity( \ |
| absl_logging_internal_verbose_level) |
| |
| #define ABSL_LOG_INTERNAL_VLOG_EVERY_N_SEC_IMPL(verbose_level, n_seconds) \ |
| switch (const int absl_logging_internal_verbose_level = (verbose_level)) \ |
| case 0: \ |
| default: \ |
| ABSL_LOG_INTERNAL_CONDITION_INFO( \ |
| STATEFUL, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level)) \ |
| (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_LOG_INFO.InternalStream() \ |
| .WithVerbosity(absl_logging_internal_verbose_level) |
| |
| #define ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_IMPL(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryN, n) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_LOG_IF_FIRST_N_IMPL(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(FirstN, n) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_LOG_IF_EVERY_POW_2_IMPL(severity, condition) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryPow2) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_SEC_IMPL(severity, condition, \ |
| n_seconds) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryNSec, \ |
| n_seconds) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_IMPL(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryN, n) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ |
| .WithPerror() |
| |
| #define ABSL_LOG_INTERNAL_PLOG_IF_FIRST_N_IMPL(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(FirstN, n) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ |
| .WithPerror() |
| |
| #define ABSL_LOG_INTERNAL_PLOG_IF_EVERY_POW_2_IMPL(severity, condition) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryPow2) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ |
| .WithPerror() |
| |
| #define ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_SEC_IMPL(severity, condition, \ |
| n_seconds) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryNSec, \ |
| n_seconds) \ |
| ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ |
| .WithPerror() |
| |
| #ifndef NDEBUG |
| #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_IMPL(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryN, n) \ |
| ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_IF_FIRST_N_IMPL(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(FirstN, n) \ |
| ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_POW_2_IMPL(severity, condition) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryPow2) \ |
| ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_SEC_IMPL(severity, condition, \ |
| n_seconds) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryNSec, \ |
| n_seconds) \ |
| ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #else // def NDEBUG |
| #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_IMPL(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ |
| EveryN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_IF_FIRST_N_IMPL(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ |
| FirstN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_POW_2_IMPL(severity, condition) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ |
| EveryPow2) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_SEC_IMPL(severity, condition, \ |
| n_seconds) \ |
| ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ |
| EveryNSec, n_seconds) \ |
| ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() |
| #endif // def NDEBUG |
| |
| #endif // ABSL_LOG_INTERNAL_LOG_IMPL_H_ |
| *Ñ" |
| ksoong/.intermediates/external/abseil-cpp/absl_base_config_hdrs/gen/my_include_dir/absl/base/policy_checks.há!// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: policy_checks.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header enforces a minimum set of policies at build time, such as the |
| // supported compiler and library versions. Unsupported configurations are |
| // reported with `#error`. This enforcement is best effort, so successfully |
| // compiling this header does not guarantee a supported configuration. |
| |
| // SKIP_ABSL_INLINE_NAMESPACE_CHECK |
| |
| #ifndef ABSL_BASE_POLICY_CHECKS_H_ |
| #define ABSL_BASE_POLICY_CHECKS_H_ |
| |
| // Included for the __GLIBC_PREREQ macro used below. |
| #include <limits.h> |
| |
| // Included for the _STLPORT_VERSION macro used below. |
| #if defined(__cplusplus) |
| #include <cstddef> |
| #endif |
| |
| // ----------------------------------------------------------------------------- |
| // Operating System Check |
| // ----------------------------------------------------------------------------- |
| |
| #if defined(__CYGWIN__) |
| #error "Cygwin is not supported." |
| #endif |
| |
| // ----------------------------------------------------------------------------- |
| // Toolchain Check |
| // ----------------------------------------------------------------------------- |
| |
| // We support Visual Studio 2019 (MSVC++ 16.0) and later. |
| // This minimum will go up. |
| #if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) |
| #error "This package requires Visual Studio 2019 (MSVC++ 16.0) or higher." |
| #endif |
| |
| // We support GCC 7 and later. |
| // This minimum will go up. |
| #if defined(__GNUC__) && !defined(__clang__) |
| #if __GNUC__ < 7 |
| #error "This package requires GCC 7 or higher." |
| #endif |
| #endif |
| |
| // We support Apple Xcode clang 4.2.1 (version 421.11.65) and later. |
| // This corresponds to Apple Xcode version 4.5. |
| // This minimum will go up. |
| #if defined(__apple_build_version__) && __apple_build_version__ < 4211165 |
| #error "This package requires __apple_build_version__ of 4211165 or higher." |
| #endif |
| |
| // ----------------------------------------------------------------------------- |
| // C++ Version Check |
| // ----------------------------------------------------------------------------- |
| |
| // Enforce C++17 as the minimum. |
| #if defined(_MSVC_LANG) |
| #if _MSVC_LANG < 201703L |
| #error "C++ versions less than C++17 are not supported." |
| #endif // _MSVC_LANG < 201703L |
| #elif defined(__cplusplus) |
| #if __cplusplus < 201703L |
| #error "C++ versions less than C++17 are not supported." |
| #endif // __cplusplus < 201703L |
| #endif |
| |
| // ----------------------------------------------------------------------------- |
| // Standard Library Check |
| // ----------------------------------------------------------------------------- |
| |
| #if defined(_STLPORT_VERSION) |
| #error "STLPort is not supported." |
| #endif |
| |
| // ----------------------------------------------------------------------------- |
| // `char` Size Check |
| // ----------------------------------------------------------------------------- |
| |
| // Abseil currently assumes CHAR_BIT == 8. If you would like to use Abseil on a |
| // platform where this is not the case, please provide us with the details about |
| // your platform so we can consider relaxing this requirement. |
| #if CHAR_BIT != 8 |
| #error "Abseil assumes CHAR_BIT == 8." |
| #endif |
| |
| // ----------------------------------------------------------------------------- |
| // `int` Size Check |
| // ----------------------------------------------------------------------------- |
| |
| // Abseil currently assumes that an int is 4 bytes. If you would like to use |
| // Abseil on a platform where this is not the case, please provide us with the |
| // details about your platform so we can consider relaxing this requirement. |
| #if INT_MAX < 2147483647 |
| #error "Abseil assumes that int is at least 4 bytes. " |
| #endif |
| |
| #endif // ABSL_BASE_POLICY_CHECKS_H_ |
| *I |
| esoong/.intermediates/external/abseil-cpp/absl_base_config_hdrs/gen/my_include_dir/absl/base/options.h¥H// Copyright 2019 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: options.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This file contains Abseil configuration options for setting specific |
| // implementations instead of letting Abseil determine which implementation to |
| // use at compile-time. Setting these options may be useful for package or build |
| // managers who wish to guarantee ABI stability within binary builds (which are |
| // otherwise difficult to enforce). |
| // |
| // *** IMPORTANT NOTICE FOR PACKAGE MANAGERS: It is important that |
| // maintainers of package managers who wish to package Abseil read and |
| // understand this file! *** |
| // |
| // Abseil contains a number of possible configuration endpoints, based on |
| // parameters such as the detected platform, language version, or command-line |
| // flags used to invoke the underlying binary. As is the case with all |
| // libraries, binaries which contain Abseil code must ensure that separate |
| // packages use the same compiled copy of Abseil to avoid a diamond dependency |
| // problem, which can occur if two packages built with different Abseil |
| // configuration settings are linked together. Diamond dependency problems in |
| // C++ may manifest as violations to the One Definition Rule (ODR) (resulting in |
| // linker errors), or undefined behavior (resulting in crashes). |
| // |
| // Diamond dependency problems can be avoided if all packages utilize the same |
| // exact version of Abseil. Building from source code with the same compilation |
| // parameters is the easiest way to avoid such dependency problems. However, for |
| // package managers who cannot control such compilation parameters, we are |
| // providing the file to allow you to inject ABI (Application Binary Interface) |
| // stability across builds. Settings options in this file will neither change |
| // API nor ABI, providing a stable copy of Abseil between packages. |
| // |
| // Care must be taken to keep options within these configurations isolated |
| // from any other dynamic settings, such as command-line flags which could alter |
| // these options. This file is provided specifically to help build and package |
| // managers provide a stable copy of Abseil within their libraries and binaries; |
| // other developers should not have need to alter the contents of this file. |
| // |
| // ----------------------------------------------------------------------------- |
| // Usage |
| // ----------------------------------------------------------------------------- |
| // |
| // For any particular package release, set the appropriate definitions within |
| // this file to whatever value makes the most sense for your package(s). Note |
| // that, by default, most of these options, at the moment, affect the |
| // implementation of types; future options may affect other implementation |
| // details. |
| // |
| // NOTE: the defaults within this file all assume that Abseil can select the |
| // proper Abseil implementation at compile-time, which will not be sufficient |
| // to guarantee ABI stability to package managers. |
| |
| // SKIP_ABSL_INLINE_NAMESPACE_CHECK |
| |
| #ifndef ABSL_BASE_OPTIONS_H_ |
| #define ABSL_BASE_OPTIONS_H_ |
| |
| // ----------------------------------------------------------------------------- |
| // Type Compatibility Options |
| // ----------------------------------------------------------------------------- |
| |
| // ABSL_OPTION_USE_STD_STRING_VIEW |
| // |
| // This option controls whether absl::string_view is implemented as an alias to |
| // std::string_view, or as an independent implementation. |
| // |
| // A value of 0 means to use Abseil's implementation. This requires only C++11 |
| // support, and is expected to work on every toolchain we support. |
| // |
| // A value of 1 means to use an alias to std::string_view. This requires that |
| // all code using Abseil is built in C++17 mode or later. |
| // |
| // A value of 2 means to detect the C++ version being used to compile Abseil, |
| // and use an alias only if a working std::string_view is available. This |
| // option is useful when you are building your program from source. It should |
| // not be used otherwise -- for example, if you are distributing Abseil in a |
| // binary package manager -- since in mode 2, absl::string_view will name a |
| // different type, with a different mangled name and binary layout, depending on |
| // the compiler flags passed by the end user. For more info, see |
| // https://abseil.io/about/design/dropin-types. |
| // |
| // User code should not inspect this macro. To check in the preprocessor if |
| // absl::string_view is a typedef of std::string_view, use the feature macro |
| // ABSL_USES_STD_STRING_VIEW. |
| |
| #define ABSL_OPTION_USE_STD_STRING_VIEW 1 |
| |
| // ABSL_OPTION_USE_STD_ORDERING |
| // |
| // This option controls whether absl::{partial,weak,strong}_ordering are |
| // implemented as aliases to the std:: ordering types, or as an independent |
| // implementation. |
| // |
| // A value of 0 means to use Abseil's implementation. This requires only C++11 |
| // support, and is expected to work on every toolchain we support. |
| // |
| // A value of 1 means to use aliases. This requires that all code using Abseil |
| // is built in C++20 mode or later. |
| // |
| // A value of 2 means to detect the C++ version being used to compile Abseil, |
| // and use an alias only if working std:: ordering types are available. This |
| // option is useful when you are building your program from source. It should |
| // not be used otherwise -- for example, if you are distributing Abseil in a |
| // binary package manager -- since in mode 2, they will name different types, |
| // with different mangled names and binary layout, depending on the compiler |
| // flags passed by the end user. For more info, see |
| // https://abseil.io/about/design/dropin-types. |
| // |
| // User code should not inspect this macro. To check in the preprocessor if |
| // the ordering types are aliases of std:: ordering types, use the feature macro |
| // ABSL_USES_STD_ORDERING. |
| |
| #define ABSL_OPTION_USE_STD_ORDERING 2 |
| |
| // ABSL_OPTION_USE_INLINE_NAMESPACE |
| // ABSL_OPTION_INLINE_NAMESPACE_NAME |
| // |
| // These options controls whether all entities in the absl namespace are |
| // contained within an inner inline namespace. This does not affect the |
| // user-visible API of Abseil, but it changes the mangled names of all symbols. |
| // |
| // This can be useful as a version tag if you are distributing Abseil in |
| // precompiled form. This will prevent a binary library build of Abseil with |
| // one inline namespace being used with headers configured with a different |
| // inline namespace name. Binary packagers are reminded that Abseil does not |
| // guarantee any ABI stability in Abseil, so any update of Abseil or |
| // configuration change in such a binary package should be combined with a |
| // new, unique value for the inline namespace name. |
| // |
| // A value of 0 means not to use inline namespaces. |
| // |
| // A value of 1 means to use an inline namespace with the given name inside |
| // namespace absl. If this is set, ABSL_OPTION_INLINE_NAMESPACE_NAME must also |
| // be changed to a new, unique identifier name. In particular "head" is not |
| // allowed. |
| |
| #define ABSL_OPTION_USE_INLINE_NAMESPACE 1 |
| #ifdef ANDROID_DISABLE_TLS_FOR_LINKER |
| #define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20250512_notls |
| #else |
| #define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20250512 |
| #endif |
| |
| // ABSL_OPTION_HARDENED |
| // |
| // This option enables a "hardened" build in release mode (in this context, |
| // release mode is defined as a build where the `NDEBUG` macro is defined). |
| // |
| // A value of 0 means that "hardened" mode is not enabled. |
| // |
| // A value of 1 means that "hardened" mode is enabled with all checks. |
| // |
| // A value of 2 means that "hardened" mode is partially enabled, with |
| // only a subset of checks chosen to minimize performance impact. |
| // |
| // Hardened builds have additional security checks enabled when `NDEBUG` is |
| // defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a |
| // no-op, as well as disabling other bespoke program consistency checks. By |
| // defining ABSL_OPTION_HARDENED to 1, a select set of checks remain enabled in |
| // release mode. These checks guard against programming errors that may lead to |
| // security vulnerabilities. In release mode, when one of these programming |
| // errors is encountered, the program will immediately abort, possibly without |
| // any attempt at logging. |
| // |
| // The checks enabled by this option are not free; they do incur runtime cost. |
| // |
| // The checks enabled by this option are always active when `NDEBUG` is not |
| // defined, even in the case when ABSL_OPTION_HARDENED is defined to 0. The |
| // checks enabled by this option may abort the program in a different way and |
| // log additional information when `NDEBUG` is not defined. |
| |
| #define ABSL_OPTION_HARDENED 0 |
| |
| #endif // ABSL_BASE_OPTIONS_H_ |
| *× |
| dsoong/.intermediates/external/abseil-cpp/absl_base_config_hdrs/gen/my_include_dir/absl/base/config.hí
// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: config.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines a set of macros for checking the presence of |
| // important compiler and platform features. Such macros can be used to |
| // produce portable code by parameterizing compilation based on the presence or |
| // lack of a given feature. |
| // |
| // We define a "feature" as some interface we wish to program to: for example, |
| // a library function or system call. A value of `1` indicates support for |
| // that feature; any other value indicates the feature support is undefined. |
| // |
| // Example: |
| // |
| // Suppose a programmer wants to write a program that uses the 'mmap()' system |
| // call. The Abseil macro for that feature (`ABSL_HAVE_MMAP`) allows you to |
| // selectively include the `mmap.h` header and bracket code using that feature |
| // in the macro: |
| // |
| // #include "absl/base/config.h" |
| // |
| // #ifdef ABSL_HAVE_MMAP |
| // #include "sys/mman.h" |
| // #endif //ABSL_HAVE_MMAP |
| // |
| // ... |
| // #ifdef ABSL_HAVE_MMAP |
| // void *ptr = mmap(...); |
| // ... |
| // #endif // ABSL_HAVE_MMAP |
| |
| #ifndef ABSL_BASE_CONFIG_H_ |
| #define ABSL_BASE_CONFIG_H_ |
| |
| // Included for the __GLIBC__ macro (or similar macros on other systems). |
| #include <limits.h> |
| |
| #ifdef __cplusplus |
| // Included for __GLIBCXX__, _LIBCPP_VERSION |
| #include <cstddef> |
| #endif // __cplusplus |
| |
| // ABSL_INTERNAL_CPLUSPLUS_LANG |
| // |
| // MSVC does not set the value of __cplusplus correctly, but instead uses |
| // _MSVC_LANG as a stand-in. |
| // https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros |
| // |
| // However, there are reports that MSVC even sets _MSVC_LANG incorrectly at |
| // times, for example: |
| // https://github.com/microsoft/vscode-cpptools/issues/1770 |
| // https://reviews.llvm.org/D70996 |
| // |
| // For this reason, this symbol is considered INTERNAL and code outside of |
| // Abseil must not use it. |
| #if defined(_MSVC_LANG) |
| #define ABSL_INTERNAL_CPLUSPLUS_LANG _MSVC_LANG |
| #elif defined(__cplusplus) |
| #define ABSL_INTERNAL_CPLUSPLUS_LANG __cplusplus |
| #endif |
| |
| #if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ |
| ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L |
| // Include library feature test macros. |
| #include <version> |
| #endif |
| |
| #if defined(__APPLE__) |
| // Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED, |
| // __IPHONE_8_0. |
| #include <Availability.h> |
| #include <TargetConditionals.h> |
| #endif |
| |
| #include "absl/base/options.h" |
| #include "absl/base/policy_checks.h" |
| |
| // Abseil long-term support (LTS) releases will define |
| // `ABSL_LTS_RELEASE_VERSION` to the integer representing the date string of the |
| // LTS release version, and will define `ABSL_LTS_RELEASE_PATCH_LEVEL` to the |
| // integer representing the patch-level for that release. |
| // |
| // For example, for LTS release version "20300401.2", this would give us |
| // ABSL_LTS_RELEASE_VERSION == 20300401 && ABSL_LTS_RELEASE_PATCH_LEVEL == 2 |
| // |
| // These symbols will not be defined in non-LTS code. |
| // |
| // Abseil recommends that clients live-at-head. Therefore, if you are using |
| // these symbols to assert a minimum version requirement, we recommend you do it |
| // as |
| // |
| // #if defined(ABSL_LTS_RELEASE_VERSION) && ABSL_LTS_RELEASE_VERSION < 20300401 |
| // #error Project foo requires Abseil LTS version >= 20300401 |
| // #endif |
| // |
| // The `defined(ABSL_LTS_RELEASE_VERSION)` part of the check excludes |
| // live-at-head clients from the minimum version assertion. |
| // |
| // See https://abseil.io/about/releases for more information on Abseil release |
| // management. |
| // |
| // LTS releases can be obtained from |
| // https://github.com/abseil/abseil-cpp/releases. |
| #define ABSL_LTS_RELEASE_VERSION 20250512 |
| #define ABSL_LTS_RELEASE_PATCH_LEVEL 1 |
| |
| // Helper macro to convert a CPP variable to a string literal. |
| #define ABSL_INTERNAL_DO_TOKEN_STR(x) #x |
| #define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x) |
| |
| // ----------------------------------------------------------------------------- |
| // Abseil namespace annotations |
| // ----------------------------------------------------------------------------- |
| |
| // ABSL_NAMESPACE_BEGIN/ABSL_NAMESPACE_END |
| // |
| // An annotation placed at the beginning/end of each `namespace absl` scope. |
| // This is used to inject an inline namespace. |
| // |
| // The proper way to write Abseil code in the `absl` namespace is: |
| // |
| // namespace absl { |
| // ABSL_NAMESPACE_BEGIN |
| // |
| // void Foo(); // absl::Foo(). |
| // |
| // ABSL_NAMESPACE_END |
| // } // namespace absl |
| // |
| // Users of Abseil should not use these macros, because users of Abseil should |
| // not write `namespace absl {` in their own code for any reason. (Abseil does |
| // not support forward declarations of its own types, nor does it support |
| // user-provided specialization of Abseil templates. Code that violates these |
| // rules may be broken without warning.) |
| #if !defined(ABSL_OPTION_USE_INLINE_NAMESPACE) || \ |
| !defined(ABSL_OPTION_INLINE_NAMESPACE_NAME) |
| #error options.h is misconfigured. |
| #endif |
| |
| // Check that ABSL_OPTION_INLINE_NAMESPACE_NAME is neither "head" nor "" |
| #if defined(__cplusplus) && ABSL_OPTION_USE_INLINE_NAMESPACE == 1 |
| |
| #define ABSL_INTERNAL_INLINE_NAMESPACE_STR \ |
| ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME) |
| |
| static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != '\0', |
| "options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must " |
| "not be empty."); |
| static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || |
| ABSL_INTERNAL_INLINE_NAMESPACE_STR[1] != 'e' || |
| ABSL_INTERNAL_INLINE_NAMESPACE_STR[2] != 'a' || |
| ABSL_INTERNAL_INLINE_NAMESPACE_STR[3] != 'd' || |
| ABSL_INTERNAL_INLINE_NAMESPACE_STR[4] != '\0', |
| "options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must " |
| "be changed to a new, unique identifier name."); |
| |
| #endif |
| |
| #if ABSL_OPTION_USE_INLINE_NAMESPACE == 0 |
| #define ABSL_NAMESPACE_BEGIN |
| #define ABSL_NAMESPACE_END |
| #define ABSL_INTERNAL_C_SYMBOL(x) x |
| #elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1 |
| #define ABSL_NAMESPACE_BEGIN \ |
| inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME { |
| #define ABSL_NAMESPACE_END } |
| #define ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) x##_##v |
| #define ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, v) \ |
| ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) |
| #define ABSL_INTERNAL_C_SYMBOL(x) \ |
| ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, ABSL_OPTION_INLINE_NAMESPACE_NAME) |
| #else |
| #error options.h is misconfigured. |
| #endif |
| |
| // ----------------------------------------------------------------------------- |
| // Compiler Feature Checks |
| // ----------------------------------------------------------------------------- |
| |
| // ABSL_HAVE_BUILTIN() |
| // |
| // Checks whether the compiler supports a Clang Feature Checking Macro, and if |
| // so, checks whether it supports the provided builtin function "x" where x |
| // is one of the functions noted in |
| // https://clang.llvm.org/docs/LanguageExtensions.html |
| // |
| // Note: Use this macro to avoid an extra level of #ifdef __has_builtin check. |
| // http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html |
| #ifdef __has_builtin |
| #define ABSL_HAVE_BUILTIN(x) __has_builtin(x) |
| #else |
| #define ABSL_HAVE_BUILTIN(x) 0 |
| #endif |
| |
| #ifdef __has_feature |
| #define ABSL_HAVE_FEATURE(f) __has_feature(f) |
| #else |
| #define ABSL_HAVE_FEATURE(f) 0 |
| #endif |
| |
| // Portable check for GCC minimum version: |
| // https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html |
| #if defined(__GNUC__) && defined(__GNUC_MINOR__) |
| #define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) \ |
| (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) |
| #else |
| #define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) 0 |
| #endif |
| |
| #if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) |
| #define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) \ |
| (__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y)) |
| #else |
| #define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) 0 |
| #endif |
| |
| // ABSL_HAVE_TLS is defined to 1 when __thread should be supported. |
| // We assume __thread is supported on Linux when compiled with Clang or |
| // compiled against libstdc++ with _GLIBCXX_HAVE_TLS defined. |
| #ifdef ABSL_HAVE_TLS |
| #error ABSL_HAVE_TLS cannot be directly set |
| #elif (defined(__linux__)) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS)) |
| #define ABSL_HAVE_TLS 1 |
| #endif |
| |
| // ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE |
| // |
| // Checks whether `std::is_trivially_destructible<T>` is supported. |
| #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE |
| #error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set |
| #define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1 |
| #endif |
| |
| // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE |
| // |
| // Checks whether `std::is_trivially_default_constructible<T>` and |
| // `std::is_trivially_copy_constructible<T>` are supported. |
| #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE |
| #error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set |
| #else |
| #define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1 |
| #endif |
| |
| // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE |
| // |
| // Checks whether `std::is_trivially_copy_assignable<T>` is supported. |
| #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE |
| #error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot be directly set |
| #else |
| #define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1 |
| #endif |
| |
| // ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE |
| // |
| // Checks whether `std::is_trivially_copyable<T>` is supported. |
| #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE |
| #error ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE cannot be directly set |
| #define ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE 1 |
| #endif |
| |
| // ABSL_HAVE_THREAD_LOCAL |
| // |
| // Checks whether the `thread_local` storage duration specifier is supported. |
| #ifdef ABSL_HAVE_THREAD_LOCAL |
| #error ABSL_HAVE_THREAD_LOCAL cannot be directly set |
| #elif !defined(__XTENSA__) && !defined(ANDROID_DISABLE_TLS_FOR_LINKER) |
| #define ABSL_HAVE_THREAD_LOCAL 1 |
| #endif |
| |
| // ABSL_HAVE_INTRINSIC_INT128 |
| // |
| // Checks whether the __int128 compiler extension for a 128-bit integral type is |
| // supported. |
| // |
| // Note: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is |
| // supported, but we avoid using it in certain cases: |
| // * On Clang: |
| // * Building using Clang for Windows, where the Clang runtime library has |
| // 128-bit support only on LP64 architectures, but Windows is LLP64. |
| // * On Nvidia's nvcc: |
| // * nvcc also defines __GNUC__ and __SIZEOF_INT128__, but not all versions |
| // actually support __int128. |
| #ifdef ABSL_HAVE_INTRINSIC_INT128 |
| #error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set |
| #elif defined(__SIZEOF_INT128__) |
| #if (defined(__clang__) && !defined(_WIN32)) || \ |
| (defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \ |
| (defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__)) |
| #define ABSL_HAVE_INTRINSIC_INT128 1 |
| #elif defined(__CUDACC__) |
| // __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a |
| // string explaining that it has been removed starting with CUDA 9. We use |
| // nested #ifs because there is no short-circuiting in the preprocessor. |
| // NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined. |
| #if __CUDACC_VER__ >= 70000 |
| #define ABSL_HAVE_INTRINSIC_INT128 1 |
| #endif // __CUDACC_VER__ >= 70000 |
| #endif // defined(__CUDACC__) |
| #endif // ABSL_HAVE_INTRINSIC_INT128 |
| |
| // ABSL_HAVE_EXCEPTIONS |
| // |
| // Checks whether the compiler both supports and enables exceptions. Many |
| // compilers support a "no exceptions" mode that disables exceptions. |
| // |
| // Generally, when ABSL_HAVE_EXCEPTIONS is not defined: |
| // |
| // * Code using `throw` and `try` may not compile. |
| // * The `noexcept` specifier will still compile and behave as normal. |
| // * The `noexcept` operator may still return `false`. |
| // |
| // For further details, consult the compiler's documentation. |
| #ifdef ABSL_HAVE_EXCEPTIONS |
| #error ABSL_HAVE_EXCEPTIONS cannot be directly set. |
| #elif ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(3, 6) |
| // Clang >= 3.6 |
| #if ABSL_HAVE_FEATURE(cxx_exceptions) |
| #define ABSL_HAVE_EXCEPTIONS 1 |
| #endif // ABSL_HAVE_FEATURE(cxx_exceptions) |
| #elif defined(__clang__) |
| // Clang < 3.6 |
| // http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro |
| #if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions) |
| #define ABSL_HAVE_EXCEPTIONS 1 |
| #endif // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions) |
| // Handle remaining special cases and default to exceptions being supported. |
| #elif !(defined(__GNUC__) && !defined(__cpp_exceptions)) && \ |
| !(defined(_MSC_VER) && !defined(_CPPUNWIND)) |
| #define ABSL_HAVE_EXCEPTIONS 1 |
| #endif |
| |
| // ----------------------------------------------------------------------------- |
| // Platform Feature Checks |
| // ----------------------------------------------------------------------------- |
| |
| // Currently supported operating systems and associated preprocessor |
| // symbols: |
| // |
| // Linux and Linux-derived __linux__ |
| // Android __ANDROID__ (implies __linux__) |
| // Linux (non-Android) __linux__ && !__ANDROID__ |
| // Darwin (macOS and iOS) __APPLE__ |
| // Akaros (http://akaros.org) __ros__ |
| // Windows _WIN32 |
| // NaCL __native_client__ |
| // AsmJS __asmjs__ |
| // WebAssembly (Emscripten) __EMSCRIPTEN__ |
| // Fuchsia __Fuchsia__ |
| // |
| // Note that since Android defines both __ANDROID__ and __linux__, one |
| // may probe for either Linux or Android by simply testing for __linux__. |
| |
| // ABSL_HAVE_MMAP |
| // |
| // Checks whether the platform has an mmap(2) implementation as defined in |
| // POSIX.1-2001. |
| #ifdef ABSL_HAVE_MMAP |
| #error ABSL_HAVE_MMAP cannot be directly set |
| #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ |
| defined(_AIX) || defined(__ros__) || defined(__native_client__) || \ |
| defined(__asmjs__) || defined(__EMSCRIPTEN__) || defined(__Fuchsia__) || \ |
| defined(__sun) || defined(__myriad2__) || defined(__HAIKU__) || \ |
| defined(__OpenBSD__) || defined(__NetBSD__) || defined(__QNX__) || \ |
| defined(__VXWORKS__) || defined(__hexagon__) || defined(__XTENSA__) |
| #define ABSL_HAVE_MMAP 1 |
| #endif |
| |
| // ABSL_HAVE_PTHREAD_GETSCHEDPARAM |
| // |
| // Checks whether the platform implements the pthread_(get|set)schedparam(3) |
| // functions as defined in POSIX.1-2001. |
| #ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM |
| #error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set |
| #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ |
| defined(_AIX) || defined(__ros__) || defined(__OpenBSD__) || \ |
| defined(__NetBSD__) || defined(__VXWORKS__) |
| #define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1 |
| #endif |
| |
| // ABSL_HAVE_SCHED_GETCPU |
| // |
| // Checks whether sched_getcpu is available. |
| #ifdef ABSL_HAVE_SCHED_GETCPU |
| #error ABSL_HAVE_SCHED_GETCPU cannot be directly set |
| #elif defined(__linux__) |
| #define ABSL_HAVE_SCHED_GETCPU 1 |
| #endif |
| |
| // ABSL_HAVE_SCHED_YIELD |
| // |
| // Checks whether the platform implements sched_yield(2) as defined in |
| // POSIX.1-2001. |
| #ifdef ABSL_HAVE_SCHED_YIELD |
| #error ABSL_HAVE_SCHED_YIELD cannot be directly set |
| #elif defined(__linux__) || defined(__ros__) || defined(__native_client__) || \ |
| defined(__VXWORKS__) |
| #define ABSL_HAVE_SCHED_YIELD 1 |
| #endif |
| |
| // ABSL_HAVE_SEMAPHORE_H |
| // |
| // Checks whether the platform supports the <semaphore.h> header and sem_init(3) |
| // family of functions as standardized in POSIX.1-2001. |
| // |
| // Note: While Apple provides <semaphore.h> for both iOS and macOS, it is |
| // explicitly deprecated and will cause build failures if enabled for those |
| // platforms. We side-step the issue by not defining it here for Apple |
| // platforms. |
| #ifdef ABSL_HAVE_SEMAPHORE_H |
| #error ABSL_HAVE_SEMAPHORE_H cannot be directly set |
| #elif defined(__linux__) || defined(__ros__) || defined(__VXWORKS__) |
| #define ABSL_HAVE_SEMAPHORE_H 1 |
| #endif |
| |
| // ABSL_HAVE_ALARM |
| // |
| // Checks whether the platform supports the <signal.h> header and alarm(2) |
| // function as standardized in POSIX.1-2001. |
| #ifdef ABSL_HAVE_ALARM |
| #error ABSL_HAVE_ALARM cannot be directly set |
| #elif defined(__GOOGLE_GRTE_VERSION__) |
| // feature tests for Google's GRTE |
| #define ABSL_HAVE_ALARM 1 |
| #elif defined(__GLIBC__) |
| // feature test for glibc |
| #define ABSL_HAVE_ALARM 1 |
| #elif defined(_MSC_VER) |
| // feature tests for Microsoft's library |
| #elif defined(__MINGW32__) |
| // mingw32 doesn't provide alarm(2): |
| // https://osdn.net/projects/mingw/scm/git/mingw-org-wsl/blobs/5.2-trunk/mingwrt/include/unistd.h |
| // mingw-w64 provides a no-op implementation: |
| // https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/misc/alarm.c |
| #elif defined(__EMSCRIPTEN__) |
| // emscripten doesn't support signals |
| #elif defined(__wasi__) |
| // WASI doesn't support signals |
| #elif defined(__Fuchsia__) |
| // Signals don't exist on fuchsia. |
| #elif defined(__native_client__) |
| // Signals don't exist on hexagon/QuRT |
| #elif defined(__hexagon__) |
| #else |
| // other standard libraries |
| #define ABSL_HAVE_ALARM 1 |
| #endif |
| |
| // ABSL_IS_LITTLE_ENDIAN |
| // ABSL_IS_BIG_ENDIAN |
| // |
| // Checks the endianness of the platform. |
| // |
| // Prefer using `std::endian` in C++20, or `absl::endian` from |
| // absl/numeric/bits.h prior to C++20. |
| // |
| // Notes: uses the built in endian macros provided by GCC (since 4.6) and |
| // Clang (since 3.2); see |
| // https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html. |
| // Otherwise, if _WIN32, assume little endian. Otherwise, bail with an error. |
| #if defined(ABSL_IS_BIG_ENDIAN) |
| #error "ABSL_IS_BIG_ENDIAN cannot be directly set." |
| #endif |
| #if defined(ABSL_IS_LITTLE_ENDIAN) |
| #error "ABSL_IS_LITTLE_ENDIAN cannot be directly set." |
| #endif |
| |
| #if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ |
| __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) |
| #define ABSL_IS_LITTLE_ENDIAN 1 |
| #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ |
| __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
| #define ABSL_IS_BIG_ENDIAN 1 |
| #elif defined(_WIN32) |
| #define ABSL_IS_LITTLE_ENDIAN 1 |
| #else |
| #error "absl endian detection needs to be set up for your compiler" |
| #endif |
| |
| // macOS < 10.13 and iOS < 12 don't support <any>, <optional>, or <variant> |
| // because the libc++ shared library shipped on the system doesn't have the |
| // requisite exported symbols. See |
| // https://github.com/abseil/abseil-cpp/issues/207 and |
| // https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes |
| // |
| // libc++ spells out the availability requirements in the file |
| // llvm-project/libcxx/include/__config via the #define |
| // _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS. The set of versions has been |
| // modified a few times, via |
| // https://github.com/llvm/llvm-project/commit/7fb40e1569dd66292b647f4501b85517e9247953 |
| // and |
| // https://github.com/llvm/llvm-project/commit/0bc451e7e137c4ccadcd3377250874f641ca514a |
| // The second has the actually correct versions, thus, is what we copy here. |
| #if defined(__APPLE__) && \ |
| ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ |
| __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300) || \ |
| (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ |
| __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \ |
| (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ |
| __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \ |
| (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \ |
| __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000)) |
| #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1 |
| #else |
| #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0 |
| #endif |
| |
| // Deprecated macros for polyfill detection. |
| #define ABSL_HAVE_STD_ANY 1 |
| #define ABSL_USES_STD_ANY 1 |
| #define ABSL_HAVE_STD_OPTIONAL 1 |
| #define ABSL_USES_STD_OPTIONAL 1 |
| #define ABSL_HAVE_STD_VARIANT 1 |
| #define ABSL_USES_STD_VARIANT 1 |
| |
| // ABSL_HAVE_STD_STRING_VIEW |
| // |
| // Deprecated: always defined to 1. |
| // std::string_view was added in C++17, which means all versions of C++ |
| // supported by Abseil have it. |
| #ifdef ABSL_HAVE_STD_STRING_VIEW |
| #error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set." |
| #else |
| #define ABSL_HAVE_STD_STRING_VIEW 1 |
| #endif |
| |
| // ABSL_HAVE_STD_ORDERING |
| // |
| // Checks whether C++20 std::{partial,weak,strong}_ordering are available. |
| // |
| // __cpp_lib_three_way_comparison is missing on libc++ |
| // (https://github.com/llvm/llvm-project/issues/73953) so treat it as defined |
| // when building in C++20 mode. |
| #ifdef ABSL_HAVE_STD_ORDERING |
| #error "ABSL_HAVE_STD_ORDERING cannot be directly set." |
| #elif (defined(__cpp_lib_three_way_comparison) && \ |
| __cpp_lib_three_way_comparison >= 201907L) || \ |
| (defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ |
| ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L) |
| #define ABSL_HAVE_STD_ORDERING 1 |
| #endif |
| |
| // ABSL_USES_STD_STRING_VIEW |
| // |
| // Indicates whether absl::string_view is an alias for std::string_view. |
| #if !defined(ABSL_OPTION_USE_STD_STRING_VIEW) |
| #error options.h is misconfigured. |
| #elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 |
| #undef ABSL_USES_STD_STRING_VIEW |
| #elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \ |
| ABSL_OPTION_USE_STD_STRING_VIEW == 2 |
| #define ABSL_USES_STD_STRING_VIEW 1 |
| #else |
| #error options.h is misconfigured. |
| #endif |
| |
| // ABSL_USES_STD_ORDERING |
| // |
| // Indicates whether absl::{partial,weak,strong}_ordering are aliases for the |
| // std:: ordering types. |
| #if !defined(ABSL_OPTION_USE_STD_ORDERING) |
| #error options.h is misconfigured. |
| #elif ABSL_OPTION_USE_STD_ORDERING == 0 || \ |
| (ABSL_OPTION_USE_STD_ORDERING == 2 && !defined(ABSL_HAVE_STD_ORDERING)) |
| #undef ABSL_USES_STD_ORDERING |
| #elif ABSL_OPTION_USE_STD_ORDERING == 1 || \ |
| (ABSL_OPTION_USE_STD_ORDERING == 2 && defined(ABSL_HAVE_STD_ORDERING)) |
| #define ABSL_USES_STD_ORDERING 1 |
| #else |
| #error options.h is misconfigured. |
| #endif |
| |
| // ABSL_INTERNAL_MANGLED_NS |
| // ABSL_INTERNAL_MANGLED_BACKREFERENCE |
| // |
| // Internal macros for building up mangled names in our internal fork of CCTZ. |
| // This implementation detail is only needed and provided for the MSVC build. |
| // |
| // These macros both expand to string literals. ABSL_INTERNAL_MANGLED_NS is |
| // the mangled spelling of the `absl` namespace, and |
| // ABSL_INTERNAL_MANGLED_BACKREFERENCE is a back-reference integer representing |
| // the proper count to skip past the CCTZ fork namespace names. (This number |
| // is one larger when there is an inline namespace name to skip.) |
| #if defined(_MSC_VER) |
| #if ABSL_OPTION_USE_INLINE_NAMESPACE == 0 |
| #define ABSL_INTERNAL_MANGLED_NS "absl" |
| #define ABSL_INTERNAL_MANGLED_BACKREFERENCE "5" |
| #else |
| #define ABSL_INTERNAL_MANGLED_NS \ |
| ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME) "@absl" |
| #define ABSL_INTERNAL_MANGLED_BACKREFERENCE "6" |
| #endif |
| #endif |
| |
| // ABSL_DLL |
| // |
| // When building Abseil as a DLL, this macro expands to `__declspec(dllexport)` |
| // so we can annotate symbols appropriately as being exported. When used in |
| // headers consuming a DLL, this macro expands to `__declspec(dllimport)` so |
| // that consumers know the symbol is defined inside the DLL. In all other cases, |
| // the macro expands to nothing. |
| #if defined(_MSC_VER) |
| #if defined(ABSL_BUILD_DLL) |
| #define ABSL_DLL __declspec(dllexport) |
| #elif defined(ABSL_CONSUME_DLL) |
| #define ABSL_DLL __declspec(dllimport) |
| #else |
| #define ABSL_DLL |
| #endif |
| #else |
| #define ABSL_DLL |
| #endif // defined(_MSC_VER) |
| |
| #if defined(_MSC_VER) |
| #if defined(ABSL_BUILD_TEST_DLL) |
| #define ABSL_TEST_DLL __declspec(dllexport) |
| #elif defined(ABSL_CONSUME_TEST_DLL) |
| #define ABSL_TEST_DLL __declspec(dllimport) |
| #else |
| #define ABSL_TEST_DLL |
| #endif |
| #else |
| #define ABSL_TEST_DLL |
| #endif // defined(_MSC_VER) |
| |
| // ABSL_HAVE_MEMORY_SANITIZER |
| // |
| // MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of |
| // a compiler instrumentation module and a run-time library. |
| #ifdef ABSL_HAVE_MEMORY_SANITIZER |
| #error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set." |
| #elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer) |
| #define ABSL_HAVE_MEMORY_SANITIZER 1 |
| #endif |
| |
| // ABSL_HAVE_THREAD_SANITIZER |
| // |
| // ThreadSanitizer (TSan) is a fast data race detector. |
| #ifdef ABSL_HAVE_THREAD_SANITIZER |
| #error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set." |
| #elif defined(__SANITIZE_THREAD__) |
| #define ABSL_HAVE_THREAD_SANITIZER 1 |
| #elif ABSL_HAVE_FEATURE(thread_sanitizer) |
| #define ABSL_HAVE_THREAD_SANITIZER 1 |
| #endif |
| |
| // ABSL_HAVE_ADDRESS_SANITIZER |
| // |
| // AddressSanitizer (ASan) is a fast memory error detector. |
| #ifdef ABSL_HAVE_ADDRESS_SANITIZER |
| #error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set." |
| #elif defined(__SANITIZE_ADDRESS__) |
| #define ABSL_HAVE_ADDRESS_SANITIZER 1 |
| #elif ABSL_HAVE_FEATURE(address_sanitizer) |
| #define ABSL_HAVE_ADDRESS_SANITIZER 1 |
| #endif |
| |
| // ABSL_HAVE_HWADDRESS_SANITIZER |
| // |
| // Hardware-Assisted AddressSanitizer (or HWASAN) is even faster than asan |
| // memory error detector which can use CPU features like ARM TBI, Intel LAM or |
| // AMD UAI. |
| #ifdef ABSL_HAVE_HWADDRESS_SANITIZER |
| #error "ABSL_HAVE_HWADDRESS_SANITIZER cannot be directly set." |
| #elif defined(__SANITIZE_HWADDRESS__) |
| #define ABSL_HAVE_HWADDRESS_SANITIZER 1 |
| #elif ABSL_HAVE_FEATURE(hwaddress_sanitizer) |
| #define ABSL_HAVE_HWADDRESS_SANITIZER 1 |
| #endif |
| |
| // ABSL_HAVE_DATAFLOW_SANITIZER |
| // |
| // Dataflow Sanitizer (or DFSAN) is a generalised dynamic data flow analysis. |
| #ifdef ABSL_HAVE_DATAFLOW_SANITIZER |
| #error "ABSL_HAVE_DATAFLOW_SANITIZER cannot be directly set." |
| #elif defined(DATAFLOW_SANITIZER) |
| // GCC provides no method for detecting the presence of the standalone |
| // DataFlowSanitizer (-fsanitize=dataflow), so GCC users of -fsanitize=dataflow |
| // should also use -DDATAFLOW_SANITIZER. |
| #define ABSL_HAVE_DATAFLOW_SANITIZER 1 |
| #elif ABSL_HAVE_FEATURE(dataflow_sanitizer) |
| #define ABSL_HAVE_DATAFLOW_SANITIZER 1 |
| #endif |
| |
| // ABSL_HAVE_LEAK_SANITIZER |
| // |
| // LeakSanitizer (or lsan) is a detector of memory leaks. |
| // https://clang.llvm.org/docs/LeakSanitizer.html |
| // https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer |
| // |
| // The macro ABSL_HAVE_LEAK_SANITIZER can be used to detect at compile-time |
| // whether the LeakSanitizer is potentially available. However, just because the |
| // LeakSanitizer is available does not mean it is active. Use the |
| // always-available run-time interface in //absl/debugging/leak_check.h for |
| // interacting with LeakSanitizer. |
| #ifdef ABSL_HAVE_LEAK_SANITIZER |
| #error "ABSL_HAVE_LEAK_SANITIZER cannot be directly set." |
| #elif defined(LEAK_SANITIZER) |
| // GCC provides no method for detecting the presence of the standalone |
| // LeakSanitizer (-fsanitize=leak), so GCC users of -fsanitize=leak should also |
| // use -DLEAK_SANITIZER. |
| #define ABSL_HAVE_LEAK_SANITIZER 1 |
| // Clang standalone LeakSanitizer (-fsanitize=leak) |
| #elif ABSL_HAVE_FEATURE(leak_sanitizer) |
| #define ABSL_HAVE_LEAK_SANITIZER 1 |
| #elif defined(ABSL_HAVE_ADDRESS_SANITIZER) |
| // GCC or Clang using the LeakSanitizer integrated into AddressSanitizer. |
| #define ABSL_HAVE_LEAK_SANITIZER 1 |
| #endif |
| |
| // ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION |
| // |
| // Deprecated: always defined to 1. |
| // Class template argument deduction is a language feature added in C++17, |
| // which means all versions of C++ supported by Abseil have it. |
| #ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION |
| #error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set." |
| #else |
| #define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1 |
| #endif |
| |
| // `ABSL_INTERNAL_HAS_RTTI` determines whether abseil is being compiled with |
| // RTTI support. |
| #ifdef ABSL_INTERNAL_HAS_RTTI |
| #error ABSL_INTERNAL_HAS_RTTI cannot be directly set |
| #elif ABSL_HAVE_FEATURE(cxx_rtti) |
| #define ABSL_INTERNAL_HAS_RTTI 1 |
| #elif defined(__GNUC__) && defined(__GXX_RTTI) |
| #define ABSL_INTERNAL_HAS_RTTI 1 |
| #elif defined(_MSC_VER) && defined(_CPPRTTI) |
| #define ABSL_INTERNAL_HAS_RTTI 1 |
| #elif !defined(__GNUC__) && !defined(_MSC_VER) |
| // Unknown compiler, default to RTTI |
| #define ABSL_INTERNAL_HAS_RTTI 1 |
| #endif |
| |
| // `ABSL_INTERNAL_HAS_CXA_DEMANGLE` determines whether `abi::__cxa_demangle` is |
| // available. |
| #ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE |
| #error ABSL_INTERNAL_HAS_CXA_DEMANGLE cannot be directly set |
| #elif defined(OS_ANDROID) && (defined(__i386__) || defined(__x86_64__)) |
| #define ABSL_INTERNAL_HAS_CXA_DEMANGLE 0 |
| #elif defined(__GNUC__) |
| #define ABSL_INTERNAL_HAS_CXA_DEMANGLE 1 |
| #elif defined(__clang__) && !defined(_MSC_VER) |
| #define ABSL_INTERNAL_HAS_CXA_DEMANGLE 1 |
| #endif |
| |
| // ABSL_INTERNAL_HAVE_SSE is used for compile-time detection of SSE support. |
| // See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of |
| // which architectures support the various x86 instruction sets. |
| #ifdef ABSL_INTERNAL_HAVE_SSE |
| #error ABSL_INTERNAL_HAVE_SSE cannot be directly set |
| #elif defined(__SSE__) |
| #define ABSL_INTERNAL_HAVE_SSE 1 |
| #elif (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)) && \ |
| !defined(_M_ARM64EC) |
| // MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 1 |
| // indicates that at least SSE was targeted with the /arch:SSE option. |
| // All x86-64 processors support SSE, so support can be assumed. |
| // https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros |
| #define ABSL_INTERNAL_HAVE_SSE 1 |
| #endif |
| |
| // ABSL_INTERNAL_HAVE_SSE2 is used for compile-time detection of SSE2 support. |
| // See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of |
| // which architectures support the various x86 instruction sets. |
| #ifdef ABSL_INTERNAL_HAVE_SSE2 |
| #error ABSL_INTERNAL_HAVE_SSE2 cannot be directly set |
| #elif defined(__SSE2__) |
| #define ABSL_INTERNAL_HAVE_SSE2 1 |
| #elif (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)) && \ |
| !defined(_M_ARM64EC) |
| // MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 2 |
| // indicates that at least SSE2 was targeted with the /arch:SSE2 option. |
| // All x86-64 processors support SSE2, so support can be assumed. |
| // https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros |
| #define ABSL_INTERNAL_HAVE_SSE2 1 |
| #endif |
| |
| // ABSL_INTERNAL_HAVE_SSSE3 is used for compile-time detection of SSSE3 support. |
| // See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of |
| // which architectures support the various x86 instruction sets. |
| // |
| // MSVC does not have a mode that targets SSSE3 at compile-time. To use SSSE3 |
| // with MSVC requires either assuming that the code will only every run on CPUs |
| // that support SSSE3, otherwise __cpuid() can be used to detect support at |
| // runtime and fallback to a non-SSSE3 implementation when SSSE3 is unsupported |
| // by the CPU. |
| #ifdef ABSL_INTERNAL_HAVE_SSSE3 |
| #error ABSL_INTERNAL_HAVE_SSSE3 cannot be directly set |
| #elif defined(__SSSE3__) |
| #define ABSL_INTERNAL_HAVE_SSSE3 1 |
| #endif |
| |
| // ABSL_INTERNAL_HAVE_ARM_NEON is used for compile-time detection of NEON (ARM |
| // SIMD). |
| // |
| // If __CUDA_ARCH__ is defined, then we are compiling CUDA code in device mode. |
| // In device mode, NEON intrinsics are not available, regardless of host |
| // platform. |
| // https://llvm.org/docs/CompileCudaWithLLVM.html#detecting-clang-vs-nvcc-from-code |
| #ifdef ABSL_INTERNAL_HAVE_ARM_NEON |
| #error ABSL_INTERNAL_HAVE_ARM_NEON cannot be directly set |
| #elif defined(__ARM_NEON) && !(defined(__NVCC__) && defined(__CUDACC__)) |
| #define ABSL_INTERNAL_HAVE_ARM_NEON 1 |
| #endif |
| |
| // ABSL_HAVE_CONSTANT_EVALUATED is used for compile-time detection of |
| // constant evaluation support through `absl::is_constant_evaluated`. |
| #ifdef ABSL_HAVE_CONSTANT_EVALUATED |
| #error ABSL_HAVE_CONSTANT_EVALUATED cannot be directly set |
| #endif |
| #ifdef __cpp_lib_is_constant_evaluated |
| #define ABSL_HAVE_CONSTANT_EVALUATED 1 |
| #elif ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated) |
| #define ABSL_HAVE_CONSTANT_EVALUATED 1 |
| #endif |
| |
| // ABSL_INTERNAL_CONSTEXPR_SINCE_CXXYY is used to conditionally define constexpr |
| // for different C++ versions. |
| // |
| // These macros are an implementation detail and will be unconditionally removed |
| // once the minimum supported C++ version catches up to a given version. |
| // |
| // For this reason, this symbol is considered INTERNAL and code outside of |
| // Abseil must not use it. |
| #if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ |
| ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L |
| #define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 constexpr |
| #else |
| #define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 |
| #endif |
| #if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ |
| ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L |
| #define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 constexpr |
| #else |
| #define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 |
| #endif |
| |
| // ABSL_INTERNAL_EMSCRIPTEN_VERSION combines Emscripten's three version macros |
| // into an integer that can be compared against. |
| #ifdef ABSL_INTERNAL_EMSCRIPTEN_VERSION |
| #error ABSL_INTERNAL_EMSCRIPTEN_VERSION cannot be directly set |
| #endif |
| #ifdef __EMSCRIPTEN__ |
| #include <emscripten/version.h> |
| #ifdef __EMSCRIPTEN_major__ |
| #if __EMSCRIPTEN_minor__ >= 1000 |
| #error __EMSCRIPTEN_minor__ is too big to fit in ABSL_INTERNAL_EMSCRIPTEN_VERSION |
| #endif |
| #if __EMSCRIPTEN_tiny__ >= 1000 |
| #error __EMSCRIPTEN_tiny__ is too big to fit in ABSL_INTERNAL_EMSCRIPTEN_VERSION |
| #endif |
| #define ABSL_INTERNAL_EMSCRIPTEN_VERSION \ |
| ((__EMSCRIPTEN_major__) * 1000000 + (__EMSCRIPTEN_minor__) * 1000 + \ |
| (__EMSCRIPTEN_tiny__)) |
| #endif |
| #endif |
| |
| #endif // ABSL_BASE_CONFIG_H_ |
| *Õ` |
| psoong/.intermediates/external/abseil-cpp/absl_base_core_headers_hdrs/gen/my_include_dir/absl/base/optimization.hà_// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: optimization.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines portable macros for performance optimization. |
| // |
| // This header is included in both C++ code and legacy C code and thus must |
| // remain compatible with both C and C++. C compatibility will be removed if |
| // the legacy code is removed or converted to C++. Do not include this header in |
| // new code that requires C compatibility or assume C compatibility will remain |
| // indefinitely. |
| |
| // SKIP_ABSL_INLINE_NAMESPACE_CHECK |
| |
| #ifndef ABSL_BASE_OPTIMIZATION_H_ |
| #define ABSL_BASE_OPTIMIZATION_H_ |
| |
| #include <assert.h> |
| |
| #ifdef __cplusplus |
| // Included for std::unreachable() |
| #include <utility> |
| #endif // __cplusplus |
| |
| #include "absl/base/config.h" |
| #include "absl/base/options.h" |
| |
| // ABSL_BLOCK_TAIL_CALL_OPTIMIZATION |
| // |
| // Instructs the compiler to avoid optimizing tail-call recursion. This macro is |
| // useful when you wish to preserve the existing function order within a stack |
| // trace for logging, debugging, or profiling purposes. |
| // |
| // Example: |
| // |
| // int f() { |
| // int result = g(); |
| // ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); |
| // return result; |
| // } |
| #if defined(__pnacl__) |
| #define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; } |
| #elif defined(__clang__) |
| // Clang will not tail call given inline volatile assembly. |
| #define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("") |
| #elif defined(__GNUC__) |
| // GCC will not tail call given inline volatile assembly. |
| #define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("") |
| #elif defined(_MSC_VER) |
| #include <intrin.h> |
| // The __nop() intrinsic blocks the optimisation. |
| #define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __nop() |
| #else |
| #define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; } |
| #endif |
| |
| // ABSL_CACHELINE_SIZE |
| // |
| // Explicitly defines the size of the L1 cache for purposes of alignment. |
| // Setting the cacheline size allows you to specify that certain objects be |
| // aligned on a cacheline boundary with `ABSL_CACHELINE_ALIGNED` declarations. |
| // (See below.) |
| // |
| // NOTE: this macro should be replaced with the following C++17 features, when |
| // those are generally available: |
| // |
| // * `std::hardware_constructive_interference_size` |
| // * `std::hardware_destructive_interference_size` |
| // |
| // See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html |
| // for more information. |
| #if defined(__GNUC__) |
| // Cache line alignment |
| #if defined(__i386__) || defined(__x86_64__) |
| #define ABSL_CACHELINE_SIZE 64 |
| #elif defined(__powerpc64__) |
| #define ABSL_CACHELINE_SIZE 128 |
| #elif defined(__aarch64__) |
| // We would need to read special register ctr_el0 to find out L1 dcache size. |
| // This value is a good estimate based on a real aarch64 machine. |
| #define ABSL_CACHELINE_SIZE 64 |
| #elif defined(__arm__) |
| // Cache line sizes for ARM: These values are not strictly correct since |
| // cache line sizes depend on implementations, not architectures. There |
| // are even implementations with cache line sizes configurable at boot |
| // time. |
| #if defined(__ARM_ARCH_5T__) |
| #define ABSL_CACHELINE_SIZE 32 |
| #elif defined(__ARM_ARCH_7A__) |
| #define ABSL_CACHELINE_SIZE 64 |
| #endif |
| #endif |
| #endif |
| |
| #ifndef ABSL_CACHELINE_SIZE |
| // A reasonable default guess. Note that overestimates tend to waste more |
| // space, while underestimates tend to waste more time. |
| #define ABSL_CACHELINE_SIZE 64 |
| #endif |
| |
| // ABSL_CACHELINE_ALIGNED |
| // |
| // Indicates that the declared object be cache aligned using |
| // `ABSL_CACHELINE_SIZE` (see above). Cacheline aligning objects allows you to |
| // load a set of related objects in the L1 cache for performance improvements. |
| // Cacheline aligning objects properly allows constructive memory sharing and |
| // prevents destructive (or "false") memory sharing. |
| // |
| // NOTE: callers should replace uses of this macro with `alignas()` using |
| // `std::hardware_constructive_interference_size` and/or |
| // `std::hardware_destructive_interference_size` when C++17 becomes available to |
| // them. |
| // |
| // See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html |
| // for more information. |
| // |
| // On some compilers, `ABSL_CACHELINE_ALIGNED` expands to an `__attribute__` |
| // or `__declspec` attribute. For compilers where this is not known to work, |
| // the macro expands to nothing. |
| // |
| // No further guarantees are made here. The result of applying the macro |
| // to variables and types is always implementation-defined. |
| // |
| // WARNING: It is easy to use this attribute incorrectly, even to the point |
| // of causing bugs that are difficult to diagnose, crash, etc. It does not |
| // of itself guarantee that objects are aligned to a cache line. |
| // |
| // NOTE: Some compilers are picky about the locations of annotations such as |
| // this attribute, so prefer to put it at the beginning of your declaration. |
| // For example, |
| // |
| // ABSL_CACHELINE_ALIGNED static Foo* foo = ... |
| // |
| // class ABSL_CACHELINE_ALIGNED Bar { ... |
| // |
| // Recommendations: |
| // |
| // 1) Consult compiler documentation; this comment is not kept in sync as |
| // toolchains evolve. |
| // 2) Verify your use has the intended effect. This often requires inspecting |
| // the generated machine code. |
| // 3) Prefer applying this attribute to individual variables. Avoid |
| // applying it to types. This tends to localize the effect. |
| #if defined(__clang__) || defined(__GNUC__) |
| #define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE))) |
| #elif defined(_MSC_VER) |
| #define ABSL_CACHELINE_ALIGNED __declspec(align(ABSL_CACHELINE_SIZE)) |
| #else |
| #define ABSL_CACHELINE_ALIGNED |
| #endif |
| |
| // ABSL_PREDICT_TRUE, ABSL_PREDICT_FALSE |
| // |
| // Enables the compiler to prioritize compilation using static analysis for |
| // likely paths within a boolean branch. |
| // |
| // Example: |
| // |
| // if (ABSL_PREDICT_TRUE(expression)) { |
| // return result; // Faster if more likely |
| // } else { |
| // return 0; |
| // } |
| // |
| // Compilers can use the information that a certain branch is not likely to be |
| // taken (for instance, a CHECK failure) to optimize for the common case in |
| // the absence of better information (ie. compiling gcc with `-fprofile-arcs`). |
| // |
| // Recommendation: Modern CPUs dynamically predict branch execution paths, |
| // typically with accuracy greater than 97%. As a result, annotating every |
| // branch in a codebase is likely counterproductive; however, annotating |
| // specific branches that are both hot and consistently mispredicted is likely |
| // to yield performance improvements. |
| #if ABSL_HAVE_BUILTIN(__builtin_expect) || \ |
| (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_PREDICT_FALSE(x) (__builtin_expect(false || (x), false)) |
| #define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true)) |
| #else |
| #define ABSL_PREDICT_FALSE(x) (x) |
| #define ABSL_PREDICT_TRUE(x) (x) |
| #endif |
| |
| // `ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL()` aborts the program in the fastest |
| // possible way, with no attempt at logging. One use is to implement hardening |
| // aborts with ABSL_OPTION_HARDENED. Since this is an internal symbol, it |
| // should not be used directly outside of Abseil. |
| #if ABSL_HAVE_BUILTIN(__builtin_trap) || \ |
| (defined(__GNUC__) && !defined(__clang__)) |
| #define ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL() __builtin_trap() |
| #else |
| #define ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL() abort() |
| #endif |
| |
| // `ABSL_INTERNAL_UNREACHABLE_IMPL()` is the platform specific directive to |
| // indicate that a statement is unreachable, and to allow the compiler to |
| // optimize accordingly. Clients should use `ABSL_UNREACHABLE()`, which is |
| // defined below. |
| #if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L |
| #define ABSL_INTERNAL_UNREACHABLE_IMPL() std::unreachable() |
| #elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) |
| #define ABSL_INTERNAL_UNREACHABLE_IMPL() __builtin_unreachable() |
| #elif ABSL_HAVE_BUILTIN(__builtin_assume) |
| #define ABSL_INTERNAL_UNREACHABLE_IMPL() __builtin_assume(false) |
| #elif defined(_MSC_VER) |
| #define ABSL_INTERNAL_UNREACHABLE_IMPL() __assume(false) |
| #else |
| #define ABSL_INTERNAL_UNREACHABLE_IMPL() |
| #endif |
| |
| // `ABSL_UNREACHABLE()` is an unreachable statement. A program which reaches |
| // one has undefined behavior, and the compiler may optimize accordingly. |
| #if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG) |
| // Abort in hardened mode to avoid dangerous undefined behavior. |
| #define ABSL_UNREACHABLE() \ |
| do { \ |
| ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL(); \ |
| ABSL_INTERNAL_UNREACHABLE_IMPL(); \ |
| } while (false) |
| #else |
| // The assert only fires in debug mode to aid in debugging. |
| // When NDEBUG is defined, reaching ABSL_UNREACHABLE() is undefined behavior. |
| #define ABSL_UNREACHABLE() \ |
| do { \ |
| /* NOLINTNEXTLINE: misc-static-assert */ \ |
| assert(false && "ABSL_UNREACHABLE reached"); \ |
| ABSL_INTERNAL_UNREACHABLE_IMPL(); \ |
| } while (false) |
| #endif |
| |
| // ABSL_ASSUME(cond) |
| // |
| // Informs the compiler that a condition is always true and that it can assume |
| // it to be true for optimization purposes. |
| // |
| // WARNING: If the condition is false, the program can produce undefined and |
| // potentially dangerous behavior. |
| // |
| // In !NDEBUG mode, the condition is checked with an assert(). |
| // |
| // NOTE: The expression must not have side effects, as it may only be evaluated |
| // in some compilation modes and not others. Some compilers may issue a warning |
| // if the compiler cannot prove the expression has no side effects. For example, |
| // the expression should not use a function call since the compiler cannot prove |
| // that a function call does not have side effects. |
| // |
| // Example: |
| // |
| // int x = ...; |
| // ABSL_ASSUME(x >= 0); |
| // // The compiler can optimize the division to a simple right shift using the |
| // // assumption specified above. |
| // int y = x / 16; |
| // |
| #if !defined(NDEBUG) |
| #define ABSL_ASSUME(cond) assert(cond) |
| #elif ABSL_HAVE_BUILTIN(__builtin_assume) |
| #define ABSL_ASSUME(cond) __builtin_assume(cond) |
| #elif defined(_MSC_VER) |
| #define ABSL_ASSUME(cond) __assume(cond) |
| #elif defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L |
| #define ABSL_ASSUME(cond) ((cond) ? void() : std::unreachable()) |
| #elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) |
| #define ABSL_ASSUME(cond) ((cond) ? void() : __builtin_unreachable()) |
| #elif ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L |
| // Unimplemented. Uses the same definition as ABSL_ASSERT in the NDEBUG case. |
| #define ABSL_ASSUME(expr) (decltype((expr) ? void() : void())()) |
| #else |
| #define ABSL_ASSUME(expr) (false ? ((expr) ? void() : void()) : void()) |
| #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_ |
| *ù |
| soong/.intermediates/external/abseil-cpp/absl_strings_str_format_internal_hdrs/gen/my_include_dir/absl/strings/internal/str_format/checker.hç// Copyright 2020 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ |
| #define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ |
| |
| #include <algorithm> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/strings/internal/str_format/arg.h" |
| #include "absl/strings/internal/str_format/constexpr_parser.h" |
| #include "absl/strings/internal/str_format/extension.h" |
| |
| // Compile time check support for entry points. |
| |
| #ifndef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
| // We disable format checker under vscode intellisense compilation. |
| // See https://github.com/microsoft/vscode-cpptools/issues/3683 for |
| // more details. |
| #if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) && \ |
| !defined(__INTELLISENSE__) |
| #define ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 1 |
| #endif // ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) && |
| // !defined(__INTELLISENSE__) |
| #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace str_format_internal { |
| |
| #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
| |
| template <FormatConversionCharSet... C> |
| constexpr bool ValidFormatImpl(string_view format) { |
| int next_arg = 0; |
| const char* p = format.data(); |
| const char* const end = p + format.size(); |
| constexpr FormatConversionCharSet |
| kAllowedConvs[(std::max)(sizeof...(C), size_t{1})] = {C...}; |
| bool used[(std::max)(sizeof...(C), size_t{1})]{}; |
| constexpr int kNumArgs = sizeof...(C); |
| while (p != end) { |
| while (p != end && *p != '%') ++p; |
| if (p == end) { |
| break; |
| } |
| if (p + 1 >= end) return false; |
| if (p[1] == '%') { |
| // %% |
| p += 2; |
| continue; |
| } |
| |
| UnboundConversion conv(absl::kConstInit); |
| p = ConsumeUnboundConversion(p + 1, end, &conv, &next_arg); |
| if (p == nullptr) return false; |
| if (conv.arg_position <= 0 || conv.arg_position > kNumArgs) { |
| return false; |
| } |
| if (!Contains(kAllowedConvs[conv.arg_position - 1], conv.conv)) { |
| return false; |
| } |
| used[conv.arg_position - 1] = true; |
| for (auto extra : {conv.width, conv.precision}) { |
| if (extra.is_from_arg()) { |
| int pos = extra.get_from_arg(); |
| if (pos <= 0 || pos > kNumArgs) return false; |
| used[pos - 1] = true; |
| if (!Contains(kAllowedConvs[pos - 1], '*')) { |
| return false; |
| } |
| } |
| } |
| } |
| if (sizeof...(C) != 0) { |
| for (bool b : used) { |
| if (!b) return false; |
| } |
| } |
| return true; |
| } |
| |
| #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
| |
| } // namespace str_format_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ |
| *Ã |
| soong/.intermediates/external/abseil-cpp/absl_debugging_demangle_internal_hdrs/gen/my_include_dir/absl/debugging/internal/demangle.h¹// 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_DEBUGGING_INTERNAL_DEMANGLE_H_ |
| #define ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_ |
| |
| #include <string> |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace debugging_internal { |
| |
| // Demangle `mangled`. On success, return true and write the |
| // demangled symbol name to `out`. Otherwise, return false. |
| // `out` is modified even if demangling is unsuccessful. |
| // |
| // This function provides an alternative to libstdc++'s abi::__cxa_demangle, |
| // which is not async signal safe (it uses malloc internally). It's intended to |
| // be used in async signal handlers to symbolize stack traces. |
| // |
| // Note that this demangler doesn't support full demangling. More |
| // specifically, it doesn't print types of function parameters and |
| // types of template arguments. It just skips them. However, it's |
| // still very useful to extract basic information such as class, |
| // function, constructor, destructor, and operator names. |
| // |
| // See the implementation note in demangle.cc if you are interested. |
| // |
| // Example: |
| // |
| // | Mangled Name | Demangle | DemangleString |
| // |---------------|-------------|----------------------- |
| // | _Z1fv | f() | f() |
| // | _Z1fi | f() | f(int) |
| // | _Z3foo3bar | foo() | foo(bar) |
| // | _Z1fIiEvi | f<>() | void f<int>(int) |
| // | _ZN1N1fE | N::f | N::f |
| // | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar() |
| // | _Zrm1XS_" | operator%() | operator%(X, X) |
| // | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo() |
| // | _Z1fSs | f() | f(std::basic_string<char, |
| // | | | std::char_traits<char>, |
| // | | | std::allocator<char> >) |
| // |
| // See the unit test for more examples. |
| // |
| // Demangle also recognizes Rust mangled names by delegating the parsing of |
| // anything that starts with _R to DemangleRustSymbolEncoding (demangle_rust.h). |
| // |
| // Note: we might want to write demanglers for ABIs other than Itanium |
| // C++ ABI in the future. |
| bool Demangle(const char* mangled, char* out, size_t out_size); |
| |
| // A wrapper around `abi::__cxa_demangle()`. On success, returns the demangled |
| // name. On failure, returns the input mangled name. |
| // |
| // This function is not async-signal-safe. |
| std::string DemangleString(const char* mangled); |
| |
| } // namespace debugging_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_ |
| *㢠|
| soong/.intermediates/external/abseil-cpp/absl_container_btree_hdrs/gen/my_include_dir/absl/container/internal/btree_container.hÞ¡// Copyright 2018 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_ |
| #define ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_ |
| |
| #include <algorithm> |
| #include <initializer_list> |
| #include <iterator> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/internal/throw_delegate.h" |
| #include "absl/container/internal/btree.h" // IWYU pragma: export |
| #include "absl/container/internal/common.h" |
| #include "absl/hash/internal/weakly_mixed_integer.h" |
| #include "absl/memory/memory.h" |
| #include "absl/meta/type_traits.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace container_internal { |
| |
| // A common base class for btree_set, btree_map, btree_multiset, and |
| // btree_multimap. |
| template <typename Tree> |
| class btree_container { |
| using params_type = typename Tree::params_type; |
| |
| protected: |
| // Alias used for heterogeneous lookup functions. |
| // `key_arg<K>` evaluates to `K` when the functors are transparent and to |
| // `key_type` otherwise. It permits template argument deduction on `K` for the |
| // transparent case. |
| template <class K> |
| using key_arg = |
| typename KeyArg<params_type::kIsKeyCompareTransparent>::template type< |
| K, typename Tree::key_type>; |
| |
| public: |
| using key_type = typename Tree::key_type; |
| using value_type = typename Tree::value_type; |
| using size_type = typename Tree::size_type; |
| using difference_type = typename Tree::difference_type; |
| using key_compare = typename Tree::original_key_compare; |
| using value_compare = typename Tree::value_compare; |
| using allocator_type = typename Tree::allocator_type; |
| using reference = typename Tree::reference; |
| using const_reference = typename Tree::const_reference; |
| using pointer = typename Tree::pointer; |
| using const_pointer = typename Tree::const_pointer; |
| using iterator = typename Tree::iterator; |
| using const_iterator = typename Tree::const_iterator; |
| using reverse_iterator = typename Tree::reverse_iterator; |
| using const_reverse_iterator = typename Tree::const_reverse_iterator; |
| using node_type = typename Tree::node_handle_type; |
| |
| struct extract_and_get_next_return_type { |
| node_type node; |
| iterator next; |
| }; |
| |
| // Constructors/assignments. |
| btree_container() : tree_(key_compare(), allocator_type()) {} |
| explicit btree_container(const key_compare &comp, |
| const allocator_type &alloc = allocator_type()) |
| : tree_(comp, alloc) {} |
| explicit btree_container(const allocator_type &alloc) |
| : tree_(key_compare(), alloc) {} |
| |
| btree_container(const btree_container &other) |
| : btree_container(other, absl::allocator_traits<allocator_type>:: |
| select_on_container_copy_construction( |
| other.get_allocator())) {} |
| btree_container(const btree_container &other, const allocator_type &alloc) |
| : tree_(other.tree_, alloc) {} |
| |
| btree_container(btree_container &&other) noexcept( |
| std::is_nothrow_move_constructible<Tree>::value) = default; |
| btree_container(btree_container &&other, const allocator_type &alloc) |
| : tree_(std::move(other.tree_), alloc) {} |
| |
| btree_container &operator=(const btree_container &other) = default; |
| btree_container &operator=(btree_container &&other) noexcept( |
| std::is_nothrow_move_assignable<Tree>::value) = default; |
| |
| // Iterator routines. |
| iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { return tree_.begin(); } |
| const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.begin(); |
| } |
| const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.begin(); |
| } |
| iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return tree_.end(); } |
| const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.end(); |
| } |
| const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.end(); |
| } |
| reverse_iterator rbegin() ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.rbegin(); |
| } |
| const_reverse_iterator rbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.rbegin(); |
| } |
| const_reverse_iterator crbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.rbegin(); |
| } |
| reverse_iterator rend() ABSL_ATTRIBUTE_LIFETIME_BOUND { return tree_.rend(); } |
| const_reverse_iterator rend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.rend(); |
| } |
| const_reverse_iterator crend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.rend(); |
| } |
| |
| // Lookup routines. |
| template <typename K = key_type> |
| size_type count(const key_arg<K> &key) const { |
| auto equal_range = this->equal_range(key); |
| return equal_range.second - equal_range.first; |
| } |
| template <typename K = key_type> |
| iterator find(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.find(key); |
| } |
| template <typename K = key_type> |
| const_iterator find(const key_arg<K> &key) const |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.find(key); |
| } |
| template <typename K = key_type> |
| bool contains(const key_arg<K> &key) const { |
| return find(key) != end(); |
| } |
| template <typename K = key_type> |
| iterator lower_bound(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.lower_bound(key); |
| } |
| template <typename K = key_type> |
| const_iterator lower_bound(const key_arg<K> &key) const |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.lower_bound(key); |
| } |
| template <typename K = key_type> |
| iterator upper_bound(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.upper_bound(key); |
| } |
| template <typename K = key_type> |
| const_iterator upper_bound(const key_arg<K> &key) const |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.upper_bound(key); |
| } |
| template <typename K = key_type> |
| std::pair<iterator, iterator> equal_range(const key_arg<K> &key) |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.equal_range(key); |
| } |
| template <typename K = key_type> |
| std::pair<const_iterator, const_iterator> equal_range( |
| const key_arg<K> &key) const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.equal_range(key); |
| } |
| |
| // Deletion routines. Note that there is also a deletion routine that is |
| // specific to btree_set_container/btree_multiset_container. |
| |
| // Erase the specified iterator from the btree. The iterator must be valid |
| // (i.e. not equal to end()). Return an iterator pointing to the node after |
| // the one that was erased (or end() if none exists). |
| iterator erase(const_iterator iter) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.erase(iterator(iter)); |
| } |
| iterator erase(iterator iter) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.erase(iter); |
| } |
| iterator erase(const_iterator first, |
| const_iterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return tree_.erase_range(iterator(first), iterator(last)).second; |
| } |
| template <typename K = key_type> |
| size_type erase(const key_arg<K> &key) { |
| auto equal_range = this->equal_range(key); |
| return tree_.erase_range(equal_range.first, equal_range.second).first; |
| } |
| |
| // Extract routines. |
| extract_and_get_next_return_type extract_and_get_next(const_iterator position) |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| // Use Construct instead of Transfer because the rebalancing code will |
| // destroy the slot later. |
| // Note: we rely on erase() taking place after Construct(). |
| return {CommonAccess::Construct<node_type>(get_allocator(), |
| iterator(position).slot()), |
| erase(position)}; |
| } |
| node_type extract(iterator position) { |
| // Use Construct instead of Transfer because the rebalancing code will |
| // destroy the slot later. |
| auto node = |
| CommonAccess::Construct<node_type>(get_allocator(), position.slot()); |
| erase(position); |
| return node; |
| } |
| node_type extract(const_iterator position) { |
| return extract(iterator(position)); |
| } |
| |
| // Utility routines. |
| ABSL_ATTRIBUTE_REINITIALIZES void clear() { tree_.clear(); } |
| void swap(btree_container &other) { tree_.swap(other.tree_); } |
| void verify() const { tree_.verify(); } |
| |
| // Size routines. |
| size_type size() const { return tree_.size(); } |
| size_type max_size() const { return tree_.max_size(); } |
| bool empty() const { return tree_.empty(); } |
| |
| friend bool operator==(const btree_container &x, const btree_container &y) { |
| if (x.size() != y.size()) return false; |
| return std::equal(x.begin(), x.end(), y.begin()); |
| } |
| |
| friend bool operator!=(const btree_container &x, const btree_container &y) { |
| return !(x == y); |
| } |
| |
| friend bool operator<(const btree_container &x, const btree_container &y) { |
| return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); |
| } |
| |
| friend bool operator>(const btree_container &x, const btree_container &y) { |
| return y < x; |
| } |
| |
| friend bool operator<=(const btree_container &x, const btree_container &y) { |
| return !(y < x); |
| } |
| |
| friend bool operator>=(const btree_container &x, const btree_container &y) { |
| return !(x < y); |
| } |
| |
| // The allocator used by the btree. |
| allocator_type get_allocator() const { return tree_.get_allocator(); } |
| |
| // The key comparator used by the btree. |
| key_compare key_comp() const { return key_compare(tree_.key_comp()); } |
| value_compare value_comp() const { return tree_.value_comp(); } |
| |
| // Support absl::Hash. |
| template <typename State> |
| friend State AbslHashValue(State h, const btree_container &b) { |
| for (const auto &v : b) { |
| h = State::combine(std::move(h), v); |
| } |
| return State::combine(std::move(h), |
| hash_internal::WeaklyMixedInteger{b.size()}); |
| } |
| |
| protected: |
| friend struct btree_access; |
| Tree tree_; |
| }; |
| |
| // A common base class for btree_set and btree_map. |
| template <typename Tree> |
| class btree_set_container : public btree_container<Tree> { |
| using super_type = btree_container<Tree>; |
| using params_type = typename Tree::params_type; |
| using init_type = typename params_type::init_type; |
| using is_key_compare_to = typename params_type::is_key_compare_to; |
| friend class BtreeNodePeer; |
| |
| protected: |
| template <class K> |
| using key_arg = typename super_type::template key_arg<K>; |
| |
| public: |
| using key_type = typename Tree::key_type; |
| using value_type = typename Tree::value_type; |
| using size_type = typename Tree::size_type; |
| using key_compare = typename Tree::original_key_compare; |
| using allocator_type = typename Tree::allocator_type; |
| using iterator = typename Tree::iterator; |
| using const_iterator = typename Tree::const_iterator; |
| using node_type = typename super_type::node_type; |
| using insert_return_type = InsertReturnType<iterator, node_type>; |
| |
| // Inherit constructors. |
| using super_type::super_type; |
| btree_set_container() {} |
| |
| // Range constructors. |
| template <class InputIterator> |
| btree_set_container(InputIterator b, InputIterator e, |
| const key_compare &comp = key_compare(), |
| const allocator_type &alloc = allocator_type()) |
| : super_type(comp, alloc) { |
| insert(b, e); |
| } |
| template <class InputIterator> |
| btree_set_container(InputIterator b, InputIterator e, |
| const allocator_type &alloc) |
| : btree_set_container(b, e, key_compare(), alloc) {} |
| |
| // Initializer list constructors. |
| btree_set_container(std::initializer_list<init_type> init, |
| const key_compare &comp = key_compare(), |
| const allocator_type &alloc = allocator_type()) |
| : btree_set_container(init.begin(), init.end(), comp, alloc) {} |
| btree_set_container(std::initializer_list<init_type> init, |
| const allocator_type &alloc) |
| : btree_set_container(init.begin(), init.end(), alloc) {} |
| |
| // Insertion routines. |
| std::pair<iterator, bool> insert(const value_type &v) |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return this->tree_.insert_unique(params_type::key(v), v); |
| } |
| std::pair<iterator, bool> insert(value_type &&v) |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return this->tree_.insert_unique(params_type::key(v), std::move(v)); |
| } |
| template <typename... Args> |
| std::pair<iterator, bool> emplace(Args &&...args) |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| // Use a node handle to manage a temp slot. |
| auto node = CommonAccess::Construct<node_type>(this->get_allocator(), |
| std::forward<Args>(args)...); |
| auto *slot = CommonAccess::GetSlot(node); |
| return this->tree_.insert_unique(params_type::key(slot), slot); |
| } |
| iterator insert(const_iterator hint, |
| const value_type &v) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return this->tree_ |
| .insert_hint_unique(iterator(hint), params_type::key(v), v) |
| .first; |
| } |
| iterator insert(const_iterator hint, |
| value_type &&v) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return this->tree_ |
| .insert_hint_unique(iterator(hint), params_type::key(v), std::move(v)) |
| .first; |
| } |
| template <typename... Args> |
| iterator emplace_hint(const_iterator hint, |
| Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| // Use a node handle to manage a temp slot. |
| auto node = CommonAccess::Construct<node_type>(this->get_allocator(), |
| std::forward<Args>(args)...); |
| auto *slot = CommonAccess::GetSlot(node); |
| return this->tree_ |
| .insert_hint_unique(iterator(hint), params_type::key(slot), slot) |
| .first; |
| } |
| template <typename InputIterator> |
| void insert(InputIterator b, InputIterator e) { |
| this->tree_.insert_iterator_unique(b, e, 0); |
| } |
| void insert(std::initializer_list<init_type> init) { |
| this->tree_.insert_iterator_unique(init.begin(), init.end(), 0); |
| } |
| insert_return_type insert(node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| if (!node) return {this->end(), false, node_type()}; |
| std::pair<iterator, bool> res = |
| this->tree_.insert_unique(params_type::key(CommonAccess::GetSlot(node)), |
| CommonAccess::GetSlot(node)); |
| if (res.second) { |
| CommonAccess::Destroy(&node); |
| return {res.first, true, node_type()}; |
| } else { |
| return {res.first, false, std::move(node)}; |
| } |
| } |
| iterator insert(const_iterator hint, |
| node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| if (!node) return this->end(); |
| std::pair<iterator, bool> res = this->tree_.insert_hint_unique( |
| iterator(hint), params_type::key(CommonAccess::GetSlot(node)), |
| CommonAccess::GetSlot(node)); |
| if (res.second) CommonAccess::Destroy(&node); |
| return res.first; |
| } |
| |
| // Node extraction routines. |
| template <typename K = key_type> |
| node_type extract(const key_arg<K> &key) { |
| const std::pair<iterator, bool> lower_and_equal = |
| this->tree_.lower_bound_equal(key); |
| return lower_and_equal.second ? extract(lower_and_equal.first) |
| : node_type(); |
| } |
| using super_type::extract; |
| |
| // Merge routines. |
| // Moves elements from `src` into `this`. If the element already exists in |
| // `this`, it is left unmodified in `src`. |
| template < |
| typename T, |
| typename absl::enable_if_t< |
| absl::conjunction< |
| std::is_same<value_type, typename T::value_type>, |
| std::is_same<allocator_type, typename T::allocator_type>, |
| std::is_same<typename params_type::is_map_container, |
| typename T::params_type::is_map_container>>::value, |
| int> = 0> |
| void merge(btree_container<T> &src) { // NOLINT |
| for (auto src_it = src.begin(); src_it != src.end();) { |
| if (insert(std::move(params_type::element(src_it.slot()))).second) { |
| src_it = src.erase(src_it); |
| } else { |
| ++src_it; |
| } |
| } |
| } |
| |
| template < |
| typename T, |
| typename absl::enable_if_t< |
| absl::conjunction< |
| std::is_same<value_type, typename T::value_type>, |
| std::is_same<allocator_type, typename T::allocator_type>, |
| std::is_same<typename params_type::is_map_container, |
| typename T::params_type::is_map_container>>::value, |
| int> = 0> |
| void merge(btree_container<T> &&src) { |
| merge(src); |
| } |
| }; |
| |
| // Base class for btree_map. |
| template <typename Tree> |
| class btree_map_container : public btree_set_container<Tree> { |
| using super_type = btree_set_container<Tree>; |
| using params_type = typename Tree::params_type; |
| friend class BtreeNodePeer; |
| |
| private: |
| template <class K> |
| using key_arg = typename super_type::template key_arg<K>; |
| |
| // NOTE: The mess here is to shorten the code for the (very repetitive) |
| // function overloads, and to allow the lifetime-bound overloads to dispatch |
| // to the non-lifetime-bound overloads, to ensure there is a single source of |
| // truth for each overload set. |
| // |
| // Enabled if an assignment from the given type would require the |
| // source object to remain alive for the life of the element. |
| // |
| // TODO(b/402804213): Remove these traits and simplify the overloads whenever |
| // we have a better mechanism available to handle lifetime analysis. |
| template <class K, bool Value, typename = void> |
| using LifetimeBoundK = |
| HasValue<Value, type_traits_internal::IsLifetimeBoundAssignment< |
| typename Tree::key_type, K>>; |
| template <class M, bool Value, typename = void> |
| using LifetimeBoundV = |
| HasValue<Value, type_traits_internal::IsLifetimeBoundAssignment< |
| typename Tree::params_type::mapped_type, M>>; |
| template <class K, bool KValue, class M, bool MValue, typename... Dummy> |
| using LifetimeBoundKV = |
| absl::conjunction<LifetimeBoundK<K, KValue, absl::void_t<Dummy...>>, |
| LifetimeBoundV<M, MValue>>; |
| |
| public: |
| using key_type = typename Tree::key_type; |
| using mapped_type = typename params_type::mapped_type; |
| using value_type = typename Tree::value_type; |
| using key_compare = typename Tree::original_key_compare; |
| using allocator_type = typename Tree::allocator_type; |
| using iterator = typename Tree::iterator; |
| using const_iterator = typename Tree::const_iterator; |
| |
| // Inherit constructors. |
| using super_type::super_type; |
| btree_map_container() {} |
| |
| // TODO(b/402804213): Remove these macros whenever we have a better mechanism |
| // available to handle lifetime analysis. |
| #define ABSL_INTERNAL_X(Func, Callee, KQual, MQual, KValue, MValue, ...) \ |
| template < \ |
| typename K = key_type, class M, \ |
| ABSL_INTERNAL_IF_##KValue##_NOR_##MValue( \ |
| int = (EnableIf<LifetimeBoundKV<K, KValue, M, MValue, \ |
| IfRRef<int KQual>::AddPtr<K>, \ |
| IfRRef<int MQual>::AddPtr<M>>>()), \ |
| ABSL_INTERNAL_SINGLE_ARG( \ |
| int &..., \ |
| decltype(EnableIf<LifetimeBoundKV<K, KValue, M, MValue>>()) = \ |
| 0))> \ |
| decltype(auto) Func( \ |
| __VA_ARGS__ key_arg<K> KQual k ABSL_INTERNAL_IF_##KValue( \ |
| ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this)), \ |
| M MQual obj ABSL_INTERNAL_IF_##MValue( \ |
| ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))) \ |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { \ |
| return ABSL_INTERNAL_IF_##KValue##_OR_##MValue( \ |
| (this->template Func<K, M, 0>), Callee)( \ |
| __VA_ARGS__ std::forward<decltype(k)>(k), \ |
| std::forward<decltype(obj)>(obj)); \ |
| } \ |
| friend struct std::enable_if<false> /* just to force a semicolon */ |
| // Insertion routines. |
| // Note: the nullptr template arguments and extra `const M&` overloads allow |
| // for supporting bitfield arguments. |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, |
| false, false); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, |
| false, true); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, |
| true, false); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, |
| true, true); |
| |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false, |
| false); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false, |
| true); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true, |
| false); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true, |
| true); |
| |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false, |
| false); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false, |
| true); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true, |
| false); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true, |
| true); |
| |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false, |
| false); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false, true); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, false); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, true); |
| |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, |
| const &, false, false, |
| const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, |
| const &, false, true, |
| const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, |
| const &, true, false, |
| const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, |
| const &, true, true, |
| const_iterator(hint) ABSL_INTERNAL_COMMA); |
| |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, &&, |
| false, false, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, &&, |
| false, true, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, &&, |
| true, false, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, &&, |
| true, true, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, const &, |
| false, false, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, const &, |
| false, true, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, const &, |
| true, false, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, const &, |
| true, true, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, &&, false, |
| false, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, &&, false, |
| true, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, &&, true, |
| false, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, &&, true, |
| true, const_iterator(hint) ABSL_INTERNAL_COMMA); |
| #undef ABSL_INTERNAL_X |
| |
| #define ABSL_INTERNAL_X(Func, Callee, KQual, KValue, ...) \ |
| template < \ |
| class K = key_type, \ |
| ABSL_INTERNAL_IF_##KValue( \ |
| class... Args, \ |
| int = (EnableIf< \ |
| LifetimeBoundK<K, KValue, IfRRef<int KQual>::AddPtr<K>>>())), \ |
| ABSL_INTERNAL_IF_##KValue( \ |
| decltype(EnableIf<LifetimeBoundK< \ |
| K, KValue, IfRRef<int KQual>::AddPtr<K>>>()) = 0, \ |
| class... Args), \ |
| std::enable_if_t<!std::is_convertible<K, const_iterator>::value, int> = \ |
| 0> \ |
| decltype(auto) Func( \ |
| __VA_ARGS__ key_arg<K> KQual k ABSL_INTERNAL_IF_##KValue( \ |
| ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this)), \ |
| Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { \ |
| return ABSL_INTERNAL_IF_##KValue((this->template Func<K, 0>), Callee)( \ |
| __VA_ARGS__ std::forward<decltype(k)>(k), \ |
| std::forward<decltype(args)>(args)...); \ |
| } \ |
| friend struct std::enable_if<false> /* just to force a semicolon */ |
| ABSL_INTERNAL_X(try_emplace, try_emplace_impl, const &, false); |
| ABSL_INTERNAL_X(try_emplace, try_emplace_impl, const &, true); |
| ABSL_INTERNAL_X(try_emplace, try_emplace_impl, &&, false); |
| ABSL_INTERNAL_X(try_emplace, try_emplace_impl, &&, true); |
| ABSL_INTERNAL_X(try_emplace, try_emplace_hint_impl, const &, false, |
| const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(try_emplace, try_emplace_hint_impl, const &, true, |
| const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(try_emplace, try_emplace_hint_impl, &&, false, |
| const_iterator(hint) ABSL_INTERNAL_COMMA); |
| ABSL_INTERNAL_X(try_emplace, try_emplace_hint_impl, &&, true, |
| const_iterator(hint) ABSL_INTERNAL_COMMA); |
| #undef ABSL_INTERNAL_X |
| |
| template <class K = key_type, int = EnableIf<LifetimeBoundK<K, false>>()> |
| mapped_type &operator[](const key_arg<K> &k) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return try_emplace(k).first->second; |
| } |
| template <class K = key_type, int &..., EnableIf<LifetimeBoundK<K, true>> = 0> |
| mapped_type &operator[]( |
| const key_arg<K> &k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this)) |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return this->template operator[]<K, 0>(k); |
| } |
| template <class K = key_type, int = EnableIf<LifetimeBoundK<K, false>>()> |
| mapped_type &operator[](key_arg<K> &&k) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return try_emplace(std::forward<K>(k)).first->second; |
| } |
| template <class K = key_type, int &..., EnableIf<LifetimeBoundK<K, true>> = 0> |
| mapped_type &operator[](key_arg<K> &&k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY( |
| this)) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return this->template operator[]<K, 0>(std::forward<K>(k)); |
| } |
| |
| template <typename K = key_type> |
| mapped_type &at(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| auto it = this->find(key); |
| if (it == this->end()) |
| base_internal::ThrowStdOutOfRange("absl::btree_map::at"); |
| return it->second; |
| } |
| template <typename K = key_type> |
| const mapped_type &at(const key_arg<K> &key) const |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| auto it = this->find(key); |
| if (it == this->end()) |
| base_internal::ThrowStdOutOfRange("absl::btree_map::at"); |
| return it->second; |
| } |
| |
| private: |
| // Note: when we call `std::forward<M>(obj)` twice, it's safe because |
| // insert_unique/insert_hint_unique are guaranteed to not consume `obj` when |
| // `ret.second` is false. |
| template <class K, class M> |
| std::pair<iterator, bool> insert_or_assign_impl(K &&k, M &&obj) { |
| const std::pair<iterator, bool> ret = |
| this->tree_.insert_unique(k, std::forward<K>(k), std::forward<M>(obj)); |
| if (!ret.second) ret.first->second = std::forward<M>(obj); |
| return ret; |
| } |
| template <class K, class M> |
| iterator insert_or_assign_hint_impl(const_iterator hint, K &&k, M &&obj) { |
| const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique( |
| iterator(hint), k, std::forward<K>(k), std::forward<M>(obj)); |
| if (!ret.second) ret.first->second = std::forward<M>(obj); |
| return ret.first; |
| } |
| |
| template <class K, class... Args> |
| std::pair<iterator, bool> try_emplace_impl(K &&k, Args &&... args) { |
| return this->tree_.insert_unique( |
| k, std::piecewise_construct, std::forward_as_tuple(std::forward<K>(k)), |
| std::forward_as_tuple(std::forward<Args>(args)...)); |
| } |
| template <class K, class... Args> |
| iterator try_emplace_hint_impl(const_iterator hint, K &&k, Args &&... args) { |
| return this->tree_ |
| .insert_hint_unique(iterator(hint), k, std::piecewise_construct, |
| std::forward_as_tuple(std::forward<K>(k)), |
| std::forward_as_tuple(std::forward<Args>(args)...)) |
| .first; |
| } |
| }; |
| |
| // A common base class for btree_multiset and btree_multimap. |
| template <typename Tree> |
| class btree_multiset_container : public btree_container<Tree> { |
| using super_type = btree_container<Tree>; |
| using params_type = typename Tree::params_type; |
| using init_type = typename params_type::init_type; |
| using is_key_compare_to = typename params_type::is_key_compare_to; |
| friend class BtreeNodePeer; |
| |
| template <class K> |
| using key_arg = typename super_type::template key_arg<K>; |
| |
| public: |
| using key_type = typename Tree::key_type; |
| using value_type = typename Tree::value_type; |
| using size_type = typename Tree::size_type; |
| using key_compare = typename Tree::original_key_compare; |
| using allocator_type = typename Tree::allocator_type; |
| using iterator = typename Tree::iterator; |
| using const_iterator = typename Tree::const_iterator; |
| using node_type = typename super_type::node_type; |
| |
| // Inherit constructors. |
| using super_type::super_type; |
| btree_multiset_container() {} |
| |
| // Range constructors. |
| template <class InputIterator> |
| btree_multiset_container(InputIterator b, InputIterator e, |
| const key_compare &comp = key_compare(), |
| const allocator_type &alloc = allocator_type()) |
| : super_type(comp, alloc) { |
| insert(b, e); |
| } |
| template <class InputIterator> |
| btree_multiset_container(InputIterator b, InputIterator e, |
| const allocator_type &alloc) |
| : btree_multiset_container(b, e, key_compare(), alloc) {} |
| |
| // Initializer list constructors. |
| btree_multiset_container(std::initializer_list<init_type> init, |
| const key_compare &comp = key_compare(), |
| const allocator_type &alloc = allocator_type()) |
| : btree_multiset_container(init.begin(), init.end(), comp, alloc) {} |
| btree_multiset_container(std::initializer_list<init_type> init, |
| const allocator_type &alloc) |
| : btree_multiset_container(init.begin(), init.end(), alloc) {} |
| |
| // Insertion routines. |
| iterator insert(const value_type &v) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return this->tree_.insert_multi(v); |
| } |
| iterator insert(value_type &&v) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return this->tree_.insert_multi(std::move(v)); |
| } |
| iterator insert(const_iterator hint, |
| const value_type &v) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return this->tree_.insert_hint_multi(iterator(hint), v); |
| } |
| iterator insert(const_iterator hint, |
| value_type &&v) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return this->tree_.insert_hint_multi(iterator(hint), std::move(v)); |
| } |
| template <typename InputIterator> |
| void insert(InputIterator b, InputIterator e) { |
| this->tree_.insert_iterator_multi(b, e); |
| } |
| void insert(std::initializer_list<init_type> init) { |
| this->tree_.insert_iterator_multi(init.begin(), init.end()); |
| } |
| template <typename... Args> |
| iterator emplace(Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| // Use a node handle to manage a temp slot. |
| auto node = CommonAccess::Construct<node_type>(this->get_allocator(), |
| std::forward<Args>(args)...); |
| return this->tree_.insert_multi(CommonAccess::GetSlot(node)); |
| } |
| template <typename... Args> |
| iterator emplace_hint(const_iterator hint, |
| Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| // Use a node handle to manage a temp slot. |
| auto node = CommonAccess::Construct<node_type>(this->get_allocator(), |
| std::forward<Args>(args)...); |
| return this->tree_.insert_hint_multi(iterator(hint), |
| CommonAccess::GetSlot(node)); |
| } |
| iterator insert(node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| if (!node) return this->end(); |
| iterator res = |
| this->tree_.insert_multi(params_type::key(CommonAccess::GetSlot(node)), |
| CommonAccess::GetSlot(node)); |
| CommonAccess::Destroy(&node); |
| return res; |
| } |
| iterator insert(const_iterator hint, |
| node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| if (!node) return this->end(); |
| iterator res = this->tree_.insert_hint_multi( |
| iterator(hint), |
| std::move(params_type::element(CommonAccess::GetSlot(node)))); |
| CommonAccess::Destroy(&node); |
| return res; |
| } |
| |
| // Node extraction routines. |
| template <typename K = key_type> |
| node_type extract(const key_arg<K> &key) { |
| const std::pair<iterator, bool> lower_and_equal = |
| this->tree_.lower_bound_equal(key); |
| return lower_and_equal.second ? extract(lower_and_equal.first) |
| : node_type(); |
| } |
| using super_type::extract; |
| |
| // Merge routines. |
| // Moves all elements from `src` into `this`. |
| template < |
| typename T, |
| typename absl::enable_if_t< |
| absl::conjunction< |
| std::is_same<value_type, typename T::value_type>, |
| std::is_same<allocator_type, typename T::allocator_type>, |
| std::is_same<typename params_type::is_map_container, |
| typename T::params_type::is_map_container>>::value, |
| int> = 0> |
| void merge(btree_container<T> &src) { // NOLINT |
| for (auto src_it = src.begin(), end = src.end(); src_it != end; ++src_it) { |
| insert(std::move(params_type::element(src_it.slot()))); |
| } |
| src.clear(); |
| } |
| |
| template < |
| typename T, |
| typename absl::enable_if_t< |
| absl::conjunction< |
| std::is_same<value_type, typename T::value_type>, |
| std::is_same<allocator_type, typename T::allocator_type>, |
| std::is_same<typename params_type::is_map_container, |
| typename T::params_type::is_map_container>>::value, |
| int> = 0> |
| void merge(btree_container<T> &&src) { |
| merge(src); |
| } |
| }; |
| |
| // A base class for btree_multimap. |
| template <typename Tree> |
| class btree_multimap_container : public btree_multiset_container<Tree> { |
| using super_type = btree_multiset_container<Tree>; |
| using params_type = typename Tree::params_type; |
| friend class BtreeNodePeer; |
| |
| public: |
| using mapped_type = typename params_type::mapped_type; |
| |
| // Inherit constructors. |
| using super_type::super_type; |
| btree_multimap_container() {} |
| }; |
| |
| } // namespace container_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_ |
| * |
| soong/.intermediates/external/abseil-cpp/absl_strings_cord_internal_hdrs/gen/my_include_dir/absl/strings/internal/cord_rep_crc.h// 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_STRINGS_INTERNAL_CORD_REP_CRC_H_ |
| #define ABSL_STRINGS_INTERNAL_CORD_REP_CRC_H_ |
| |
| #include <cassert> |
| #include <cstdint> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/optimization.h" |
| #include "absl/crc/internal/crc_cord_state.h" |
| #include "absl/strings/internal/cord_internal.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // CordRepCrc is a CordRep node intended only to appear at the top level of a |
| // cord tree. It associates an "expected CRC" with the contained data, to allow |
| // for easy passage of checksum data in Cord data flows. |
| // |
| // From Cord's perspective, the crc value has no semantics; any validation of |
| // the contained checksum is the user's responsibility. |
| struct CordRepCrc : public CordRep { |
| CordRep* child; |
| absl::crc_internal::CrcCordState crc_cord_state; |
| |
| // Consumes `child` and returns a CordRepCrc prefixed tree containing `child`. |
| // If the specified `child` is itself a CordRepCrc node, then this method |
| // either replaces the existing node, or directly updates the crc state in it |
| // depending on the node being shared or not, i.e.: refcount.IsOne(). |
| // `child` must only be null if the Cord is empty. Never returns null. |
| static CordRepCrc* New(CordRep* child, crc_internal::CrcCordState state); |
| |
| // Destroys (deletes) the provided node. `node` must not be null. |
| static void Destroy(CordRepCrc* node); |
| }; |
| |
| // Consumes `rep` and returns a CordRep* with any outer CordRepCrc wrapper |
| // removed. This is usually a no-op (returning `rep`), but this will remove and |
| // unref an outer CordRepCrc node. |
| inline CordRep* RemoveCrcNode(CordRep* rep) { |
| assert(rep != nullptr); |
| if (ABSL_PREDICT_FALSE(rep->IsCrc())) { |
| CordRep* child = rep->crc()->child; |
| if (rep->refcount.IsOne()) { |
| delete rep->crc(); |
| } else { |
| CordRep::Ref(child); |
| CordRep::Unref(rep); |
| } |
| return child; |
| } |
| return rep; |
| } |
| |
| // Returns `rep` if it is not a CordRepCrc node, or its child if it is. |
| // Does not consume or create a reference on `rep` or the returned value. |
| inline CordRep* SkipCrcNode(CordRep* rep) { |
| assert(rep != nullptr); |
| if (ABSL_PREDICT_FALSE(rep->IsCrc())) { |
| return rep->crc()->child; |
| } else { |
| return rep; |
| } |
| } |
| |
| inline const CordRep* SkipCrcNode(const CordRep* rep) { |
| assert(rep != nullptr); |
| if (ABSL_PREDICT_FALSE(rep->IsCrc())) { |
| return rep->crc()->child; |
| } else { |
| return rep; |
| } |
| } |
| |
| inline CordRepCrc* CordRep::crc() { |
| assert(IsCrc()); |
| return static_cast<CordRepCrc*>(this); |
| } |
| |
| inline const CordRepCrc* CordRep::crc() const { |
| assert(IsCrc()); |
| return static_cast<const CordRepCrc*>(this); |
| } |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORD_REP_CRC_H_ |
| *÷ |
| soong/.intermediates/external/abseil-cpp/absl_container_container_memory_hdrs/gen/my_include_dir/absl/container/internal/container_memory.hå// Copyright 2018 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_ |
| #define ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_ |
| |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <memory> |
| #include <new> |
| #include <tuple> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/config.h" |
| #include "absl/memory/memory.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/utility/utility.h" |
| |
| #ifdef ABSL_HAVE_ADDRESS_SANITIZER |
| #include <sanitizer/asan_interface.h> |
| #endif |
| |
| #ifdef ABSL_HAVE_MEMORY_SANITIZER |
| #include <sanitizer/msan_interface.h> |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace container_internal { |
| |
| template <size_t Alignment> |
| struct alignas(Alignment) AlignedType {}; |
| |
| // Allocates at least n bytes aligned to the specified alignment. |
| // Alignment must be a power of 2. It must be positive. |
| // |
| // Note that many allocators don't honor alignment requirements above certain |
| // threshold (usually either alignof(std::max_align_t) or alignof(void*)). |
| // Allocate() doesn't apply alignment corrections. If the underlying allocator |
| // returns insufficiently alignment pointer, that's what you are going to get. |
| template <size_t Alignment, class Alloc> |
| void* Allocate(Alloc* alloc, size_t n) { |
| static_assert(Alignment > 0, ""); |
| assert(n && "n must be positive"); |
| using M = AlignedType<Alignment>; |
| using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>; |
| using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>; |
| // On macOS, "mem_alloc" is a #define with one argument defined in |
| // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it |
| // with the "foo(bar)" syntax. |
| A my_mem_alloc(*alloc); |
| void* p = AT::allocate(my_mem_alloc, (n + sizeof(M) - 1) / sizeof(M)); |
| assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 && |
| "allocator does not respect alignment"); |
| return p; |
| } |
| |
| // Returns true if the destruction of the value with given Allocator will be |
| // trivial. |
| template <class Allocator, class ValueType> |
| constexpr auto IsDestructionTrivial() { |
| constexpr bool result = |
| std::is_trivially_destructible<ValueType>::value && |
| std::is_same<typename absl::allocator_traits< |
| Allocator>::template rebind_alloc<char>, |
| std::allocator<char>>::value; |
| return std::integral_constant<bool, result>(); |
| } |
| |
| // The pointer must have been previously obtained by calling |
| // Allocate<Alignment>(alloc, n). |
| template <size_t Alignment, class Alloc> |
| void Deallocate(Alloc* alloc, void* p, size_t n) { |
| static_assert(Alignment > 0, ""); |
| assert(n && "n must be positive"); |
| using M = AlignedType<Alignment>; |
| using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>; |
| using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>; |
| // On macOS, "mem_alloc" is a #define with one argument defined in |
| // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it |
| // with the "foo(bar)" syntax. |
| A my_mem_alloc(*alloc); |
| AT::deallocate(my_mem_alloc, static_cast<M*>(p), |
| (n + sizeof(M) - 1) / sizeof(M)); |
| } |
| |
| namespace memory_internal { |
| |
| // Constructs T into uninitialized storage pointed by `ptr` using the args |
| // specified in the tuple. |
| template <class Alloc, class T, class Tuple, size_t... I> |
| void ConstructFromTupleImpl(Alloc* alloc, T* ptr, Tuple&& t, |
| absl::index_sequence<I...>) { |
| absl::allocator_traits<Alloc>::construct( |
| *alloc, ptr, std::get<I>(std::forward<Tuple>(t))...); |
| } |
| |
| template <class T, class F> |
| struct WithConstructedImplF { |
| template <class... Args> |
| decltype(std::declval<F>()(std::declval<T>())) operator()( |
| Args&&... args) const { |
| return std::forward<F>(f)(T(std::forward<Args>(args)...)); |
| } |
| F&& f; |
| }; |
| |
| template <class T, class Tuple, size_t... Is, class F> |
| decltype(std::declval<F>()(std::declval<T>())) WithConstructedImpl( |
| Tuple&& t, absl::index_sequence<Is...>, F&& f) { |
| return WithConstructedImplF<T, F>{std::forward<F>(f)}( |
| std::get<Is>(std::forward<Tuple>(t))...); |
| } |
| |
| template <class T, size_t... Is> |
| auto TupleRefImpl(T&& t, absl::index_sequence<Is...>) |
| -> decltype(std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...)) { |
| return std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...); |
| } |
| |
| // Returns a tuple of references to the elements of the input tuple. T must be a |
| // tuple. |
| template <class T> |
| auto TupleRef(T&& t) -> decltype(TupleRefImpl( |
| std::forward<T>(t), |
| absl::make_index_sequence< |
| std::tuple_size<typename std::decay<T>::type>::value>())) { |
| return TupleRefImpl( |
| std::forward<T>(t), |
| absl::make_index_sequence< |
| std::tuple_size<typename std::decay<T>::type>::value>()); |
| } |
| |
| template <class F, class K, class V> |
| decltype(std::declval<F>()(std::declval<const K&>(), std::piecewise_construct, |
| std::declval<std::tuple<K>>(), std::declval<V>())) |
| DecomposePairImpl(F&& f, std::pair<std::tuple<K>, V> p) { |
| const auto& key = std::get<0>(p.first); |
| return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first), |
| std::move(p.second)); |
| } |
| |
| } // namespace memory_internal |
| |
| // Constructs T into uninitialized storage pointed by `ptr` using the args |
| // specified in the tuple. |
| template <class Alloc, class T, class Tuple> |
| void ConstructFromTuple(Alloc* alloc, T* ptr, Tuple&& t) { |
| memory_internal::ConstructFromTupleImpl( |
| alloc, ptr, std::forward<Tuple>(t), |
| absl::make_index_sequence< |
| std::tuple_size<typename std::decay<Tuple>::type>::value>()); |
| } |
| |
| // Constructs T using the args specified in the tuple and calls F with the |
| // constructed value. |
| template <class T, class Tuple, class F> |
| decltype(std::declval<F>()(std::declval<T>())) WithConstructed(Tuple&& t, |
| F&& f) { |
| return memory_internal::WithConstructedImpl<T>( |
| std::forward<Tuple>(t), |
| absl::make_index_sequence< |
| std::tuple_size<typename std::decay<Tuple>::type>::value>(), |
| std::forward<F>(f)); |
| } |
| |
| // Given arguments of an std::pair's constructor, PairArgs() returns a pair of |
| // tuples with references to the passed arguments. The tuples contain |
| // constructor arguments for the first and the second elements of the pair. |
| // |
| // The following two snippets are equivalent. |
| // |
| // 1. std::pair<F, S> p(args...); |
| // |
| // 2. auto a = PairArgs(args...); |
| // std::pair<F, S> p(std::piecewise_construct, |
| // std::move(a.first), std::move(a.second)); |
| inline std::pair<std::tuple<>, std::tuple<>> PairArgs() { return {}; } |
| template <class F, class S> |
| std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(F&& f, S&& s) { |
| return {std::piecewise_construct, std::forward_as_tuple(std::forward<F>(f)), |
| std::forward_as_tuple(std::forward<S>(s))}; |
| } |
| template <class F, class S> |
| std::pair<std::tuple<const F&>, std::tuple<const S&>> PairArgs( |
| const std::pair<F, S>& p) { |
| return PairArgs(p.first, p.second); |
| } |
| template <class F, class S> |
| std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(std::pair<F, S>&& p) { |
| return PairArgs(std::forward<F>(p.first), std::forward<S>(p.second)); |
| } |
| template <class F, class S> |
| auto PairArgs(std::piecewise_construct_t, F&& f, S&& s) |
| -> decltype(std::make_pair(memory_internal::TupleRef(std::forward<F>(f)), |
| memory_internal::TupleRef(std::forward<S>(s)))) { |
| return std::make_pair(memory_internal::TupleRef(std::forward<F>(f)), |
| memory_internal::TupleRef(std::forward<S>(s))); |
| } |
| |
| // A helper function for implementing apply() in map policies. |
| template <class F, class... Args> |
| auto DecomposePair(F&& f, Args&&... args) |
| -> decltype(memory_internal::DecomposePairImpl( |
| std::forward<F>(f), PairArgs(std::forward<Args>(args)...))) { |
| return memory_internal::DecomposePairImpl( |
| std::forward<F>(f), PairArgs(std::forward<Args>(args)...)); |
| } |
| |
| // A helper function for implementing apply() in set policies. |
| template <class F, class Arg> |
| decltype(std::declval<F>()(std::declval<const Arg&>(), std::declval<Arg>())) |
| DecomposeValue(F&& f, Arg&& arg) { |
| const auto& key = arg; |
| return std::forward<F>(f)(key, std::forward<Arg>(arg)); |
| } |
| |
| // Helper functions for asan and msan. |
| inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) { |
| #ifdef ABSL_HAVE_ADDRESS_SANITIZER |
| ASAN_POISON_MEMORY_REGION(m, s); |
| #endif |
| #ifdef ABSL_HAVE_MEMORY_SANITIZER |
| __msan_poison(m, s); |
| #endif |
| (void)m; |
| (void)s; |
| } |
| |
| inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) { |
| #ifdef ABSL_HAVE_ADDRESS_SANITIZER |
| ASAN_UNPOISON_MEMORY_REGION(m, s); |
| #endif |
| #ifdef ABSL_HAVE_MEMORY_SANITIZER |
| __msan_unpoison(m, s); |
| #endif |
| (void)m; |
| (void)s; |
| } |
| |
| template <typename T> |
| inline void SanitizerPoisonObject(const T* object) { |
| SanitizerPoisonMemoryRegion(object, sizeof(T)); |
| } |
| |
| template <typename T> |
| inline void SanitizerUnpoisonObject(const T* object) { |
| SanitizerUnpoisonMemoryRegion(object, sizeof(T)); |
| } |
| |
| namespace memory_internal { |
| |
| // If Pair is a standard-layout type, OffsetOf<Pair>::kFirst and |
| // OffsetOf<Pair>::kSecond are equivalent to offsetof(Pair, first) and |
| // offsetof(Pair, second) respectively. Otherwise they are -1. |
| // |
| // The purpose of OffsetOf is to avoid calling offsetof() on non-standard-layout |
| // type, which is non-portable. |
| template <class Pair, class = std::true_type> |
| struct OffsetOf { |
| static constexpr size_t kFirst = static_cast<size_t>(-1); |
| static constexpr size_t kSecond = static_cast<size_t>(-1); |
| }; |
| |
| template <class Pair> |
| struct OffsetOf<Pair, typename std::is_standard_layout<Pair>::type> { |
| static constexpr size_t kFirst = offsetof(Pair, first); |
| static constexpr size_t kSecond = offsetof(Pair, second); |
| }; |
| |
| template <class K, class V> |
| struct IsLayoutCompatible { |
| private: |
| struct Pair { |
| K first; |
| V second; |
| }; |
| |
| // Is P layout-compatible with Pair? |
| template <class P> |
| static constexpr bool LayoutCompatible() { |
| return std::is_standard_layout<P>() && sizeof(P) == sizeof(Pair) && |
| alignof(P) == alignof(Pair) && |
| memory_internal::OffsetOf<P>::kFirst == |
| memory_internal::OffsetOf<Pair>::kFirst && |
| memory_internal::OffsetOf<P>::kSecond == |
| memory_internal::OffsetOf<Pair>::kSecond; |
| } |
| |
| public: |
| // Whether pair<const K, V> and pair<K, V> are layout-compatible. If they are, |
| // then it is safe to store them in a union and read from either. |
| static constexpr bool value = std::is_standard_layout<K>() && |
| std::is_standard_layout<Pair>() && |
| memory_internal::OffsetOf<Pair>::kFirst == 0 && |
| LayoutCompatible<std::pair<K, V>>() && |
| LayoutCompatible<std::pair<const K, V>>(); |
| }; |
| |
| } // namespace memory_internal |
| |
| // The internal storage type for key-value containers like flat_hash_map. |
| // |
| // It is convenient for the value_type of a flat_hash_map<K, V> to be |
| // pair<const K, V>; the "const K" prevents accidental modification of the key |
| // when dealing with the reference returned from find() and similar methods. |
| // However, this creates other problems; we want to be able to emplace(K, V) |
| // efficiently with move operations, and similarly be able to move a |
| // pair<K, V> in insert(). |
| // |
| // The solution is this union, which aliases the const and non-const versions |
| // of the pair. This also allows flat_hash_map<const K, V> to work, even though |
| // that has the same efficiency issues with move in emplace() and insert() - |
| // but people do it anyway. |
| // |
| // If kMutableKeys is false, only the value member can be accessed. |
| // |
| // If kMutableKeys is true, key can be accessed through all slots while value |
| // and mutable_value must be accessed only via INITIALIZED slots. Slots are |
| // created and destroyed via mutable_value so that the key can be moved later. |
| // |
| // Accessing one of the union fields while the other is active is safe as |
| // long as they are layout-compatible, which is guaranteed by the definition of |
| // kMutableKeys. For C++11, the relevant section of the standard is |
| // https://timsong-cpp.github.io/cppwp/n3337/class.mem#19 (9.2.19) |
| template <class K, class V> |
| union map_slot_type { |
| map_slot_type() {} |
| ~map_slot_type() = delete; |
| using value_type = std::pair<const K, V>; |
| using mutable_value_type = |
| std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>; |
| |
| value_type value; |
| mutable_value_type mutable_value; |
| absl::remove_const_t<K> key; |
| }; |
| |
| template <class K, class V> |
| struct map_slot_policy { |
| using slot_type = map_slot_type<K, V>; |
| using value_type = std::pair<const K, V>; |
| using mutable_value_type = |
| std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>; |
| |
| private: |
| static void emplace(slot_type* slot) { |
| // The construction of union doesn't do anything at runtime but it allows us |
| // to access its members without violating aliasing rules. |
| new (slot) slot_type; |
| } |
| // If pair<const K, V> and pair<K, V> are layout-compatible, we can accept one |
| // or the other via slot_type. We are also free to access the key via |
| // slot_type::key in this case. |
| using kMutableKeys = memory_internal::IsLayoutCompatible<K, V>; |
| |
| public: |
| static value_type& element(slot_type* slot) { return slot->value; } |
| static const value_type& element(const slot_type* slot) { |
| return slot->value; |
| } |
| |
| static K& mutable_key(slot_type* slot) { |
| // Still check for kMutableKeys so that we can avoid calling std::launder |
| // unless necessary because it can interfere with optimizations. |
| return kMutableKeys::value ? slot->key |
| : *std::launder(const_cast<K*>( |
| std::addressof(slot->value.first))); |
| } |
| |
| static const K& key(const slot_type* slot) { |
| return kMutableKeys::value ? slot->key : slot->value.first; |
| } |
| |
| template <class Allocator, class... Args> |
| static void construct(Allocator* alloc, slot_type* slot, Args&&... args) { |
| emplace(slot); |
| if (kMutableKeys::value) { |
| absl::allocator_traits<Allocator>::construct(*alloc, &slot->mutable_value, |
| std::forward<Args>(args)...); |
| } else { |
| absl::allocator_traits<Allocator>::construct(*alloc, &slot->value, |
| std::forward<Args>(args)...); |
| } |
| } |
| |
| // Construct this slot by moving from another slot. |
| template <class Allocator> |
| static void construct(Allocator* alloc, slot_type* slot, slot_type* other) { |
| emplace(slot); |
| if (kMutableKeys::value) { |
| absl::allocator_traits<Allocator>::construct( |
| *alloc, &slot->mutable_value, std::move(other->mutable_value)); |
| } else { |
| absl::allocator_traits<Allocator>::construct(*alloc, &slot->value, |
| std::move(other->value)); |
| } |
| } |
| |
| // Construct this slot by copying from another slot. |
| template <class Allocator> |
| static void construct(Allocator* alloc, slot_type* slot, |
| const slot_type* other) { |
| emplace(slot); |
| absl::allocator_traits<Allocator>::construct(*alloc, &slot->value, |
| other->value); |
| } |
| |
| template <class Allocator> |
| static auto destroy(Allocator* alloc, slot_type* slot) { |
| if (kMutableKeys::value) { |
| absl::allocator_traits<Allocator>::destroy(*alloc, &slot->mutable_value); |
| } else { |
| absl::allocator_traits<Allocator>::destroy(*alloc, &slot->value); |
| } |
| return IsDestructionTrivial<Allocator, value_type>(); |
| } |
| |
| template <class Allocator> |
| static auto transfer(Allocator* alloc, slot_type* new_slot, |
| slot_type* old_slot) { |
| // This should really just be |
| // typename absl::is_trivially_relocatable<value_type>::type() |
| // but std::pair is not trivially copyable in C++23 in some standard |
| // library versions. |
| // See https://github.com/llvm/llvm-project/pull/95444 for instance. |
| auto is_relocatable = typename std::conjunction< |
| absl::is_trivially_relocatable<typename value_type::first_type>, |
| absl::is_trivially_relocatable<typename value_type::second_type>>:: |
| type(); |
| |
| emplace(new_slot); |
| if (is_relocatable) { |
| // TODO(b/247130232,b/251814870): remove casts after fixing warnings. |
| std::memcpy(static_cast<void*>(std::launder(&new_slot->value)), |
| static_cast<const void*>(&old_slot->value), |
| sizeof(value_type)); |
| return is_relocatable; |
| } |
| |
| if (kMutableKeys::value) { |
| absl::allocator_traits<Allocator>::construct( |
| *alloc, &new_slot->mutable_value, std::move(old_slot->mutable_value)); |
| } else { |
| absl::allocator_traits<Allocator>::construct(*alloc, &new_slot->value, |
| std::move(old_slot->value)); |
| } |
| destroy(alloc, old_slot); |
| return is_relocatable; |
| } |
| }; |
| |
| // Type erased function for computing hash of the slot. |
| using HashSlotFn = size_t (*)(const void* hash_fn, void* slot); |
| |
| // Type erased function to apply `Fn` to data inside of the `slot`. |
| // The data is expected to have type `T`. |
| template <class Fn, class T> |
| size_t TypeErasedApplyToSlotFn(const void* fn, void* slot) { |
| const auto* f = static_cast<const Fn*>(fn); |
| return (*f)(*static_cast<const T*>(slot)); |
| } |
| |
| // Type erased function to apply `Fn` to data inside of the `*slot_ptr`. |
| // The data is expected to have type `T`. |
| template <class Fn, class T> |
| size_t TypeErasedDerefAndApplyToSlotFn(const void* fn, void* slot_ptr) { |
| const auto* f = static_cast<const Fn*>(fn); |
| const T* slot = *static_cast<const T**>(slot_ptr); |
| return (*f)(*slot); |
| } |
| |
| } // namespace container_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_ |
| *ÿ1 |
| ~soong/.intermediates/external/abseil-cpp/absl_log_internal_vlog_config_hdrs/gen/my_include_dir/absl/log/internal/vlog_config.hü0// Copyright 2022 The Abseil Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // vlog_config.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines `VLogSite`, a public primitive that represents |
| // a callsite for the `VLOG` family of macros and related libraries. |
| // It also declares and defines multiple internal utilities used to implement |
| // `VLOG`, such as `VLogSiteManager`. |
| |
| #ifndef ABSL_LOG_INTERNAL_VLOG_CONFIG_H_ |
| #define ABSL_LOG_INTERNAL_VLOG_CONFIG_H_ |
| |
| // IWYU pragma: private, include "absl/log/log.h" |
| |
| #include <atomic> |
| #include <cstdint> |
| #include <functional> |
| #include <limits> |
| #include <type_traits> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/optimization.h" |
| #include "absl/base/thread_annotations.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace log_internal { |
| |
| class SyntheticBinary; |
| class VLogSite; |
| |
| int RegisterAndInitialize(VLogSite* absl_nonnull v); |
| void UpdateVLogSites(); |
| constexpr int kUseFlag = (std::numeric_limits<int16_t>::min)(); |
| |
| // Represents a unique callsite for a `VLOG()` or `VLOG_IS_ON()` call. |
| // |
| // Libraries that provide `VLOG`-like functionality should use this to |
| // efficiently handle --vmodule. |
| // |
| // VLogSite objects must not be destroyed until the program exits. Doing so will |
| // probably yield nasty segfaults in VLogSiteManager::UpdateLogSites(). The |
| // recommendation is to make all such objects function-local statics. |
| class VLogSite final { |
| public: |
| // `f` must not be destroyed until the program exits. |
| explicit constexpr VLogSite(const char* absl_nonnull f) |
| : file_(f), v_(kUninitialized), next_(nullptr) {} |
| VLogSite(const VLogSite&) = delete; |
| VLogSite& operator=(const VLogSite&) = delete; |
| |
| // Inlining the function yields a ~3x performance improvement at the cost of a |
| // 1.5x code size increase at the call site. |
| // Takes locks but does not allocate memory. |
| ABSL_ATTRIBUTE_ALWAYS_INLINE |
| bool IsEnabled(int level) { |
| int stale_v = v_.load(std::memory_order_relaxed); |
| if (ABSL_PREDICT_TRUE(level > stale_v)) { |
| return false; |
| } |
| |
| // We put everything other than the fast path, i.e. vlogging is initialized |
| // but not on, behind an out-of-line function to reduce code size. |
| // "level" is almost always a call-site constant, so we can save a bit |
| // of code space by special-casing for a few common levels. |
| #if ABSL_HAVE_BUILTIN(__builtin_constant_p) || defined(__GNUC__) |
| if (__builtin_constant_p(level)) { |
| if (level == 0) return SlowIsEnabled0(stale_v); |
| if (level == 1) return SlowIsEnabled1(stale_v); |
| if (level == 2) return SlowIsEnabled2(stale_v); |
| if (level == 3) return SlowIsEnabled3(stale_v); |
| if (level == 4) return SlowIsEnabled4(stale_v); |
| if (level == 5) return SlowIsEnabled5(stale_v); |
| } |
| #endif |
| return SlowIsEnabled(stale_v, level); |
| } |
| |
| private: |
| friend int log_internal::RegisterAndInitialize(VLogSite* absl_nonnull v); |
| friend void log_internal::UpdateVLogSites(); |
| friend class log_internal::SyntheticBinary; |
| static constexpr int kUninitialized = (std::numeric_limits<int>::max)(); |
| |
| // SlowIsEnabled performs slower checks to determine whether a log site is |
| // enabled. Because it is expected to be called somewhat rarely |
| // (comparatively), it is not inlined to save on code size. |
| // |
| // Prerequisites to calling SlowIsEnabled: |
| // 1) stale_v is uninitialized OR |
| // 2) stale_v is initialized and >= level (meaning we must log). |
| // Takes locks but does not allocate memory. |
| ABSL_ATTRIBUTE_NOINLINE |
| bool SlowIsEnabled(int stale_v, int level); |
| ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled0(int stale_v); |
| ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled1(int stale_v); |
| ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled2(int stale_v); |
| ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled3(int stale_v); |
| ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled4(int stale_v); |
| ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled5(int stale_v); |
| |
| // This object is too size-sensitive to use absl::string_view. |
| const char* absl_nonnull const file_; |
| std::atomic<int> v_; |
| std::atomic<VLogSite*> next_; |
| }; |
| static_assert(std::is_trivially_destructible<VLogSite>::value, |
| "VLogSite must be trivially destructible"); |
| |
| // Returns the current verbose log level of `file`. |
| // Does not allocate memory. |
| int VLogLevel(absl::string_view file); |
| |
| // Registers a site `v` to get updated as `vmodule` and `v` change. Also |
| // initializes the site based on their current values, and returns that result. |
| // Does not allocate memory. |
| int RegisterAndInitialize(VLogSite* absl_nonnull v); |
| |
| // Allocates memory. |
| void UpdateVLogSites(); |
| |
| // Completely overwrites the saved value of `vmodule`. |
| // Allocates memory. |
| void UpdateVModule(absl::string_view vmodule); |
| |
| // Updates the global verbosity level to `v` and returns the prior value. |
| // Allocates memory. |
| int UpdateGlobalVLogLevel(int v); |
| |
| // Atomically prepends `module_pattern=log_level` to the start of vmodule. |
| // Returns the prior value for `module_pattern` if there was an exact match and |
| // `global_v` otherwise. |
| // Allocates memory. |
| int PrependVModule(absl::string_view module_pattern, int log_level); |
| |
| // Registers `on_update` to be called whenever `v` or `vmodule` change. |
| // Allocates memory. |
| void OnVLogVerbosityUpdate(std::function<void()> cb); |
| |
| // Does not allocate memory. |
| VLogSite* absl_nullable SetVModuleListHeadForTestOnly( |
| VLogSite* absl_nullable v); |
| |
| } // namespace log_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_LOG_INTERNAL_VLOG_CONFIG_H_ |
| *¶å |
| tsoong/.intermediates/external/abseil-cpp/absl_strings_string_view_hdrs/gen/my_include_dir/absl/strings/string_view.h¼ä// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: string_view.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This file contains the definition of the `absl::string_view` class. A |
| // `string_view` points to a contiguous span of characters, often part or all of |
| // another `std::string`, double-quoted string literal, character array, or even |
| // another `string_view`. |
| // |
| // This `absl::string_view` abstraction is designed to be a drop-in |
| // replacement for the C++17 `std::string_view` abstraction. |
| #ifndef ABSL_STRINGS_STRING_VIEW_H_ |
| #define ABSL_STRINGS_STRING_VIEW_H_ |
| |
| #include <algorithm> |
| #include <cassert> |
| #include <cstddef> |
| #include <cstring> |
| #include <iosfwd> |
| #include <iterator> |
| #include <limits> |
| #include <string> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/throw_delegate.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/optimization.h" |
| #include "absl/base/port.h" |
| |
| #ifdef ABSL_USES_STD_STRING_VIEW |
| |
| #include <string_view> // IWYU pragma: export |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| using string_view = std::string_view; |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #else // ABSL_USES_STD_STRING_VIEW |
| |
| #if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \ |
| (defined(__GNUC__) && !defined(__clang__)) || \ |
| (defined(_MSC_VER) && _MSC_VER >= 1928) |
| #define ABSL_INTERNAL_STRING_VIEW_MEMCMP __builtin_memcmp |
| #else // ABSL_HAVE_BUILTIN(__builtin_memcmp) |
| #define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp |
| #endif // ABSL_HAVE_BUILTIN(__builtin_memcmp) |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // absl::string_view |
| // |
| // A `string_view` provides a lightweight view into the string data provided by |
| // a `std::string`, double-quoted string literal, character array, or even |
| // another `string_view`. A `string_view` does *not* own the string to which it |
| // points, and that data cannot be modified through the view. |
| // |
| // You can use `string_view` as a function or method parameter anywhere a |
| // parameter can receive a double-quoted string literal, `const char*`, |
| // `std::string`, or another `absl::string_view` argument with no need to copy |
| // the string data. Systematic use of `string_view` within function arguments |
| // reduces data copies and `strlen()` calls. |
| // |
| // Because of its small size, prefer passing `string_view` by value: |
| // |
| // void MyFunction(absl::string_view arg); |
| // |
| // If circumstances require, you may also pass one by const reference: |
| // |
| // void MyFunction(const absl::string_view& arg); // not preferred |
| // |
| // Passing by value generates slightly smaller code for many architectures. |
| // |
| // In either case, the source data of the `string_view` must outlive the |
| // `string_view` itself. |
| // |
| // A `string_view` is also suitable for local variables if you know that the |
| // lifetime of the underlying object is longer than the lifetime of your |
| // `string_view` variable. However, beware of binding a `string_view` to a |
| // temporary value: |
| // |
| // // BAD use of string_view: lifetime problem |
| // absl::string_view sv = obj.ReturnAString(); |
| // |
| // // GOOD use of string_view: str outlives sv |
| // std::string str = obj.ReturnAString(); |
| // absl::string_view sv = str; |
| // |
| // Due to lifetime issues, a `string_view` is sometimes a poor choice for a |
| // return value and usually a poor choice for a data member. If you do use a |
| // `string_view` this way, it is your responsibility to ensure that the object |
| // pointed to by the `string_view` outlives the `string_view`. |
| // |
| // A `string_view` may represent a whole string or just part of a string. For |
| // example, when splitting a string, `std::vector<absl::string_view>` is a |
| // natural data type for the output. |
| // |
| // For another example, a Cord is a non-contiguous, potentially very |
| // long string-like object. The Cord class has an interface that iteratively |
| // provides string_view objects that point to the successive pieces of a Cord |
| // object. |
| // |
| // When constructed from a source which is NUL-terminated, the `string_view` |
| // itself will not include the NUL-terminator unless a specific size (including |
| // the NUL) is passed to the constructor. As a result, common idioms that work |
| // on NUL-terminated strings do not work on `string_view` objects. If you write |
| // code that scans a `string_view`, you must check its length rather than test |
| // for nul, for example. Note, however, that nuls may still be embedded within |
| // a `string_view` explicitly. |
| // |
| // You may create a null `string_view` in two ways: |
| // |
| // absl::string_view sv; |
| // absl::string_view sv(nullptr, 0); |
| // |
| // For the above, `sv.data() == nullptr`, `sv.length() == 0`, and |
| // `sv.empty() == true`. Also, if you create a `string_view` with a non-null |
| // pointer then `sv.data() != nullptr`. Thus, you can use `string_view()` to |
| // signal an undefined value that is different from other `string_view` values |
| // in a similar fashion to how `const char* p1 = nullptr;` is different from |
| // `const char* p2 = "";`. However, in practice, it is not recommended to rely |
| // on this behavior. |
| // |
| // Be careful not to confuse a null `string_view` with an empty one. A null |
| // `string_view` is an empty `string_view`, but some empty `string_view`s are |
| // not null. Prefer checking for emptiness over checking for null. |
| // |
| // There are many ways to create an empty string_view: |
| // |
| // const char* nullcp = nullptr; |
| // // string_view.size() will return 0 in all cases. |
| // absl::string_view(); |
| // absl::string_view(nullcp, 0); |
| // absl::string_view(""); |
| // absl::string_view("", 0); |
| // absl::string_view("abcdef", 0); |
| // absl::string_view("abcdef" + 6, 0); |
| // |
| // All empty `string_view` objects whether null or not, are equal: |
| // |
| // absl::string_view() == absl::string_view("", 0) |
| // absl::string_view(nullptr, 0) == absl::string_view("abcdef"+6, 0) |
| class ABSL_ATTRIBUTE_VIEW string_view { |
| public: |
| using traits_type = std::char_traits<char>; |
| using value_type = char; |
| using pointer = char* absl_nullable; |
| using const_pointer = const char* absl_nullable; |
| using reference = char&; |
| using const_reference = const char&; |
| using const_iterator = const char* absl_nullable; |
| using iterator = const_iterator; |
| using const_reverse_iterator = std::reverse_iterator<const_iterator>; |
| using reverse_iterator = const_reverse_iterator; |
| using size_type = size_t; |
| using difference_type = std::ptrdiff_t; |
| using absl_internal_is_view = std::true_type; |
| |
| static constexpr size_type npos = static_cast<size_type>(-1); |
| |
| // Null `string_view` constructor |
| constexpr string_view() noexcept : ptr_(nullptr), length_(0) {} |
| |
| // Implicit constructors |
| |
| template <typename Allocator> |
| string_view( // NOLINT(runtime/explicit) |
| const std::basic_string<char, std::char_traits<char>, Allocator>& str |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept |
| // This is implemented in terms of `string_view(p, n)` so `str.size()` |
| // doesn't need to be reevaluated after `ptr_` is set. |
| // The length check is also skipped since it is unnecessary and causes |
| // code bloat. |
| : string_view(str.data(), str.size(), SkipCheckLengthTag{}) {} |
| |
| // Implicit constructor of a `string_view` from NUL-terminated `str`. When |
| // accepting possibly null strings, use `absl::NullSafeStringView(str)` |
| // instead (see below). |
| // The length check is skipped since it is unnecessary and causes code bloat. |
| constexpr string_view( // NOLINT(runtime/explicit) |
| const char* absl_nonnull str) |
| : ptr_(str), length_(str ? StrlenInternal(str) : 0) {} |
| |
| // Constructor of a `string_view` from a `const char*` and length. |
| constexpr string_view(const char* absl_nullable data, size_type len) |
| : ptr_(data), length_(CheckLengthInternal(len)) {} |
| |
| constexpr string_view(const string_view&) noexcept = default; |
| string_view& operator=(const string_view&) noexcept = default; |
| |
| // Iterators |
| |
| // string_view::begin() |
| // |
| // Returns an iterator pointing to the first character at the beginning of the |
| // `string_view`, or `end()` if the `string_view` is empty. |
| constexpr const_iterator begin() const noexcept { return ptr_; } |
| |
| // string_view::end() |
| // |
| // Returns an iterator pointing just beyond the last character at the end of |
| // the `string_view`. This iterator acts as a placeholder; attempting to |
| // access it results in undefined behavior. |
| constexpr const_iterator end() const noexcept { return ptr_ + length_; } |
| |
| // string_view::cbegin() |
| // |
| // Returns a const iterator pointing to the first character at the beginning |
| // of the `string_view`, or `end()` if the `string_view` is empty. |
| constexpr const_iterator cbegin() const noexcept { return begin(); } |
| |
| // string_view::cend() |
| // |
| // Returns a const iterator pointing just beyond the last character at the end |
| // of the `string_view`. This pointer acts as a placeholder; attempting to |
| // access its element results in undefined behavior. |
| constexpr const_iterator cend() const noexcept { return end(); } |
| |
| // string_view::rbegin() |
| // |
| // Returns a reverse iterator pointing to the last character at the end of the |
| // `string_view`, or `rend()` if the `string_view` is empty. |
| const_reverse_iterator rbegin() const noexcept { |
| return const_reverse_iterator(end()); |
| } |
| |
| // string_view::rend() |
| // |
| // Returns a reverse iterator pointing just before the first character at the |
| // beginning of the `string_view`. This pointer acts as a placeholder; |
| // attempting to access its element results in undefined behavior. |
| const_reverse_iterator rend() const noexcept { |
| return const_reverse_iterator(begin()); |
| } |
| |
| // string_view::crbegin() |
| // |
| // Returns a const reverse iterator pointing to the last character at the end |
| // of the `string_view`, or `crend()` if the `string_view` is empty. |
| const_reverse_iterator crbegin() const noexcept { return rbegin(); } |
| |
| // string_view::crend() |
| // |
| // Returns a const reverse iterator pointing just before the first character |
| // at the beginning of the `string_view`. This pointer acts as a placeholder; |
| // attempting to access its element results in undefined behavior. |
| const_reverse_iterator crend() const noexcept { return rend(); } |
| |
| // Capacity Utilities |
| |
| // string_view::size() |
| // |
| // Returns the number of characters in the `string_view`. |
| constexpr size_type size() const noexcept { return length_; } |
| |
| // string_view::length() |
| // |
| // Returns the number of characters in the `string_view`. Alias for `size()`. |
| constexpr size_type length() const noexcept { return size(); } |
| |
| // string_view::max_size() |
| // |
| // Returns the maximum number of characters the `string_view` can hold. |
| constexpr size_type max_size() const noexcept { return kMaxSize; } |
| |
| // string_view::empty() |
| // |
| // Checks if the `string_view` is empty (refers to no characters). |
| constexpr bool empty() const noexcept { return length_ == 0; } |
| |
| // string_view::operator[] |
| // |
| // Returns the ith element of the `string_view` using the array operator. |
| // Note that this operator does not perform any bounds checking. |
| constexpr const_reference operator[](size_type i) const { |
| ABSL_HARDENING_ASSERT(i < size()); |
| return ptr_[i]; |
| } |
| |
| // string_view::at() |
| // |
| // Returns the ith element of the `string_view`. Bounds checking is performed, |
| // and an exception of type `std::out_of_range` will be thrown on invalid |
| // access. |
| constexpr const_reference at(size_type i) const { |
| if (ABSL_PREDICT_FALSE(i >= size())) { |
| base_internal::ThrowStdOutOfRange("absl::string_view::at"); |
| } |
| return ptr_[i]; |
| } |
| |
| // string_view::front() |
| // |
| // Returns the first element of a `string_view`. |
| constexpr const_reference front() const { |
| ABSL_HARDENING_ASSERT(!empty()); |
| return ptr_[0]; |
| } |
| |
| // string_view::back() |
| // |
| // Returns the last element of a `string_view`. |
| constexpr const_reference back() const { |
| ABSL_HARDENING_ASSERT(!empty()); |
| return ptr_[size() - 1]; |
| } |
| |
| // string_view::data() |
| // |
| // Returns a pointer to the underlying character array (which is of course |
| // stored elsewhere). Note that `string_view::data()` may contain embedded nul |
| // characters, but the returned buffer may or may not be NUL-terminated; |
| // therefore, do not pass `data()` to a routine that expects a NUL-terminated |
| // string. |
| constexpr const_pointer data() const noexcept { return ptr_; } |
| |
| // Modifiers |
| |
| // string_view::remove_prefix() |
| // |
| // Removes the first `n` characters from the `string_view`. Note that the |
| // underlying string is not changed, only the view. |
| constexpr void remove_prefix(size_type n) { |
| ABSL_HARDENING_ASSERT(n <= length_); |
| ptr_ += n; |
| length_ -= n; |
| } |
| |
| // string_view::remove_suffix() |
| // |
| // Removes the last `n` characters from the `string_view`. Note that the |
| // underlying string is not changed, only the view. |
| constexpr void remove_suffix(size_type n) { |
| ABSL_HARDENING_ASSERT(n <= length_); |
| length_ -= n; |
| } |
| |
| // string_view::swap() |
| // |
| // Swaps this `string_view` with another `string_view`. |
| constexpr void swap(string_view& s) noexcept { |
| auto t = *this; |
| *this = s; |
| s = t; |
| } |
| |
| // Explicit conversion operators |
| |
| // Converts to `std::basic_string`. |
| template <typename A> |
| explicit operator std::basic_string<char, traits_type, A>() const { |
| if (!data()) return {}; |
| return std::basic_string<char, traits_type, A>(data(), size()); |
| } |
| |
| // string_view::copy() |
| // |
| // Copies the contents of the `string_view` at offset `pos` and length `n` |
| // into `buf`. |
| size_type copy(char* buf, size_type n, size_type pos = 0) const { |
| if (ABSL_PREDICT_FALSE(pos > length_)) { |
| base_internal::ThrowStdOutOfRange("absl::string_view::copy"); |
| } |
| size_type rlen = (std::min)(length_ - pos, n); |
| if (rlen > 0) { |
| const char* start = ptr_ + pos; |
| traits_type::copy(buf, start, rlen); |
| } |
| return rlen; |
| } |
| |
| // string_view::substr() |
| // |
| // Returns a "substring" of the `string_view` (at offset `pos` and length |
| // `n`) as another string_view. This function throws `std::out_of_bounds` if |
| // `pos > size`. |
| // Use absl::ClippedSubstr if you need a truncating substr operation. |
| constexpr string_view substr(size_type pos = 0, size_type n = npos) const { |
| if (ABSL_PREDICT_FALSE(pos > length_)) { |
| base_internal::ThrowStdOutOfRange("absl::string_view::substr"); |
| } |
| return string_view(ptr_ + pos, (std::min)(n, length_ - pos)); |
| } |
| |
| // string_view::compare() |
| // |
| // Performs a lexicographical comparison between this `string_view` and |
| // another `string_view` `x`, returning a negative value if `*this` is less |
| // than `x`, 0 if `*this` is equal to `x`, and a positive value if `*this` |
| // is greater than `x`. |
| constexpr int compare(string_view x) const noexcept { |
| return CompareImpl(length_, x.length_, |
| (std::min)(length_, x.length_) == 0 |
| ? 0 |
| : ABSL_INTERNAL_STRING_VIEW_MEMCMP( |
| ptr_, x.ptr_, (std::min)(length_, x.length_))); |
| } |
| |
| // Overload of `string_view::compare()` for comparing a substring of the |
| // 'string_view` and another `absl::string_view`. |
| constexpr int compare(size_type pos1, size_type count1, string_view v) const { |
| return substr(pos1, count1).compare(v); |
| } |
| |
| // Overload of `string_view::compare()` for comparing a substring of the |
| // `string_view` and a substring of another `absl::string_view`. |
| constexpr int compare(size_type pos1, size_type count1, string_view v, |
| size_type pos2, size_type count2) const { |
| return substr(pos1, count1).compare(v.substr(pos2, count2)); |
| } |
| |
| // Overload of `string_view::compare()` for comparing a `string_view` and a |
| // a different C-style string `s`. |
| constexpr int compare(const char* absl_nonnull s) const { |
| return compare(string_view(s)); |
| } |
| |
| // Overload of `string_view::compare()` for comparing a substring of the |
| // `string_view` and a different string C-style string `s`. |
| constexpr int compare(size_type pos1, size_type count1, |
| const char* absl_nonnull s) const { |
| return substr(pos1, count1).compare(string_view(s)); |
| } |
| |
| // Overload of `string_view::compare()` for comparing a substring of the |
| // `string_view` and a substring of a different C-style string `s`. |
| constexpr int compare(size_type pos1, size_type count1, |
| const char* absl_nonnull s, size_type count2) const { |
| return substr(pos1, count1).compare(string_view(s, count2)); |
| } |
| |
| // Find Utilities |
| |
| // string_view::find() |
| // |
| // Finds the first occurrence of the substring `s` within the `string_view`, |
| // returning the position of the first character's match, or `npos` if no |
| // match was found. |
| size_type find(string_view s, size_type pos = 0) const noexcept; |
| |
| // Overload of `string_view::find()` for finding the given character `c` |
| // within the `string_view`. |
| size_type find(char c, size_type pos = 0) const noexcept; |
| |
| // Overload of `string_view::find()` for finding a substring of a different |
| // C-style string `s` within the `string_view`. |
| size_type find(const char* absl_nonnull s, size_type pos, |
| size_type count) const { |
| return find(string_view(s, count), pos); |
| } |
| |
| // Overload of `string_view::find()` for finding a different C-style string |
| // `s` within the `string_view`. |
| size_type find(const char* absl_nonnull s, size_type pos = 0) const { |
| return find(string_view(s), pos); |
| } |
| |
| // string_view::rfind() |
| // |
| // Finds the last occurrence of a substring `s` within the `string_view`, |
| // returning the position of the first character's match, or `npos` if no |
| // match was found. |
| size_type rfind(string_view s, size_type pos = npos) const noexcept; |
| |
| // Overload of `string_view::rfind()` for finding the last given character `c` |
| // within the `string_view`. |
| size_type rfind(char c, size_type pos = npos) const noexcept; |
| |
| // Overload of `string_view::rfind()` for finding a substring of a different |
| // C-style string `s` within the `string_view`. |
| size_type rfind(const char* absl_nonnull s, size_type pos, |
| size_type count) const { |
| return rfind(string_view(s, count), pos); |
| } |
| |
| // Overload of `string_view::rfind()` for finding a different C-style string |
| // `s` within the `string_view`. |
| size_type rfind(const char* absl_nonnull s, size_type pos = npos) const { |
| return rfind(string_view(s), pos); |
| } |
| |
| // string_view::find_first_of() |
| // |
| // Finds the first occurrence of any of the characters in `s` within the |
| // `string_view`, returning the start position of the match, or `npos` if no |
| // match was found. |
| size_type find_first_of(string_view s, size_type pos = 0) const noexcept; |
| |
| // Overload of `string_view::find_first_of()` for finding a character `c` |
| // within the `string_view`. |
| size_type find_first_of(char c, size_type pos = 0) const noexcept { |
| return find(c, pos); |
| } |
| |
| // Overload of `string_view::find_first_of()` for finding a substring of a |
| // different C-style string `s` within the `string_view`. |
| size_type find_first_of(const char* absl_nonnull s, size_type pos, |
| size_type count) const { |
| return find_first_of(string_view(s, count), pos); |
| } |
| |
| // Overload of `string_view::find_first_of()` for finding a different C-style |
| // string `s` within the `string_view`. |
| size_type find_first_of(const char* absl_nonnull s, size_type pos = 0) const { |
| return find_first_of(string_view(s), pos); |
| } |
| |
| // string_view::find_last_of() |
| // |
| // Finds the last occurrence of any of the characters in `s` within the |
| // `string_view`, returning the start position of the match, or `npos` if no |
| // match was found. |
| size_type find_last_of(string_view s, size_type pos = npos) const noexcept; |
| |
| // Overload of `string_view::find_last_of()` for finding a character `c` |
| // within the `string_view`. |
| size_type find_last_of(char c, size_type pos = npos) const noexcept { |
| return rfind(c, pos); |
| } |
| |
| // Overload of `string_view::find_last_of()` for finding a substring of a |
| // different C-style string `s` within the `string_view`. |
| size_type find_last_of(const char* absl_nonnull s, size_type pos, |
| size_type count) const { |
| return find_last_of(string_view(s, count), pos); |
| } |
| |
| // Overload of `string_view::find_last_of()` for finding a different C-style |
| // string `s` within the `string_view`. |
| size_type find_last_of(const char* absl_nonnull s, |
| size_type pos = npos) const { |
| return find_last_of(string_view(s), pos); |
| } |
| |
| // string_view::find_first_not_of() |
| // |
| // Finds the first occurrence of any of the characters not in `s` within the |
| // `string_view`, returning the start position of the first non-match, or |
| // `npos` if no non-match was found. |
| size_type find_first_not_of(string_view s, size_type pos = 0) const noexcept; |
| |
| // Overload of `string_view::find_first_not_of()` for finding a character |
| // that is not `c` within the `string_view`. |
| size_type find_first_not_of(char c, size_type pos = 0) const noexcept; |
| |
| // Overload of `string_view::find_first_not_of()` for finding a substring of a |
| // different C-style string `s` within the `string_view`. |
| size_type find_first_not_of(const char* absl_nonnull s, size_type pos, |
| size_type count) const { |
| return find_first_not_of(string_view(s, count), pos); |
| } |
| |
| // Overload of `string_view::find_first_not_of()` for finding a different |
| // C-style string `s` within the `string_view`. |
| size_type find_first_not_of(const char* absl_nonnull s, |
| size_type pos = 0) const { |
| return find_first_not_of(string_view(s), pos); |
| } |
| |
| // string_view::find_last_not_of() |
| // |
| // Finds the last occurrence of any of the characters not in `s` within the |
| // `string_view`, returning the start position of the last non-match, or |
| // `npos` if no non-match was found. |
| size_type find_last_not_of(string_view s, |
| size_type pos = npos) const noexcept; |
| |
| // Overload of `string_view::find_last_not_of()` for finding a character |
| // that is not `c` within the `string_view`. |
| size_type find_last_not_of(char c, size_type pos = npos) const noexcept; |
| |
| // Overload of `string_view::find_last_not_of()` for finding a substring of a |
| // different C-style string `s` within the `string_view`. |
| size_type find_last_not_of(const char* absl_nonnull s, size_type pos, |
| size_type count) const { |
| return find_last_not_of(string_view(s, count), pos); |
| } |
| |
| // Overload of `string_view::find_last_not_of()` for finding a different |
| // C-style string `s` within the `string_view`. |
| size_type find_last_not_of(const char* absl_nonnull s, |
| size_type pos = npos) const { |
| return find_last_not_of(string_view(s), pos); |
| } |
| |
| #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L |
| // string_view::starts_with() |
| // |
| // Returns true if the `string_view` starts with the prefix `s`. |
| // |
| // This method only exists when targeting at least C++20. |
| // If support for C++ prior to C++20 is required, use `absl::StartsWith()` |
| // from `//absl/strings/match.h` for compatibility. |
| constexpr bool starts_with(string_view s) const noexcept { |
| return s.empty() || |
| (size() >= s.size() && |
| ABSL_INTERNAL_STRING_VIEW_MEMCMP(data(), s.data(), s.size()) == 0); |
| } |
| |
| // Overload of `string_view::starts_with()` that returns true if `c` is the |
| // first character of the `string_view`. |
| constexpr bool starts_with(char c) const noexcept { |
| return !empty() && front() == c; |
| } |
| |
| // Overload of `string_view::starts_with()` that returns true if the |
| // `string_view` starts with the C-style prefix `s`. |
| constexpr bool starts_with(const char* s) const { |
| return starts_with(string_view(s)); |
| } |
| |
| // string_view::ends_with() |
| // |
| // Returns true if the `string_view` ends with the suffix `s`. |
| // |
| // This method only exists when targeting at least C++20. |
| // If support for C++ prior to C++20 is required, use `absl::EndsWith()` |
| // from `//absl/strings/match.h` for compatibility. |
| constexpr bool ends_with(string_view s) const noexcept { |
| return s.empty() || (size() >= s.size() && ABSL_INTERNAL_STRING_VIEW_MEMCMP( |
| data() + (size() - s.size()), |
| s.data(), s.size()) == 0); |
| } |
| |
| // Overload of `string_view::ends_with()` that returns true if `c` is the |
| // last character of the `string_view`. |
| constexpr bool ends_with(char c) const noexcept { |
| return !empty() && back() == c; |
| } |
| |
| // Overload of `string_view::ends_with()` that returns true if the |
| // `string_view` ends with the C-style suffix `s`. |
| constexpr bool ends_with(const char* s) const { |
| return ends_with(string_view(s)); |
| } |
| #endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L |
| |
| private: |
| // The constructor from std::string delegates to this constructor. |
| // See the comment on that constructor for the rationale. |
| struct SkipCheckLengthTag {}; |
| string_view(const char* absl_nullable data, size_type len, |
| SkipCheckLengthTag) noexcept |
| : ptr_(data), length_(len) {} |
| |
| static constexpr size_type kMaxSize = |
| (std::numeric_limits<difference_type>::max)(); |
| |
| static constexpr size_type CheckLengthInternal(size_type len) { |
| ABSL_HARDENING_ASSERT(len <= kMaxSize); |
| return len; |
| } |
| |
| static constexpr size_type StrlenInternal(const char* absl_nonnull str) { |
| #if defined(_MSC_VER) && !defined(__clang__) |
| // MSVC 2017+ can evaluate this at compile-time. |
| const char* begin = str; |
| while (*str != '\0') ++str; |
| return str - begin; |
| #elif ABSL_HAVE_BUILTIN(__builtin_strlen) || \ |
| (defined(__GNUC__) && !defined(__clang__)) |
| // GCC has __builtin_strlen according to |
| // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html, but |
| // ABSL_HAVE_BUILTIN doesn't detect that, so we use the extra checks above. |
| // __builtin_strlen is constexpr. |
| return __builtin_strlen(str); |
| #else |
| return str ? strlen(str) : 0; |
| #endif |
| } |
| |
| static constexpr int CompareImpl(size_type length_a, size_type length_b, |
| int compare_result) { |
| return compare_result == 0 ? static_cast<int>(length_a > length_b) - |
| static_cast<int>(length_a < length_b) |
| : (compare_result < 0 ? -1 : 1); |
| } |
| |
| const char* absl_nullable ptr_; |
| size_type length_; |
| }; |
| |
| // This large function is defined inline so that in a fairly common case where |
| // one of the arguments is a literal, the compiler can elide a lot of the |
| // following comparisons. |
| constexpr bool operator==(string_view x, string_view y) noexcept { |
| return x.size() == y.size() && |
| (x.empty() || |
| ABSL_INTERNAL_STRING_VIEW_MEMCMP(x.data(), y.data(), x.size()) == 0); |
| } |
| |
| constexpr bool operator!=(string_view x, string_view y) noexcept { |
| return !(x == y); |
| } |
| |
| constexpr bool operator<(string_view x, string_view y) noexcept { |
| return x.compare(y) < 0; |
| } |
| |
| constexpr bool operator>(string_view x, string_view y) noexcept { |
| return y < x; |
| } |
| |
| constexpr bool operator<=(string_view x, string_view y) noexcept { |
| return !(y < x); |
| } |
| |
| constexpr bool operator>=(string_view x, string_view y) noexcept { |
| return !(x < y); |
| } |
| |
| // IO Insertion Operator |
| std::ostream& operator<<(std::ostream& o, string_view piece); |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #undef ABSL_INTERNAL_STRING_VIEW_MEMCMP |
| |
| #endif // ABSL_USES_STD_STRING_VIEW |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // ClippedSubstr() |
| // |
| // Like `s.substr(pos, n)`, but clips `pos` to an upper bound of `s.size()`. |
| // Provided because std::string_view::substr throws if `pos > size()` |
| inline string_view ClippedSubstr(string_view s, size_t pos, |
| size_t n = string_view::npos) { |
| pos = (std::min)(pos, static_cast<size_t>(s.size())); |
| return s.substr(pos, n); |
| } |
| |
| // NullSafeStringView() |
| // |
| // Creates an `absl::string_view` from a pointer `p` even if it's null-valued. |
| // This function should be used where an `absl::string_view` can be created from |
| // a possibly-null pointer. |
| constexpr string_view NullSafeStringView(const char* absl_nullable p) { |
| return p ? string_view(p) : string_view(); |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_STRING_VIEW_H_ |
| *ï |
| tsoong/.intermediates/external/abseil-cpp/absl_strings_hdrs/gen/my_include_dir/absl/strings/internal/stringify_sink.hö// Copyright 2022 The Abseil Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_STRINGIFY_SINK_H_ |
| #define ABSL_STRINGS_INTERNAL_STRINGIFY_SINK_H_ |
| |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| namespace strings_internal { |
| class StringifySink { |
| public: |
| void Append(size_t count, char ch); |
| |
| void Append(string_view v); |
| |
| // Support `absl::Format(&sink, format, args...)`. |
| friend void AbslFormatFlush(StringifySink* sink, absl::string_view v) { |
| sink->Append(v); |
| } |
| |
| private: |
| template <typename T> |
| friend string_view ExtractStringification(StringifySink& sink, const T& v); |
| |
| std::string buffer_; |
| }; |
| |
| template <typename T> |
| string_view ExtractStringification(StringifySink& sink, const T& v) { |
| AbslStringify(sink, v); |
| return sink.buffer_; |
| } |
| |
| } // namespace strings_internal |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_STRINGIFY_SINK_H_ |
| * |
| {soong/.intermediates/external/abseil-cpp/absl_base_spinlock_wait_hdrs/gen/my_include_dir/absl/base/internal/spinlock_wait.h// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ |
| #define ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ |
| |
| // Operations to make atomic transitions on a word, and to allow |
| // waiting for those transitions to become possible. |
| |
| #include <stdint.h> |
| #include <atomic> |
| |
| #include "absl/base/internal/scheduling_mode.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace base_internal { |
| |
| // SpinLockWait() waits until it can perform one of several transitions from |
| // "from" to "to". It returns when it performs a transition where done==true. |
| struct SpinLockWaitTransition { |
| uint32_t from; |
| uint32_t to; |
| bool done; |
| }; |
| |
| // Wait until *w can transition from trans[i].from to trans[i].to for some i |
| // satisfying 0<=i<n && trans[i].done, atomically make the transition, |
| // then return the old value of *w. Make any other atomic transitions |
| // where !trans[i].done, but continue waiting. |
| // |
| // Wakeups for threads blocked on SpinLockWait do not respect priorities. |
| uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n, |
| const SpinLockWaitTransition trans[], |
| SchedulingMode scheduling_mode); |
| |
| // If possible, wake some thread that has called SpinLockDelay(w, ...). If `all` |
| // is true, wake all such threads. On some systems, this may be a no-op; on |
| // those systems, threads calling SpinLockDelay() will always wake eventually |
| // even if SpinLockWake() is never called. |
| void SpinLockWake(std::atomic<uint32_t> *w, bool all); |
| |
| // Wait for an appropriate spin delay on iteration "loop" of a |
| // spin loop on location *w, whose previously observed value was "value". |
| // SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick, |
| // or may wait for a call to SpinLockWake(w). |
| void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop, |
| base_internal::SchedulingMode scheduling_mode); |
| |
| // Helper used by AbslInternalSpinLockDelay. |
| // Returns a suggested delay in nanoseconds for iteration number "loop". |
| int SpinLockSuggestedDelayNS(int loop); |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| // In some build configurations we pass --detect-odr-violations to the |
| // gold linker. This causes it to flag weak symbol overrides as ODR |
| // violations. Because ODR only applies to C++ and not C, |
| // --detect-odr-violations ignores symbols not mangled with C++ names. |
| // By changing our extension points to be extern "C", we dodge this |
| // check. |
| extern "C" { |
| void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(std::atomic<uint32_t> *w, |
| bool all); |
| void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( |
| std::atomic<uint32_t> *w, uint32_t value, int loop, |
| absl::base_internal::SchedulingMode scheduling_mode); |
| } |
| |
| inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w, |
| bool all) { |
| ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(w, all); |
| } |
| |
| inline void absl::base_internal::SpinLockDelay( |
| std::atomic<uint32_t> *w, uint32_t value, int loop, |
| absl::base_internal::SchedulingMode scheduling_mode) { |
| ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay) |
| (w, value, loop, scheduling_mode); |
| } |
| |
| #endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ |
| *þ |
| soong/.intermediates/external/abseil-cpp/absl_base_nullability_hdrs/gen/my_include_dir/absl/base/internal/nullability_deprecated.hö// Copyright 2023 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_NULLABILITY_DEPRECATED_H_ |
| #define ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_ |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace nullability_internal { |
| |
| template <typename T> |
| using NullableImpl |
| #if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) |
| [[clang::annotate("Nullable")]] |
| #endif |
| // Don't add the _Nullable attribute in Objective-C compiles. Many Objective-C |
| // projects enable the `-Wnullable-to-nonnull-conversion warning`, which is |
| // liable to produce false positives. |
| #if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__) |
| = T _Nullable; |
| #else |
| = T; |
| #endif |
| |
| template <typename T> |
| using NonnullImpl |
| #if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) |
| [[clang::annotate("Nonnull")]] |
| #endif |
| #if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__) |
| = T _Nonnull; |
| #else |
| = T; |
| #endif |
| |
| template <typename T> |
| using NullabilityUnknownImpl |
| #if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) |
| [[clang::annotate("Nullability_Unspecified")]] |
| #endif |
| #if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__) |
| = T _Null_unspecified; |
| #else |
| = T; |
| #endif |
| |
| } // namespace nullability_internal |
| |
| // The following template aliases are deprecated forms of nullability |
| // annotations. They have some limitations, for example, an incompatibility with |
| // `auto*` pointers, as `auto` cannot be used in a template argument. |
| // |
| // It is important to note that these annotations are not distinct strong |
| // *types*. They are alias templates defined to be equal to the underlying |
| // pointer type. A pointer annotated `Nonnull<T*>`, for example, is simply a |
| // pointer of type `T*`. |
| // |
| // Prefer the macro style annotations in `absl/base/nullability.h` instead. |
| |
| // absl::Nonnull, analogous to absl_nonnull |
| // |
| // Example: |
| // absl::Nonnull<int*> foo; |
| // Is equivalent to: |
| // int* absl_nonnull foo; |
| template <typename T> |
| using Nonnull [[deprecated("Use `absl_nonnull`.")]] = |
| nullability_internal::NonnullImpl<T>; |
| |
| // absl::Nullable, analogous to absl_nullable |
| // |
| // Example: |
| // absl::Nullable<int*> foo; |
| // Is equivalent to: |
| // int* absl_nullable foo; |
| template <typename T> |
| using Nullable [[deprecated("Use `absl_nullable`.")]] = |
| nullability_internal::NullableImpl<T>; |
| |
| // absl::NullabilityUnknown, analogous to absl_nullability_unknown |
| // |
| // Example: |
| // absl::NullabilityUnknown<int*> foo; |
| // Is equivalent to: |
| // int* absl_nullability_unknown foo; |
| template <typename T> |
| using NullabilityUnknown [[deprecated("Use `absl_nullability_unknown`.")]] = |
| nullability_internal::NullabilityUnknownImpl<T>; |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_ |
| *õ |
| soong/.intermediates/external/abseil-cpp/absl_strings_str_format_internal_hdrs/gen/my_include_dir/absl/strings/internal/str_format/output.hä// 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. |
| // |
| // Output extension hooks for the Format library. |
| // `internal::InvokeFlush` calls the appropriate flush function for the |
| // specified output argument. |
| // `BufferRawSink` is a simple output sink for a char buffer. Used by SnprintF. |
| // `FILERawSink` is a std::FILE* based sink. Used by PrintF and FprintF. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ |
| #define ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ |
| |
| #include <cstdio> |
| #include <ios> |
| #include <ostream> |
| #include <string> |
| |
| #include "absl/base/port.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace str_format_internal { |
| |
| // RawSink implementation that writes into a char* buffer. |
| // It will not overflow the buffer, but will keep the total count of chars |
| // that would have been written. |
| class BufferRawSink { |
| public: |
| BufferRawSink(char* buffer, size_t size) : buffer_(buffer), size_(size) {} |
| |
| size_t total_written() const { return total_written_; } |
| void Write(string_view v); |
| |
| private: |
| char* buffer_; |
| size_t size_; |
| size_t total_written_ = 0; |
| }; |
| |
| // RawSink implementation that writes into a FILE*. |
| // It keeps track of the total number of bytes written and any error encountered |
| // during the writes. |
| class FILERawSink { |
| public: |
| explicit FILERawSink(std::FILE* output) : output_(output) {} |
| |
| void Write(string_view v); |
| |
| size_t count() const { return count_; } |
| int error() const { return error_; } |
| |
| private: |
| std::FILE* output_; |
| int error_ = 0; |
| size_t count_ = 0; |
| }; |
| |
| // Provide RawSink integration with common types from the STL. |
| inline void AbslFormatFlush(std::string* out, string_view s) { |
| out->append(s.data(), s.size()); |
| } |
| inline void AbslFormatFlush(std::ostream* out, string_view s) { |
| out->write(s.data(), static_cast<std::streamsize>(s.size())); |
| } |
| |
| inline void AbslFormatFlush(FILERawSink* sink, string_view v) { |
| sink->Write(v); |
| } |
| |
| inline void AbslFormatFlush(BufferRawSink* sink, string_view v) { |
| sink->Write(v); |
| } |
| |
| // This is a SFINAE to get a better compiler error message when the type |
| // is not supported. |
| template <typename T> |
| auto InvokeFlush(T* out, string_view s) -> decltype(AbslFormatFlush(out, s)) { |
| AbslFormatFlush(out, s); |
| } |
| |
| } // namespace str_format_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ |
| *Ý@ |
| soong/.intermediates/external/abseil-cpp/absl_strings_str_format_internal_hdrs/gen/my_include_dir/absl/strings/internal/str_format/bind.hÎ?// Copyright 2020 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ |
| #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ |
| |
| #include <cassert> |
| #include <cstdio> |
| #include <ostream> |
| #include <string> |
| |
| #include "absl/base/config.h" |
| #include "absl/container/inlined_vector.h" |
| #include "absl/strings/internal/str_format/arg.h" |
| #include "absl/strings/internal/str_format/checker.h" |
| #include "absl/strings/internal/str_format/constexpr_parser.h" |
| #include "absl/strings/internal/str_format/extension.h" |
| #include "absl/strings/internal/str_format/parser.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/types/span.h" |
| #include "absl/utility/utility.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| class UntypedFormatSpec; |
| |
| namespace str_format_internal { |
| |
| class BoundConversion : public FormatConversionSpecImpl { |
| public: |
| const FormatArgImpl* arg() const { return arg_; } |
| void set_arg(const FormatArgImpl* a) { arg_ = a; } |
| |
| private: |
| const FormatArgImpl* arg_; |
| }; |
| |
| // This is the type-erased class that the implementation uses. |
| class UntypedFormatSpecImpl { |
| public: |
| UntypedFormatSpecImpl() = delete; |
| |
| explicit UntypedFormatSpecImpl(string_view s) |
| : data_(s.data()), size_(s.size()) {} |
| explicit UntypedFormatSpecImpl( |
| const str_format_internal::ParsedFormatBase* pc) |
| : data_(pc), size_(~size_t{}) {} |
| |
| bool has_parsed_conversion() const { return size_ == ~size_t{}; } |
| |
| string_view str() const { |
| assert(!has_parsed_conversion()); |
| return string_view(static_cast<const char*>(data_), size_); |
| } |
| const str_format_internal::ParsedFormatBase* parsed_conversion() const { |
| assert(has_parsed_conversion()); |
| return static_cast<const str_format_internal::ParsedFormatBase*>(data_); |
| } |
| |
| template <typename T> |
| static const UntypedFormatSpecImpl& Extract(const T& s) { |
| return s.spec_; |
| } |
| |
| private: |
| const void* data_; |
| size_t size_; |
| }; |
| |
| template <typename T, FormatConversionCharSet...> |
| struct MakeDependent { |
| using type = T; |
| }; |
| |
| // Implicitly convertible from `const char*`, `string_view`, and the |
| // `ExtendedParsedFormat` type. This abstraction allows all format functions to |
| // operate on any without providing too many overloads. |
| template <FormatConversionCharSet... Args> |
| class FormatSpecTemplate |
| : public MakeDependent<UntypedFormatSpec, Args...>::type { |
| using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type; |
| |
| template <bool res> |
| struct ErrorMaker { |
| constexpr bool operator()(int) const { return res; } |
| }; |
| |
| template <int i, int j> |
| static constexpr bool CheckArity(ErrorMaker<true> SpecifierCount = {}, |
| ErrorMaker<i == j> ParametersPassed = {}) { |
| static_assert(SpecifierCount(i) == ParametersPassed(j), |
| "Number of arguments passed must match the number of " |
| "conversion specifiers."); |
| return true; |
| } |
| |
| template <FormatConversionCharSet specified, FormatConversionCharSet passed, |
| int arg> |
| static constexpr bool CheckMatch( |
| ErrorMaker<Contains(specified, passed)> MismatchedArgumentNumber = {}) { |
| static_assert(MismatchedArgumentNumber(arg), |
| "Passed argument must match specified format."); |
| return true; |
| } |
| |
| template <FormatConversionCharSet... C, size_t... I> |
| static bool CheckMatches(absl::index_sequence<I...>) { |
| bool res[] = {true, CheckMatch<Args, C, I + 1>()...}; |
| (void)res; |
| return true; |
| } |
| |
| public: |
| #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
| |
| // Honeypot overload for when the string is not constexpr. |
| // We use the 'unavailable' attribute to give a better compiler error than |
| // just 'method is deleted'. |
| FormatSpecTemplate(...) // NOLINT |
| __attribute__((unavailable("Format string is not constexpr."))); |
| |
| // Honeypot overload for when the format is constexpr and invalid. |
| // We use the 'unavailable' attribute to give a better compiler error than |
| // just 'method is deleted'. |
| // To avoid checking the format twice, we just check that the format is |
| // constexpr. If it is valid, then the overload below will kick in. |
| // We add the template here to make this overload have lower priority. |
| template <typename = void> |
| FormatSpecTemplate(const char* s) // NOLINT |
| __attribute__(( |
| enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"), |
| unavailable( |
| "Format specified does not match the arguments passed."))); |
| |
| template <typename T = void> |
| FormatSpecTemplate(string_view s) // NOLINT |
| __attribute__((enable_if(str_format_internal::EnsureConstexpr(s), |
| "constexpr trap"))) |
| : Base("to avoid noise in the compiler error") { |
| static_assert(sizeof(T*) == 0, |
| "Format specified does not match the arguments passed."); |
| } |
| |
| // Good format overload. |
| FormatSpecTemplate(const char* s) // NOLINT |
| __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) |
| : Base(s) {} |
| |
| FormatSpecTemplate(string_view s) // NOLINT |
| __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) |
| : Base(s) {} |
| |
| #else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
| |
| FormatSpecTemplate(const char* s) : Base(s) {} // NOLINT |
| FormatSpecTemplate(string_view s) : Base(s) {} // NOLINT |
| |
| #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
| |
| template <FormatConversionCharSet... C> |
| FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT |
| : Base(&pc) { |
| CheckArity<sizeof...(C), sizeof...(Args)>(); |
| CheckMatches<C...>(absl::make_index_sequence<sizeof...(C)>{}); |
| } |
| }; |
| |
| class Streamable { |
| public: |
| Streamable(const UntypedFormatSpecImpl& format, |
| absl::Span<const FormatArgImpl> args) |
| : format_(format), args_(args.begin(), args.end()) {} |
| |
| std::ostream& Print(std::ostream& os) const; |
| |
| friend std::ostream& operator<<(std::ostream& os, const Streamable& l) { |
| return l.Print(os); |
| } |
| |
| private: |
| const UntypedFormatSpecImpl& format_; |
| absl::InlinedVector<FormatArgImpl, 4> args_; |
| }; |
| |
| // for testing |
| std::string Summarize(UntypedFormatSpecImpl format, |
| absl::Span<const FormatArgImpl> args); |
| bool BindWithPack(const UnboundConversion* props, |
| absl::Span<const FormatArgImpl> pack, BoundConversion* bound); |
| |
| bool FormatUntyped(FormatRawSinkImpl raw_sink, UntypedFormatSpecImpl format, |
| absl::Span<const FormatArgImpl> args); |
| |
| std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format, |
| absl::Span<const FormatArgImpl> args); |
| |
| std::string FormatPack(UntypedFormatSpecImpl format, |
| absl::Span<const FormatArgImpl> args); |
| |
| int FprintF(std::FILE* output, UntypedFormatSpecImpl format, |
| absl::Span<const FormatArgImpl> args); |
| int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format, |
| absl::Span<const FormatArgImpl> args); |
| |
| // Returned by Streamed(v). Converts via '%s' to the std::string created |
| // by std::ostream << v. |
| template <typename T> |
| class StreamedWrapper { |
| public: |
| explicit StreamedWrapper(const T& v) : v_(v) {} |
| |
| private: |
| template <typename S> |
| friend ArgConvertResult<FormatConversionCharSetUnion( |
| FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::v)> |
| FormatConvertImpl(const StreamedWrapper<S>& v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* out); |
| const T& v_; |
| }; |
| |
| } // namespace str_format_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ |
| *±½ |
| xsoong/.intermediates/external/abseil-cpp/absl_log_internal_check_op_hdrs/gen/my_include_dir/absl/log/internal/check_op.h³¼// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/internal/check_op.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This file declares helpers routines and macros used to implement `CHECK` |
| // macros. |
| |
| #ifndef ABSL_LOG_INTERNAL_CHECK_OP_H_ |
| #define ABSL_LOG_INTERNAL_CHECK_OP_H_ |
| |
| #include <stdint.h> |
| |
| #include <cstddef> |
| #include <ostream> |
| #include <sstream> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/casts.h" |
| #include "absl/base/config.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/optimization.h" |
| #include "absl/log/internal/nullguard.h" |
| #include "absl/log/internal/nullstream.h" |
| #include "absl/log/internal/strip.h" |
| #include "absl/strings/has_absl_stringify.h" |
| #include "absl/strings/string_view.h" |
| |
| // `ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL` wraps string literals that |
| // should be stripped when `ABSL_MIN_LOG_LEVEL` exceeds `kFatal`. |
| #ifdef ABSL_MIN_LOG_LEVEL |
| #define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal) \ |
| (::absl::LogSeverity::kFatal >= \ |
| static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) \ |
| ? (literal) \ |
| : "") |
| #else |
| #define ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(literal) (literal) |
| #endif |
| |
| #ifdef NDEBUG |
| // `NDEBUG` is defined, so `DCHECK_EQ(x, y)` and so on do nothing. However, we |
| // still want the compiler to parse `x` and `y`, because we don't want to lose |
| // potentially useful errors and warnings. |
| #define ABSL_LOG_INTERNAL_DCHECK_NOP(x, y) \ |
| while (false && ((void)(x), (void)(y), 0)) \ |
| ::absl::log_internal::NullStream().InternalStream() |
| #endif |
| |
| #define ABSL_LOG_INTERNAL_CHECK_OP(name, op, val1, val1_text, val2, val2_text) \ |
| while (const char* absl_nullable absl_log_internal_check_op_result \ |
| [[maybe_unused]] = ::absl::log_internal::name##Impl( \ |
| ::absl::log_internal::GetReferenceableValue(val1), \ |
| ::absl::log_internal::GetReferenceableValue(val2), \ |
| ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val1_text " " #op \ |
| " " val2_text))) \ |
| ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \ |
| ABSL_LOG_INTERNAL_CHECK(::absl::implicit_cast<const char* absl_nonnull>( \ |
| absl_log_internal_check_op_result)) \ |
| .InternalStream() |
| #define ABSL_LOG_INTERNAL_QCHECK_OP(name, op, val1, val1_text, val2, \ |
| val2_text) \ |
| while (const char* absl_nullable absl_log_internal_qcheck_op_result = \ |
| ::absl::log_internal::name##Impl( \ |
| ::absl::log_internal::GetReferenceableValue(val1), \ |
| ::absl::log_internal::GetReferenceableValue(val2), \ |
| ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \ |
| val1_text " " #op " " val2_text))) \ |
| ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \ |
| ABSL_LOG_INTERNAL_QCHECK(::absl::implicit_cast<const char* absl_nonnull>( \ |
| absl_log_internal_qcheck_op_result)) \ |
| .InternalStream() |
| #define ABSL_LOG_INTERNAL_CHECK_STROP(func, op, expected, s1, s1_text, s2, \ |
| s2_text) \ |
| while (const char* absl_nullable absl_log_internal_check_strop_result = \ |
| ::absl::log_internal::Check##func##expected##Impl( \ |
| (s1), (s2), \ |
| ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(s1_text " " #op \ |
| " " s2_text))) \ |
| ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \ |
| ABSL_LOG_INTERNAL_CHECK(::absl::implicit_cast<const char* absl_nonnull>( \ |
| absl_log_internal_check_strop_result)) \ |
| .InternalStream() |
| #define ABSL_LOG_INTERNAL_QCHECK_STROP(func, op, expected, s1, s1_text, s2, \ |
| s2_text) \ |
| while (const char* absl_nullable absl_log_internal_qcheck_strop_result = \ |
| ::absl::log_internal::Check##func##expected##Impl( \ |
| (s1), (s2), \ |
| ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(s1_text " " #op \ |
| " " s2_text))) \ |
| ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \ |
| ABSL_LOG_INTERNAL_QCHECK(::absl::implicit_cast<const char* absl_nonnull>( \ |
| absl_log_internal_qcheck_strop_result)) \ |
| .InternalStream() |
| |
| // This one is tricky: |
| // * We must evaluate `val` exactly once, yet we need to do two things with it: |
| // evaluate `.ok()` and (sometimes) `.ToString()`. |
| // * `val` might be an `absl::Status` or some `absl::StatusOr<T>`. |
| // * `val` might be e.g. `ATemporary().GetStatus()`, which may return a |
| // reference to a member of `ATemporary` that is only valid until the end of |
| // the full expression. |
| // * We don't want this file to depend on `absl::Status` `#include`s or linkage, |
| // nor do we want to move the definition to status and introduce a dependency |
| // in the other direction. We can be assured that callers must already have a |
| // `Status` and the necessary `#include`s and linkage. |
| // * Callsites should be small and fast (at least when `val.ok()`): one branch, |
| // minimal stack footprint. |
| // * In particular, the string concat stuff should be out-of-line and emitted |
| // in only one TU to save linker input size |
| // * We want the `val.ok()` check inline so static analyzers and optimizers can |
| // see it. |
| // * As usual, no braces so we can stream into the expansion with `operator<<`. |
| // * Also as usual, it must expand to a single (partial) statement with no |
| // ambiguous-else problems. |
| // * When stripped by `ABSL_MIN_LOG_LEVEL`, we must discard the `<expr> is OK` |
| // string literal and abort without doing any streaming. We don't need to |
| // strip the call to stringify the non-ok `Status` as long as we don't log it; |
| // dropping the `Status`'s message text is out of scope. |
| #define ABSL_LOG_INTERNAL_CHECK_OK(val, val_text) \ |
| for (::std::pair<const ::absl::Status* absl_nonnull, \ |
| const char* absl_nullable> \ |
| absl_log_internal_check_ok_goo; \ |
| absl_log_internal_check_ok_goo.first = \ |
| ::absl::log_internal::AsStatus(val), \ |
| absl_log_internal_check_ok_goo.second = \ |
| ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok()) \ |
| ? nullptr \ |
| : ::absl::status_internal::MakeCheckFailString( \ |
| absl_log_internal_check_ok_goo.first, \ |
| ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \ |
| " is OK")), \ |
| !ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok());) \ |
| ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \ |
| ABSL_LOG_INTERNAL_CHECK(::absl::implicit_cast<const char* absl_nonnull>( \ |
| absl_log_internal_check_ok_goo.second)) \ |
| .InternalStream() |
| #define ABSL_LOG_INTERNAL_QCHECK_OK(val, val_text) \ |
| for (::std::pair<const ::absl::Status* absl_nonnull, \ |
| const char* absl_nullable> \ |
| absl_log_internal_qcheck_ok_goo; \ |
| absl_log_internal_qcheck_ok_goo.first = \ |
| ::absl::log_internal::AsStatus(val), \ |
| absl_log_internal_qcheck_ok_goo.second = \ |
| ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok()) \ |
| ? nullptr \ |
| : ::absl::status_internal::MakeCheckFailString( \ |
| absl_log_internal_qcheck_ok_goo.first, \ |
| ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \ |
| " is OK")), \ |
| !ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok());) \ |
| ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \ |
| ABSL_LOG_INTERNAL_QCHECK(::absl::implicit_cast<const char* absl_nonnull>( \ |
| absl_log_internal_qcheck_ok_goo.second)) \ |
| .InternalStream() |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| class Status; |
| template <typename T> |
| class StatusOr; |
| |
| namespace status_internal { |
| ABSL_ATTRIBUTE_PURE_FUNCTION const char* absl_nonnull MakeCheckFailString( |
| const absl::Status* absl_nonnull status, const char* absl_nonnull prefix); |
| } // namespace status_internal |
| |
| namespace log_internal { |
| |
| // Convert a Status or a StatusOr to its underlying status value. |
| // |
| // (This implementation does not require a dep on absl::Status to work.) |
| inline const absl::Status* absl_nonnull AsStatus(const absl::Status& s) { |
| return &s; |
| } |
| template <typename T> |
| const absl::Status* absl_nonnull AsStatus(const absl::StatusOr<T>& s) { |
| return &s.status(); |
| } |
| |
| // A helper class for formatting `expr (V1 vs. V2)` in a `CHECK_XX` statement. |
| // See `MakeCheckOpString` for sample usage. |
| class CheckOpMessageBuilder final { |
| public: |
| // Inserts `exprtext` and ` (` to the stream. |
| explicit CheckOpMessageBuilder(const char* absl_nonnull exprtext); |
| ~CheckOpMessageBuilder() = default; |
| // For inserting the first variable. |
| std::ostream& ForVar1() { return stream_; } |
| // For inserting the second variable (adds an intermediate ` vs. `). |
| std::ostream& ForVar2(); |
| // Get the result (inserts the closing `)`). |
| const char* absl_nonnull NewString(); |
| |
| private: |
| std::ostringstream stream_; |
| }; |
| |
| // This formats a value for a failing `CHECK_XX` statement. Ordinarily, it uses |
| // the definition for `operator<<`, with a few special cases below. |
| template <typename T> |
| inline void MakeCheckOpValueString(std::ostream& os, const T& v) { |
| os << log_internal::NullGuard<T>::Guard(v); |
| } |
| |
| // Overloads for char types provide readable values for unprintable characters. |
| void MakeCheckOpValueString(std::ostream& os, char v); |
| void MakeCheckOpValueString(std::ostream& os, signed char v); |
| void MakeCheckOpValueString(std::ostream& os, unsigned char v); |
| void MakeCheckOpValueString(std::ostream& os, const void* absl_nullable p); |
| |
| namespace detect_specialization { |
| |
| // MakeCheckOpString is being specialized for every T and U pair that is being |
| // passed to the CHECK_op macros. However, there is a lot of redundancy in these |
| // specializations that creates unnecessary library and binary bloat. |
| // The number of instantiations tends to be O(n^2) because we have two |
| // independent inputs. This technique works by reducing `n`. |
| // |
| // Most user-defined types being passed to CHECK_op end up being printed as a |
| // builtin type. For example, enums tend to be implicitly converted to its |
| // underlying type when calling operator<<, and pointers are printed with the |
| // `const void*` overload. |
| // To reduce the number of instantiations we coerce these values before calling |
| // MakeCheckOpString instead of inside it. |
| // |
| // To detect if this coercion is needed, we duplicate all the relevant |
| // operator<< overloads as specified in the standard, just in a different |
| // namespace. If the call to `stream << value` becomes ambiguous, it means that |
| // one of these overloads is the one selected by overload resolution. We then |
| // do overload resolution again just with our overload set to see which one gets |
| // selected. That tells us which type to coerce to. |
| // If the augmented call was not ambiguous, it means that none of these were |
| // selected and we can't coerce the input. |
| // |
| // As a secondary step to reduce code duplication, we promote integral types to |
| // their 64-bit variant. This does not change the printed value, but reduces the |
| // number of instantiations even further. Promoting an integer is very cheap at |
| // the call site. |
| int64_t operator<<(std::ostream&, short value); // NOLINT |
| int64_t operator<<(std::ostream&, unsigned short value); // NOLINT |
| int64_t operator<<(std::ostream&, int value); |
| int64_t operator<<(std::ostream&, unsigned int value); |
| int64_t operator<<(std::ostream&, long value); // NOLINT |
| uint64_t operator<<(std::ostream&, unsigned long value); // NOLINT |
| int64_t operator<<(std::ostream&, long long value); // NOLINT |
| uint64_t operator<<(std::ostream&, unsigned long long value); // NOLINT |
| float operator<<(std::ostream&, float value); |
| double operator<<(std::ostream&, double value); |
| long double operator<<(std::ostream&, long double value); |
| bool operator<<(std::ostream&, bool value); |
| const void* absl_nullable operator<<(std::ostream&, |
| const void* absl_nullable value); |
| const void* absl_nullable operator<<(std::ostream&, std::nullptr_t); |
| |
| // These `char` overloads are specified like this in the standard, so we have to |
| // write them exactly the same to ensure the call is ambiguous. |
| // If we wrote it in a different way (eg taking std::ostream instead of the |
| // template) then one call might have a higher rank than the other and it would |
| // not be ambiguous. |
| template <typename Traits> |
| char operator<<(std::basic_ostream<char, Traits>&, char); |
| template <typename Traits> |
| signed char operator<<(std::basic_ostream<char, Traits>&, signed char); |
| template <typename Traits> |
| unsigned char operator<<(std::basic_ostream<char, Traits>&, unsigned char); |
| template <typename Traits> |
| const char* absl_nonnull operator<<(std::basic_ostream<char, Traits>&, |
| const char* absl_nonnull); |
| template <typename Traits> |
| const signed char* absl_nonnull operator<<(std::basic_ostream<char, Traits>&, |
| const signed char* absl_nonnull); |
| template <typename Traits> |
| const unsigned char* absl_nonnull operator<<(std::basic_ostream<char, Traits>&, |
| const unsigned char* absl_nonnull); |
| |
| // This overload triggers when the call is not ambiguous. |
| // It means that T is being printed with some overload not on this list. |
| // We keep the value as `const T&`. |
| template <typename T, typename = decltype(std::declval<std::ostream&>() |
| << std::declval<const T&>())> |
| const T& Detect(int); |
| |
| // This overload triggers when the call is ambiguous. |
| // It means that T is either one from this list or printed as one from this |
| // list. Eg an enum that decays to `int` for printing. |
| // We ask the overload set to give us the type we want to convert it to. |
| template <typename T> |
| decltype(detect_specialization::operator<<(std::declval<std::ostream&>(), |
| std::declval<const T&>())) |
| Detect(char); |
| |
| // A sink for AbslStringify which redirects everything to a std::ostream. |
| class StringifySink { |
| public: |
| explicit StringifySink(std::ostream& os ABSL_ATTRIBUTE_LIFETIME_BOUND); |
| |
| void Append(absl::string_view text); |
| void Append(size_t length, char ch); |
| friend void AbslFormatFlush(StringifySink* absl_nonnull sink, |
| absl::string_view text); |
| |
| private: |
| std::ostream& os_; |
| }; |
| |
| // Wraps a type implementing AbslStringify, and implements operator<<. |
| template <typename T> |
| class StringifyToStreamWrapper { |
| public: |
| explicit StringifyToStreamWrapper(const T& v ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| : v_(v) {} |
| |
| friend std::ostream& operator<<(std::ostream& os, |
| const StringifyToStreamWrapper& wrapper) { |
| StringifySink sink(os); |
| AbslStringify(sink, wrapper.v_); |
| return os; |
| } |
| |
| private: |
| const T& v_; |
| }; |
| |
| // This overload triggers when T implements AbslStringify. |
| // StringifyToStreamWrapper is used to allow MakeCheckOpString to use |
| // operator<<. |
| template <typename T> |
| std::enable_if_t<HasAbslStringify<T>::value, |
| StringifyToStreamWrapper<T>> |
| Detect(...); // Ellipsis has lowest preference when int passed. |
| } // namespace detect_specialization |
| |
| template <typename T> |
| using CheckOpStreamType = decltype(detect_specialization::Detect<T>(0)); |
| |
| // Build the error message string. Specify no inlining for code size. |
| template <typename T1, typename T2> |
| ABSL_ATTRIBUTE_RETURNS_NONNULL const char* absl_nonnull MakeCheckOpString( |
| T1 v1, T2 v2, const char* absl_nonnull exprtext) ABSL_ATTRIBUTE_NOINLINE; |
| |
| template <typename T1, typename T2> |
| const char* absl_nonnull MakeCheckOpString(T1 v1, T2 v2, |
| const char* absl_nonnull exprtext) { |
| CheckOpMessageBuilder comb(exprtext); |
| MakeCheckOpValueString(comb.ForVar1(), v1); |
| MakeCheckOpValueString(comb.ForVar2(), v2); |
| return comb.NewString(); |
| } |
| |
| // Add a few commonly used instantiations as extern to reduce size of objects |
| // files. |
| #define ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(x) \ |
| extern template const char* absl_nonnull MakeCheckOpString( \ |
| x, x, const char* absl_nonnull) |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(bool); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(int64_t); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(uint64_t); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(float); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(double); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(char); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(unsigned char); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const std::string&); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const absl::string_view&); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const char* absl_nonnull); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN( |
| const signed char* absl_nonnull); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN( |
| const unsigned char* absl_nonnull); |
| ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void* absl_nonnull); |
| #undef ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN |
| |
| // `ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT` skips formatting the Check_OP result |
| // string iff `ABSL_MIN_LOG_LEVEL` exceeds `kFatal`, instead returning an empty |
| // string. |
| #ifdef ABSL_MIN_LOG_LEVEL |
| #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, v1, v2, exprtext) \ |
| ((::absl::LogSeverity::kFatal >= \ |
| static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL)) \ |
| ? MakeCheckOpString<U1, U2>(v1, v2, exprtext) \ |
| : "") |
| #else |
| #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, v1, v2, exprtext) \ |
| MakeCheckOpString<U1, U2>(v1, v2, exprtext) |
| #endif |
| |
| // Helper functions for `ABSL_LOG_INTERNAL_CHECK_OP` macro family. The |
| // `(int, int)` override works around the issue that the compiler will not |
| // instantiate the template version of the function on values of unnamed enum |
| // type. |
| #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL(name, op) \ |
| template <typename T1, typename T2> \ |
| inline constexpr const char* absl_nullable name##Impl( \ |
| const T1& v1, const T2& v2, const char* absl_nonnull exprtext) { \ |
| using U1 = CheckOpStreamType<T1>; \ |
| using U2 = CheckOpStreamType<T2>; \ |
| return ABSL_PREDICT_TRUE(v1 op v2) \ |
| ? nullptr \ |
| : ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, U1(v1), \ |
| U2(v2), exprtext); \ |
| } \ |
| inline constexpr const char* absl_nullable name##Impl( \ |
| int v1, int v2, const char* absl_nonnull exprtext) { \ |
| return name##Impl<int, int>(v1, v2, exprtext); \ |
| } |
| |
| ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_EQ, ==) |
| ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_NE, !=) |
| ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_LE, <=) |
| ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_LT, <) |
| ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_GE, >=) |
| ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_GT, >) |
| #undef ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT |
| #undef ABSL_LOG_INTERNAL_CHECK_OP_IMPL |
| |
| const char* absl_nullable CheckstrcmptrueImpl( |
| const char* absl_nullable s1, const char* absl_nullable s2, |
| const char* absl_nonnull exprtext); |
| const char* absl_nullable CheckstrcmpfalseImpl( |
| const char* absl_nullable s1, const char* absl_nullable s2, |
| const char* absl_nonnull exprtext); |
| const char* absl_nullable CheckstrcasecmptrueImpl( |
| const char* absl_nullable s1, const char* absl_nullable s2, |
| const char* absl_nonnull exprtext); |
| const char* absl_nullable CheckstrcasecmpfalseImpl( |
| const char* absl_nullable s1, const char* absl_nullable s2, |
| const char* absl_nonnull exprtext); |
| |
| // `CHECK_EQ` and friends want to pass their arguments by reference, however |
| // this winds up exposing lots of cases where people have defined and |
| // initialized static const data members but never declared them (i.e. in a .cc |
| // file), meaning they are not referenceable. This function avoids that problem |
| // for integers (the most common cases) by overloading for every primitive |
| // integer type, even the ones we discourage, and returning them by value. |
| // NOLINTBEGIN(runtime/int) |
| // NOLINTBEGIN(google-runtime-int) |
| template <typename T> |
| inline constexpr const T& GetReferenceableValue(const T& t) { |
| return t; |
| } |
| inline constexpr char GetReferenceableValue(char t) { return t; } |
| inline constexpr unsigned char GetReferenceableValue(unsigned char t) { |
| return t; |
| } |
| inline constexpr signed char GetReferenceableValue(signed char t) { return t; } |
| inline constexpr short GetReferenceableValue(short t) { return t; } |
| inline constexpr unsigned short GetReferenceableValue(unsigned short t) { |
| return t; |
| } |
| inline constexpr int GetReferenceableValue(int t) { return t; } |
| inline constexpr unsigned int GetReferenceableValue(unsigned int t) { |
| return t; |
| } |
| inline constexpr long GetReferenceableValue(long t) { return t; } |
| inline constexpr unsigned long GetReferenceableValue(unsigned long t) { |
| return t; |
| } |
| inline constexpr long long GetReferenceableValue(long long t) { return t; } |
| inline constexpr unsigned long long GetReferenceableValue( |
| unsigned long long t) { |
| return t; |
| } |
| // NOLINTEND(google-runtime-int) |
| // NOLINTEND(runtime/int) |
| |
| } // namespace log_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_LOG_INTERNAL_CHECK_OP_H_ |
| *} |
| soong/.intermediates/external/abseil-cpp/absl_base_dynamic_annotations_hdrs/gen/my_include_dir/absl/base/internal/dynamic_annotations.h|// 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_ |
| * |
| soong/.intermediates/external/abseil-cpp/absl_strings_cordz_update_scope_hdrs/gen/my_include_dir/absl/strings/internal/cordz_update_scope.h// 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_STRINGS_INTERNAL_CORDZ_UPDATE_SCOPE_H_ |
| #define ABSL_STRINGS_INTERNAL_CORDZ_UPDATE_SCOPE_H_ |
| |
| #include "absl/base/config.h" |
| #include "absl/base/optimization.h" |
| #include "absl/base/thread_annotations.h" |
| #include "absl/strings/internal/cord_internal.h" |
| #include "absl/strings/internal/cordz_info.h" |
| #include "absl/strings/internal/cordz_update_tracker.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // CordzUpdateScope scopes an update to the provided CordzInfo. |
| // The class invokes `info->Lock(method)` and `info->Unlock()` to guard |
| // cordrep updates. This class does nothing if `info` is null. |
| // See also the 'Lock`, `Unlock` and `SetCordRep` methods in `CordzInfo`. |
| class ABSL_SCOPED_LOCKABLE CordzUpdateScope { |
| public: |
| CordzUpdateScope(CordzInfo* info, CordzUpdateTracker::MethodIdentifier method) |
| ABSL_EXCLUSIVE_LOCK_FUNCTION(info) |
| : info_(info) { |
| if (ABSL_PREDICT_FALSE(info_)) { |
| info->Lock(method); |
| } |
| } |
| |
| // CordzUpdateScope can not be copied or assigned to. |
| CordzUpdateScope(CordzUpdateScope&& rhs) = delete; |
| CordzUpdateScope(const CordzUpdateScope&) = delete; |
| CordzUpdateScope& operator=(CordzUpdateScope&& rhs) = delete; |
| CordzUpdateScope& operator=(const CordzUpdateScope&) = delete; |
| |
| ~CordzUpdateScope() ABSL_UNLOCK_FUNCTION() { |
| if (ABSL_PREDICT_FALSE(info_)) { |
| info_->Unlock(); |
| } |
| } |
| |
| void SetCordRep(CordRep* rep) const { |
| if (ABSL_PREDICT_FALSE(info_)) { |
| info_->SetCordRep(rep); |
| } |
| } |
| |
| CordzInfo* info() const { return info_; } |
| |
| private: |
| CordzInfo* info_; |
| }; |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORDZ_UPDATE_SCOPE_H_ |
| *Ð |
| jsoong/.intermediates/external/abseil-cpp/absl_types_optional_hdrs/gen/my_include_dir/absl/types/optional.há |
| // 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. |
| // |
| // ----------------------------------------------------------------------------- |
| // optional.h |
| // ----------------------------------------------------------------------------- |
| // |
| // Historical note: Abseil once provided an implementation of `absl::optional` |
| // as a polyfill for `std::optional` prior to C++17. Now that C++17 is required, |
| // `absl::optional` is an alias for `std::optional`. |
| |
| #ifndef ABSL_TYPES_OPTIONAL_H_ |
| #define ABSL_TYPES_OPTIONAL_H_ |
| |
| #include <optional> |
| |
| #include "absl/base/config.h" |
| #include "absl/utility/utility.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| using std::bad_optional_access; |
| using std::optional; |
| using std::make_optional; |
| using std::nullopt_t; |
| using std::nullopt; |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_TYPES_OPTIONAL_H_ |
| *¸? |
| fsoong/.intermediates/external/abseil-cpp/absl_numeric_bits_hdrs/gen/my_include_dir/absl/numeric/bits.hÍ>// 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. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: bits.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This file contains implementations of C++20's bitwise math functions, as |
| // defined by: |
| // |
| // P0553R4: |
| // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html |
| // P0556R3: |
| // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0556r3.html |
| // P1355R2: |
| // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1355r2.html |
| // P1956R1: |
| // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1956r1.pdf |
| // P0463R1 |
| // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0463r1.html |
| // P1272R4 |
| // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1272r4.html |
| // |
| // When using a standard library that implements these functions, we use the |
| // standard library's implementation. |
| |
| #ifndef ABSL_NUMERIC_BITS_H_ |
| #define ABSL_NUMERIC_BITS_H_ |
| |
| #include <cstdint> |
| #include <limits> |
| #include <type_traits> |
| |
| #include "absl/base/config.h" |
| |
| #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L |
| #include <bit> |
| #endif |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/internal/endian.h" |
| #include "absl/numeric/internal/bits.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // https://github.com/llvm/llvm-project/issues/64544 |
| // libc++ had the wrong signature for std::rotl and std::rotr |
| // prior to libc++ 18.0. |
| // |
| #if (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L) && \ |
| (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 180000) |
| using std::rotl; |
| using std::rotr; |
| |
| #else |
| |
| // Rotating functions |
| template <class T> |
| [[nodiscard]] constexpr |
| typename std::enable_if<std::is_unsigned<T>::value, T>::type |
| rotl(T x, int s) noexcept { |
| return numeric_internal::RotateLeft(x, s); |
| } |
| |
| template <class T> |
| [[nodiscard]] constexpr |
| typename std::enable_if<std::is_unsigned<T>::value, T>::type |
| rotr(T x, int s) noexcept { |
| return numeric_internal::RotateRight(x, s); |
| } |
| |
| #endif |
| |
| // https://github.com/llvm/llvm-project/issues/64544 |
| // libc++ had the wrong signature for std::rotl and std::rotr |
| // prior to libc++ 18.0. |
| // |
| #if (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L) |
| |
| using std::countl_one; |
| using std::countl_zero; |
| using std::countr_one; |
| using std::countr_zero; |
| using std::popcount; |
| |
| #else |
| |
| // Counting functions |
| // |
| // While these functions are typically constexpr, on some platforms, they may |
| // not be marked as constexpr due to constraints of the compiler/available |
| // intrinsics. |
| template <class T> |
| ABSL_INTERNAL_CONSTEXPR_CLZ inline |
| typename std::enable_if<std::is_unsigned<T>::value, int>::type |
| countl_zero(T x) noexcept { |
| return numeric_internal::CountLeadingZeroes(x); |
| } |
| |
| template <class T> |
| ABSL_INTERNAL_CONSTEXPR_CLZ inline |
| typename std::enable_if<std::is_unsigned<T>::value, int>::type |
| countl_one(T x) noexcept { |
| // Avoid integer promotion to a wider type |
| return countl_zero(static_cast<T>(~x)); |
| } |
| |
| template <class T> |
| ABSL_INTERNAL_CONSTEXPR_CTZ inline |
| typename std::enable_if<std::is_unsigned<T>::value, int>::type |
| countr_zero(T x) noexcept { |
| return numeric_internal::CountTrailingZeroes(x); |
| } |
| |
| template <class T> |
| ABSL_INTERNAL_CONSTEXPR_CTZ inline |
| typename std::enable_if<std::is_unsigned<T>::value, int>::type |
| countr_one(T x) noexcept { |
| // Avoid integer promotion to a wider type |
| return countr_zero(static_cast<T>(~x)); |
| } |
| |
| template <class T> |
| ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline |
| typename std::enable_if<std::is_unsigned<T>::value, int>::type |
| popcount(T x) noexcept { |
| return numeric_internal::Popcount(x); |
| } |
| |
| #endif |
| |
| #if (defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L) |
| |
| using std::bit_ceil; |
| using std::bit_floor; |
| using std::bit_width; |
| using std::has_single_bit; |
| |
| #else |
| |
| // Returns: true if x is an integral power of two; false otherwise. |
| template <class T> |
| constexpr inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type |
| has_single_bit(T x) noexcept { |
| return x != 0 && (x & (x - 1)) == 0; |
| } |
| |
| // Returns: If x == 0, 0; otherwise one plus the base-2 logarithm of x, with any |
| // fractional part discarded. |
| template <class T> |
| ABSL_INTERNAL_CONSTEXPR_CLZ inline |
| typename std::enable_if<std::is_unsigned<T>::value, int>::type |
| bit_width(T x) noexcept { |
| return std::numeric_limits<T>::digits - countl_zero(x); |
| } |
| |
| // Returns: If x == 0, 0; otherwise the maximal value y such that |
| // has_single_bit(y) is true and y <= x. |
| template <class T> |
| ABSL_INTERNAL_CONSTEXPR_CLZ inline |
| typename std::enable_if<std::is_unsigned<T>::value, T>::type |
| bit_floor(T x) noexcept { |
| return x == 0 ? 0 : T{1} << (bit_width(x) - 1); |
| } |
| |
| // Returns: N, where N is the smallest power of 2 greater than or equal to x. |
| // |
| // Preconditions: N is representable as a value of type T. |
| template <class T> |
| ABSL_INTERNAL_CONSTEXPR_CLZ inline |
| typename std::enable_if<std::is_unsigned<T>::value, T>::type |
| bit_ceil(T x) { |
| // If T is narrower than unsigned, T{1} << bit_width will be promoted. We |
| // want to force it to wraparound so that bit_ceil of an invalid value are not |
| // core constant expressions. |
| // |
| // BitCeilNonPowerOf2 triggers an overflow in constexpr contexts if we would |
| // undergo promotion to unsigned but not fit the result into T without |
| // truncation. |
| return has_single_bit(x) ? T{1} << (bit_width(x) - 1) |
| : numeric_internal::BitCeilNonPowerOf2(x); |
| } |
| |
| #endif |
| |
| #if defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L |
| |
| // https://en.cppreference.com/w/cpp/types/endian |
| // |
| // Indicates the endianness of all scalar types: |
| // * If all scalar types are little-endian, `absl::endian::native` equals |
| // absl::endian::little. |
| // * If all scalar types are big-endian, `absl::endian::native` equals |
| // `absl::endian::big`. |
| // * Platforms that use anything else are unsupported. |
| using std::endian; |
| |
| #else |
| |
| enum class endian { |
| little, |
| big, |
| #if defined(ABSL_IS_LITTLE_ENDIAN) |
| native = little |
| #elif defined(ABSL_IS_BIG_ENDIAN) |
| native = big |
| #else |
| #error "Endian detection needs to be set up for this platform" |
| #endif |
| }; |
| |
| #endif // defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L |
| |
| #if defined(__cpp_lib_byteswap) && __cpp_lib_byteswap >= 202110L |
| |
| // https://en.cppreference.com/w/cpp/numeric/byteswap |
| // |
| // Reverses the bytes in the given integer value `x`. |
| // |
| // `absl::byteswap` participates in overload resolution only if `T` satisfies |
| // integral, i.e., `T` is an integer type. The program is ill-formed if `T` has |
| // padding bits. |
| using std::byteswap; |
| |
| #else |
| |
| template <class T> |
| [[nodiscard]] constexpr T byteswap(T x) noexcept { |
| static_assert(std::is_integral_v<T>, |
| "byteswap requires an integral argument"); |
| static_assert( |
| sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, |
| "byteswap works only with 8, 16, 32, or 64-bit integers"); |
| if constexpr (sizeof(T) == 1) { |
| return x; |
| } else if constexpr (sizeof(T) == 2) { |
| return static_cast<T>(gbswap_16(static_cast<uint16_t>(x))); |
| } else if constexpr (sizeof(T) == 4) { |
| return static_cast<T>(gbswap_32(static_cast<uint32_t>(x))); |
| } else if constexpr (sizeof(T) == 8) { |
| return static_cast<T>(gbswap_64(static_cast<uint64_t>(x))); |
| } |
| } |
| |
| #endif // defined(__cpp_lib_byteswap) && __cpp_lib_byteswap >= 202110L |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_NUMERIC_BITS_H_ |
| *® |
| soong/.intermediates/external/abseil-cpp/absl_time_internal_cctz_time_zone_hdrs/gen/my_include_dir/absl/time/internal/cctz/include/cctz/time_zone.h// Copyright 2016 Google Inc. All Rights Reserved. |
| // |
| // 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. |
| |
| // A library for translating between absolute times (represented by |
| // std::chrono::time_points of the std::chrono::system_clock) and civil |
| // times (represented by cctz::civil_second) using the rules defined by |
| // a time zone (cctz::time_zone). |
| |
| #ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_ |
| #define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_ |
| |
| #include <chrono> |
| #include <cstdint> |
| #include <limits> |
| #include <ratio> // NOLINT: We use std::ratio in this header |
| #include <string> |
| #include <utility> |
| |
| #include "absl/base/config.h" |
| #include "absl/time/internal/cctz/include/cctz/civil_time.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace time_internal { |
| namespace cctz { |
| |
| // Convenience aliases. Not intended as public API points. |
| template <typename D> |
| using time_point = std::chrono::time_point<std::chrono::system_clock, D>; |
| using seconds = std::chrono::duration<std::int_fast64_t>; |
| using sys_seconds = seconds; // Deprecated. Use cctz::seconds instead. |
| |
| namespace detail { |
| template <typename D> |
| std::pair<time_point<seconds>, D> split_seconds(const time_point<D>& tp); |
| std::pair<time_point<seconds>, seconds> split_seconds( |
| const time_point<seconds>& tp); |
| } // namespace detail |
| |
| // cctz::time_zone is an opaque, small, value-type class representing a |
| // geo-political region within which particular rules are used for mapping |
| // between absolute and civil times. Time zones are named using the TZ |
| // identifiers from the IANA Time Zone Database, such as "America/Los_Angeles" |
| // or "Australia/Sydney". Time zones are created from factory functions such |
| // as load_time_zone(). Note: strings like "PST" and "EDT" are not valid TZ |
| // identifiers. |
| // |
| // Example: |
| // cctz::time_zone utc = cctz::utc_time_zone(); |
| // cctz::time_zone pst = cctz::fixed_time_zone(std::chrono::hours(-8)); |
| // cctz::time_zone loc = cctz::local_time_zone(); |
| // cctz::time_zone lax; |
| // if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... } |
| // |
| // See also: |
| // - http://www.iana.org/time-zones |
| // - https://en.wikipedia.org/wiki/Zoneinfo |
| class time_zone { |
| public: |
| time_zone() : time_zone(nullptr) {} // Equivalent to UTC |
| time_zone(const time_zone&) = default; |
| time_zone& operator=(const time_zone&) = default; |
| |
| std::string name() const; |
| |
| // An absolute_lookup represents the civil time (cctz::civil_second) within |
| // this time_zone at the given absolute time (time_point). There are |
| // additionally a few other fields that may be useful when working with |
| // older APIs, such as std::tm. |
| // |
| // Example: |
| // const cctz::time_zone tz = ... |
| // const auto tp = std::chrono::system_clock::now(); |
| // const cctz::time_zone::absolute_lookup al = tz.lookup(tp); |
| struct absolute_lookup { |
| civil_second cs; |
| // Note: The following fields exist for backward compatibility with older |
| // APIs. Accessing these fields directly is a sign of imprudent logic in |
| // the calling code. Modern time-related code should only access this data |
| // indirectly by way of cctz::format(). |
| int offset; // civil seconds east of UTC |
| bool is_dst; // is offset non-standard? |
| const char* abbr; // time-zone abbreviation (e.g., "PST") |
| }; |
| absolute_lookup lookup(const time_point<seconds>& tp) const; |
| template <typename D> |
| absolute_lookup lookup(const time_point<D>& tp) const { |
| return lookup(detail::split_seconds(tp).first); |
| } |
| |
| // A civil_lookup represents the absolute time(s) (time_point) that |
| // correspond to the given civil time (cctz::civil_second) within this |
| // time_zone. Usually the given civil time represents a unique instant |
| // in time, in which case the conversion is unambiguous. However, |
| // within this time zone, the given civil time may be skipped (e.g., |
| // during a positive UTC offset shift), or repeated (e.g., during a |
| // negative UTC offset shift). To account for these possibilities, |
| // civil_lookup is richer than just a single time_point. |
| // |
| // In all cases the civil_lookup::kind enum will indicate the nature |
| // of the given civil-time argument, and the pre, trans, and post |
| // members will give the absolute time answers using the pre-transition |
| // offset, the transition point itself, and the post-transition offset, |
| // respectively (all three times are equal if kind == UNIQUE). If any |
| // of these three absolute times is outside the representable range of a |
| // time_point<seconds> the field is set to its maximum/minimum value. |
| // |
| // Example: |
| // cctz::time_zone lax; |
| // if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... } |
| // |
| // // A unique civil time. |
| // auto jan01 = lax.lookup(cctz::civil_second(2011, 1, 1, 0, 0, 0)); |
| // // jan01.kind == cctz::time_zone::civil_lookup::UNIQUE |
| // // jan01.pre is 2011/01/01 00:00:00 -0800 |
| // // jan01.trans is 2011/01/01 00:00:00 -0800 |
| // // jan01.post is 2011/01/01 00:00:00 -0800 |
| // |
| // // A Spring DST transition, when there is a gap in civil time. |
| // auto mar13 = lax.lookup(cctz::civil_second(2011, 3, 13, 2, 15, 0)); |
| // // mar13.kind == cctz::time_zone::civil_lookup::SKIPPED |
| // // mar13.pre is 2011/03/13 03:15:00 -0700 |
| // // mar13.trans is 2011/03/13 03:00:00 -0700 |
| // // mar13.post is 2011/03/13 01:15:00 -0800 |
| // |
| // // A Fall DST transition, when civil times are repeated. |
| // auto nov06 = lax.lookup(cctz::civil_second(2011, 11, 6, 1, 15, 0)); |
| // // nov06.kind == cctz::time_zone::civil_lookup::REPEATED |
| // // nov06.pre is 2011/11/06 01:15:00 -0700 |
| // // nov06.trans is 2011/11/06 01:00:00 -0800 |
| // // nov06.post is 2011/11/06 01:15:00 -0800 |
| struct civil_lookup { |
| enum civil_kind { |
| UNIQUE, // the civil time was singular (pre == trans == post) |
| SKIPPED, // the civil time did not exist (pre >= trans > post) |
| REPEATED, // the civil time was ambiguous (pre < trans <= post) |
| } kind; |
| time_point<seconds> pre; // uses the pre-transition offset |
| time_point<seconds> trans; // instant of civil-offset change |
| time_point<seconds> post; // uses the post-transition offset |
| }; |
| civil_lookup lookup(const civil_second& cs) const; |
| |
| // Finds the time of the next/previous offset change in this time zone. |
| // |
| // By definition, next_transition(tp, &trans) returns false when tp has |
| // its maximum value, and prev_transition(tp, &trans) returns false |
| // when tp has its minimum value. If the zone has no transitions, the |
| // result will also be false no matter what the argument. |
| // |
| // Otherwise, when tp has its minimum value, next_transition(tp, &trans) |
| // returns true and sets trans to the first recorded transition. Chains |
| // of calls to next_transition()/prev_transition() will eventually return |
| // false, but it is unspecified exactly when next_transition(tp, &trans) |
| // jumps to false, or what time is set by prev_transition(tp, &trans) for |
| // a very distant tp. |
| // |
| // Note: Enumeration of time-zone transitions is for informational purposes |
| // only. Modern time-related code should not care about when offset changes |
| // occur. |
| // |
| // Example: |
| // cctz::time_zone nyc; |
| // if (!cctz::load_time_zone("America/New_York", &nyc)) { ... } |
| // const auto now = std::chrono::system_clock::now(); |
| // auto tp = cctz::time_point<cctz::seconds>::min(); |
| // cctz::time_zone::civil_transition trans; |
| // while (tp <= now && nyc.next_transition(tp, &trans)) { |
| // // transition: trans.from -> trans.to |
| // tp = nyc.lookup(trans.to).trans; |
| // } |
| struct civil_transition { |
| civil_second from; // the civil time we jump from |
| civil_second to; // the civil time we jump to |
| }; |
| bool next_transition(const time_point<seconds>& tp, |
| civil_transition* trans) const; |
| template <typename D> |
| bool next_transition(const time_point<D>& tp, civil_transition* trans) const { |
| return next_transition(detail::split_seconds(tp).first, trans); |
| } |
| bool prev_transition(const time_point<seconds>& tp, |
| civil_transition* trans) const; |
| template <typename D> |
| bool prev_transition(const time_point<D>& tp, civil_transition* trans) const { |
| return prev_transition(detail::split_seconds(tp).first, trans); |
| } |
| |
| // version() and description() provide additional information about the |
| // time zone. The content of each of the returned strings is unspecified, |
| // however, when the IANA Time Zone Database is the underlying data source |
| // the version() string will be in the familiar form (e.g, "2018e") or |
| // empty when unavailable. |
| // |
| // Note: These functions are for informational or testing purposes only. |
| std::string version() const; // empty when unknown |
| std::string description() const; |
| |
| // Relational operators. |
| friend bool operator==(time_zone lhs, time_zone rhs) { |
| return &lhs.effective_impl() == &rhs.effective_impl(); |
| } |
| friend bool operator!=(time_zone lhs, time_zone rhs) { return !(lhs == rhs); } |
| |
| template <typename H> |
| friend H AbslHashValue(H h, time_zone tz) { |
| return H::combine(std::move(h), &tz.effective_impl()); |
| } |
| |
| class Impl; |
| |
| private: |
| explicit time_zone(const Impl* impl) : impl_(impl) {} |
| const Impl& effective_impl() const; // handles implicit UTC |
| const Impl* impl_; |
| }; |
| |
| // Loads the named time zone. May perform I/O on the initial load. |
| // If the name is invalid, or some other kind of error occurs, returns |
| // false and "*tz" is set to the UTC time zone. |
| bool load_time_zone(const std::string& name, time_zone* tz); |
| |
| // Returns a time_zone representing UTC. Cannot fail. |
| time_zone utc_time_zone(); |
| |
| // Returns a time zone that is a fixed offset (seconds east) from UTC. |
| // Note: If the absolute value of the offset is greater than 24 hours |
| // you'll get UTC (i.e., zero offset) instead. |
| time_zone fixed_time_zone(const seconds& offset); |
| |
| // Returns a time zone representing the local time zone. Falls back to UTC. |
| // Note: local_time_zone.name() may only be something like "localtime". |
| time_zone local_time_zone(); |
| |
| // Returns the civil time (cctz::civil_second) within the given time zone at |
| // the given absolute time (time_point). Since the additional fields provided |
| // by the time_zone::absolute_lookup struct should rarely be needed in modern |
| // code, this convert() function is simpler and should be preferred. |
| template <typename D> |
| inline civil_second convert(const time_point<D>& tp, const time_zone& tz) { |
| return tz.lookup(tp).cs; |
| } |
| |
| // Returns the absolute time (time_point) that corresponds to the given civil |
| // time within the given time zone. If the civil time is not unique (i.e., if |
| // it was either repeated or non-existent), then the returned time_point is |
| // the best estimate that preserves relative order. That is, this function |
| // guarantees that if cs1 < cs2, then convert(cs1, tz) <= convert(cs2, tz). |
| inline time_point<seconds> convert(const civil_second& cs, |
| const time_zone& tz) { |
| const time_zone::civil_lookup cl = tz.lookup(cs); |
| if (cl.kind == time_zone::civil_lookup::SKIPPED) return cl.trans; |
| return cl.pre; |
| } |
| |
| namespace detail { |
| using femtoseconds = std::chrono::duration<std::int_fast64_t, std::femto>; |
| std::string format(const std::string&, const time_point<seconds>&, |
| const femtoseconds&, const time_zone&); |
| bool parse(const std::string&, const std::string&, const time_zone&, |
| time_point<seconds>*, femtoseconds*, std::string* err = nullptr); |
| template <typename Rep, std::intmax_t Denom> |
| bool join_seconds( |
| const time_point<seconds>& sec, const femtoseconds& fs, |
| time_point<std::chrono::duration<Rep, std::ratio<1, Denom>>>* tpp); |
| template <typename Rep, std::intmax_t Num> |
| bool join_seconds( |
| const time_point<seconds>& sec, const femtoseconds& fs, |
| time_point<std::chrono::duration<Rep, std::ratio<Num, 1>>>* tpp); |
| template <typename Rep> |
| bool join_seconds( |
| const time_point<seconds>& sec, const femtoseconds& fs, |
| time_point<std::chrono::duration<Rep, std::ratio<1, 1>>>* tpp); |
| bool join_seconds(const time_point<seconds>& sec, const femtoseconds&, |
| time_point<seconds>* tpp); |
| } // namespace detail |
| |
| // Formats the given time_point in the given cctz::time_zone according to |
| // the provided format string. Uses strftime()-like formatting options, |
| // with the following extensions: |
| // |
| // - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm) |
| // - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss) |
| // - %E#S - Seconds with # digits of fractional precision |
| // - %E*S - Seconds with full fractional precision (a literal '*') |
| // - %E#f - Fractional seconds with # digits of precision |
| // - %E*f - Fractional seconds with full precision (a literal '*') |
| // - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) |
| // - %ET - The RFC3339 "date-time" separator "T" |
| // |
| // Note that %E0S behaves like %S, and %E0f produces no characters. In |
| // contrast %E*f always produces at least one digit, which may be '0'. |
| // |
| // Note that %Y produces as many characters as it takes to fully render the |
| // year. A year outside of [-999:9999] when formatted with %E4Y will produce |
| // more than four characters, just like %Y. |
| // |
| // Tip: Format strings should include the UTC offset (e.g., %z, %Ez, or %E*z) |
| // so that the resulting string uniquely identifies an absolute time. |
| // |
| // Example: |
| // cctz::time_zone lax; |
| // if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... } |
| // auto tp = cctz::convert(cctz::civil_second(2013, 1, 2, 3, 4, 5), lax); |
| // std::string f = cctz::format("%H:%M:%S", tp, lax); // "03:04:05" |
| // f = cctz::format("%H:%M:%E3S", tp, lax); // "03:04:05.000" |
| template <typename D> |
| inline std::string format(const std::string& fmt, const time_point<D>& tp, |
| const time_zone& tz) { |
| const auto p = detail::split_seconds(tp); |
| const auto n = std::chrono::duration_cast<detail::femtoseconds>(p.second); |
| return detail::format(fmt, p.first, n, tz); |
| } |
| |
| // Parses an input string according to the provided format string and |
| // returns the corresponding time_point. Uses strftime()-like formatting |
| // options, with the same extensions as cctz::format(), but with the |
| // exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez |
| // and %E*z also accept the same inputs, which (along with %z) includes |
| // 'z' and 'Z' as synonyms for +00:00. %ET accepts either 'T' or 't'. |
| // |
| // %Y consumes as many numeric characters as it can, so the matching data |
| // should always be terminated with a non-numeric. %E4Y always consumes |
| // exactly four characters, including any sign. |
| // |
| // Unspecified fields are taken from the default date and time of ... |
| // |
| // "1970-01-01 00:00:00.0 +0000" |
| // |
| // For example, parsing a string of "15:45" (%H:%M) will return a time_point |
| // that represents "1970-01-01 15:45:00.0 +0000". |
| // |
| // Note that parse() returns time instants, so it makes most sense to parse |
| // fully-specified date/time strings that include a UTC offset (%z, %Ez, or |
| // %E*z). |
| // |
| // Note also that parse() only heeds the fields year, month, day, hour, |
| // minute, (fractional) second, and UTC offset. Other fields, like weekday (%a |
| // or %A), while parsed for syntactic validity, are ignored in the conversion. |
| // |
| // Date and time fields that are out-of-range will be treated as errors rather |
| // than normalizing them like cctz::civil_second() would do. For example, it |
| // is an error to parse the date "Oct 32, 2013" because 32 is out of range. |
| // |
| // A second of ":60" is normalized to ":00" of the following minute with |
| // fractional seconds discarded. The following table shows how the given |
| // seconds and subseconds will be parsed: |
| // |
| // "59.x" -> 59.x // exact |
| // "60.x" -> 00.0 // normalized |
| // "00.x" -> 00.x // exact |
| // |
| // Errors are indicated by returning false. |
| // |
| // Example: |
| // const cctz::time_zone tz = ... |
| // std::chrono::system_clock::time_point tp; |
| // if (cctz::parse("%Y-%m-%d", "2015-10-09", tz, &tp)) { |
| // ... |
| // } |
| template <typename D> |
| inline bool parse(const std::string& fmt, const std::string& input, |
| const time_zone& tz, time_point<D>* tpp) { |
| time_point<seconds> sec; |
| detail::femtoseconds fs; |
| return detail::parse(fmt, input, tz, &sec, &fs) && |
| detail::join_seconds(sec, fs, tpp); |
| } |
| |
| namespace detail { |
| |
| // Split a time_point<D> into a time_point<seconds> and a D subseconds. |
| // Undefined behavior if time_point<seconds> is not of sufficient range. |
| // Note that this means it is UB to call cctz::time_zone::lookup(tp) or |
| // cctz::format(fmt, tp, tz) with a time_point that is outside the range |
| // of a 64-bit std::time_t. |
| template <typename D> |
| std::pair<time_point<seconds>, D> split_seconds(const time_point<D>& tp) { |
| auto sec = std::chrono::time_point_cast<seconds>(tp); |
| auto sub = tp - sec; |
| if (sub.count() < 0) { |
| sec -= seconds(1); |
| sub += seconds(1); |
| } |
| return {sec, std::chrono::duration_cast<D>(sub)}; |
| } |
| |
| inline std::pair<time_point<seconds>, seconds> split_seconds( |
| const time_point<seconds>& tp) { |
| return {tp, seconds::zero()}; |
| } |
| |
| // Join a time_point<seconds> and femto subseconds into a time_point<D>. |
| // Floors to the resolution of time_point<D>. Returns false if time_point<D> |
| // is not of sufficient range. |
| template <typename Rep, std::intmax_t Denom> |
| bool join_seconds( |
| const time_point<seconds>& sec, const femtoseconds& fs, |
| time_point<std::chrono::duration<Rep, std::ratio<1, Denom>>>* tpp) { |
| using D = std::chrono::duration<Rep, std::ratio<1, Denom>>; |
| // TODO(#199): Return false if result unrepresentable as a time_point<D>. |
| *tpp = std::chrono::time_point_cast<D>(sec); |
| *tpp += std::chrono::duration_cast<D>(fs); |
| return true; |
| } |
| |
| template <typename Rep, std::intmax_t Num> |
| bool join_seconds( |
| const time_point<seconds>& sec, const femtoseconds&, |
| time_point<std::chrono::duration<Rep, std::ratio<Num, 1>>>* tpp) { |
| using D = std::chrono::duration<Rep, std::ratio<Num, 1>>; |
| auto count = sec.time_since_epoch().count(); |
| if (count >= 0 || count % Num == 0) { |
| count /= Num; |
| } else { |
| count /= Num; |
| count -= 1; |
| } |
| if (count > (std::numeric_limits<Rep>::max)()) return false; |
| if (count < (std::numeric_limits<Rep>::min)()) return false; |
| *tpp = time_point<D>() + D{static_cast<Rep>(count)}; |
| return true; |
| } |
| |
| template <typename Rep> |
| bool join_seconds( |
| const time_point<seconds>& sec, const femtoseconds&, |
| time_point<std::chrono::duration<Rep, std::ratio<1, 1>>>* tpp) { |
| using D = std::chrono::duration<Rep, std::ratio<1, 1>>; |
| auto count = sec.time_since_epoch().count(); |
| if (count > (std::numeric_limits<Rep>::max)()) return false; |
| if (count < (std::numeric_limits<Rep>::min)()) return false; |
| *tpp = time_point<D>() + D{static_cast<Rep>(count)}; |
| return true; |
| } |
| |
| inline bool join_seconds(const time_point<seconds>& sec, const femtoseconds&, |
| time_point<seconds>* tpp) { |
| *tpp = sec; |
| return true; |
| } |
| |
| } // namespace detail |
| } // namespace cctz |
| } // namespace time_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_ |
| *´" |
| tsoong/.intermediates/external/abseil-cpp/absl_log_absl_vlog_is_on_hdrs/gen/my_include_dir/absl/log/absl_vlog_is_on.h»!// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/absl_vlog_is_on.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header defines the `ABSL_VLOG_IS_ON()` macro that controls the |
| // variable-verbosity conditional logging. |
| // |
| // It's used by `VLOG` in log.h, or it can also be used directly like this: |
| // |
| // if (ABSL_VLOG_IS_ON(2)) { |
| // foo_server.RecomputeStatisticsExpensive(); |
| // LOG(INFO) << foo_server.LastStatisticsAsString(); |
| // } |
| // |
| // Each source file has an effective verbosity level that's a non-negative |
| // integer computed from the `--vmodule` and `--v` flags. |
| // `ABSL_VLOG_IS_ON(n)` is true, and `VLOG(n)` logs, if that effective verbosity |
| // level is greater than or equal to `n`. |
| // |
| // `--vmodule` takes a comma-delimited list of key=value pairs. Each key is a |
| // pattern matched against filenames, and the values give the effective severity |
| // level applied to matching files. '?' and '*' characters in patterns are |
| // interpreted as single-character and zero-or-more-character wildcards. |
| // Patterns including a slash character are matched against full pathnames, |
| // while those without are matched against basenames only. One suffix (i.e. the |
| // last . and everything after it) is stripped from each filename prior to |
| // matching, as is the special suffix "-inl". |
| // |
| // Example: --vmodule=module_a=1,module_b=2 |
| // |
| // Files are matched against globs in `--vmodule` in order, and the first match |
| // determines the verbosity level. |
| // |
| // Files which do not match any pattern in `--vmodule` use the value of `--v` as |
| // their effective verbosity level. The default is 0. |
| // |
| // SetVLogLevel helper function is provided to do limited dynamic control over |
| // V-logging by appending to `--vmodule`. Because these go at the beginning of |
| // the list, they take priority over any globs previously added. |
| // |
| // Resetting --vmodule will override all previous modifications to `--vmodule`, |
| // including via SetVLogLevel. |
| |
| #ifndef ABSL_LOG_ABSL_VLOG_IS_ON_H_ |
| #define ABSL_LOG_ABSL_VLOG_IS_ON_H_ |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/log/internal/vlog_config.h" // IWYU pragma: export |
| #include "absl/strings/string_view.h" |
| |
| // IWYU pragma: private, include "absl/log/log.h" |
| |
| // This is expanded at the callsite to allow the compiler to optimize |
| // always-false cases out of the build. |
| // An ABSL_MAX_VLOG_VERBOSITY of 2 means that VLOG(3) and above should never |
| // log. |
| #ifdef ABSL_MAX_VLOG_VERBOSITY |
| #define ABSL_LOG_INTERNAL_MAX_LOG_VERBOSITY_CHECK(x) \ |
| ((x) <= ABSL_MAX_VLOG_VERBOSITY)&& |
| #else |
| #define ABSL_LOG_INTERNAL_MAX_LOG_VERBOSITY_CHECK(x) |
| #endif |
| |
| // Each ABSL_VLOG_IS_ON call site gets its own VLogSite that registers with the |
| // global linked list of sites to asynchronously update its verbosity level on |
| // changes to --v or --vmodule. The verbosity can also be set by manually |
| // calling SetVLogLevel. |
| // |
| // ABSL_VLOG_IS_ON is not async signal safe, but it is guaranteed not to |
| // allocate new memory. |
| #define ABSL_VLOG_IS_ON(verbose_level) \ |
| (ABSL_LOG_INTERNAL_MAX_LOG_VERBOSITY_CHECK(verbose_level)[]() \ |
| ->::absl::log_internal::VLogSite * \ |
| { \ |
| ABSL_CONST_INIT static ::absl::log_internal::VLogSite site(__FILE__); \ |
| return &site; \ |
| }() \ |
| ->IsEnabled(verbose_level)) |
| |
| #endif // ABSL_LOG_ABSL_VLOG_IS_ON_H_ |
| *·² |
| asoong/.intermediates/external/abseil-cpp/absl_time_hdrs/gen/my_include_dir/absl/time/civil_time.hб// Copyright 2018 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: civil_time.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines abstractions for computing with "civil time". |
| // The term "civil time" refers to the legally recognized human-scale time |
| // that is represented by the six fields `YYYY-MM-DD hh:mm:ss`. A "date" |
| // is perhaps the most common example of a civil time (represented here as |
| // an `absl::CivilDay`). |
| // |
| // Modern-day civil time follows the Gregorian Calendar and is a |
| // time-zone-independent concept: a civil time of "2015-06-01 12:00:00", for |
| // example, is not tied to a time zone. Put another way, a civil time does not |
| // map to a unique point in time; a civil time must be mapped to an absolute |
| // time *through* a time zone. |
| // |
| // Because a civil time is what most people think of as "time," it is common to |
| // map absolute times to civil times to present to users. |
| // |
| // Time zones define the relationship between absolute and civil times. Given an |
| // absolute or civil time and a time zone, you can compute the other time: |
| // |
| // Civil Time = F(Absolute Time, Time Zone) |
| // Absolute Time = G(Civil Time, Time Zone) |
| // |
| // The Abseil time library allows you to construct such civil times from |
| // absolute times; consult time.h for such functionality. |
| // |
| // This library provides six classes for constructing civil-time objects, and |
| // provides several helper functions for rounding, iterating, and performing |
| // arithmetic on civil-time objects, while avoiding complications like |
| // daylight-saving time (DST): |
| // |
| // * `absl::CivilSecond` |
| // * `absl::CivilMinute` |
| // * `absl::CivilHour` |
| // * `absl::CivilDay` |
| // * `absl::CivilMonth` |
| // * `absl::CivilYear` |
| // |
| // Example: |
| // |
| // // Construct a civil-time object for a specific day |
| // const absl::CivilDay cd(1969, 7, 20); |
| // |
| // // Construct a civil-time object for a specific second |
| // const absl::CivilSecond cd(2018, 8, 1, 12, 0, 1); |
| // |
| // Note: In C++14 and later, this library is usable in a constexpr context. |
| // |
| // Example: |
| // |
| // // Valid in C++14 |
| // constexpr absl::CivilDay cd(1969, 7, 20); |
| |
| #ifndef ABSL_TIME_CIVIL_TIME_H_ |
| #define ABSL_TIME_CIVIL_TIME_H_ |
| |
| #include <iosfwd> |
| #include <string> |
| |
| #include "absl/base/config.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/time/internal/cctz/include/cctz/civil_time.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| namespace time_internal { |
| struct second_tag : cctz::detail::second_tag {}; |
| struct minute_tag : second_tag, cctz::detail::minute_tag {}; |
| struct hour_tag : minute_tag, cctz::detail::hour_tag {}; |
| struct day_tag : hour_tag, cctz::detail::day_tag {}; |
| struct month_tag : day_tag, cctz::detail::month_tag {}; |
| struct year_tag : month_tag, cctz::detail::year_tag {}; |
| } // namespace time_internal |
| |
| // ----------------------------------------------------------------------------- |
| // CivilSecond, CivilMinute, CivilHour, CivilDay, CivilMonth, CivilYear |
| // ----------------------------------------------------------------------------- |
| // |
| // Each of these civil-time types is a simple value type with the same |
| // interface for construction and the same six accessors for each of the civil |
| // time fields (year, month, day, hour, minute, and second, aka YMDHMS). These |
| // classes differ only in their alignment, which is indicated by the type name |
| // and specifies the field on which arithmetic operates. |
| // |
| // CONSTRUCTION |
| // |
| // Each of the civil-time types can be constructed in two ways: by directly |
| // passing to the constructor up to six integers representing the YMDHMS fields, |
| // or by copying the YMDHMS fields from a differently aligned civil-time type. |
| // Omitted fields are assigned their minimum valid value. Hours, minutes, and |
| // seconds will be set to 0, month and day will be set to 1. Since there is no |
| // minimum year, the default is 1970. |
| // |
| // Examples: |
| // |
| // absl::CivilDay default_value; // 1970-01-01 00:00:00 |
| // |
| // absl::CivilDay a(2015, 2, 3); // 2015-02-03 00:00:00 |
| // absl::CivilDay b(2015, 2, 3, 4, 5, 6); // 2015-02-03 00:00:00 |
| // absl::CivilDay c(2015); // 2015-01-01 00:00:00 |
| // |
| // absl::CivilSecond ss(2015, 2, 3, 4, 5, 6); // 2015-02-03 04:05:06 |
| // absl::CivilMinute mm(ss); // 2015-02-03 04:05:00 |
| // absl::CivilHour hh(mm); // 2015-02-03 04:00:00 |
| // absl::CivilDay d(hh); // 2015-02-03 00:00:00 |
| // absl::CivilMonth m(d); // 2015-02-01 00:00:00 |
| // absl::CivilYear y(m); // 2015-01-01 00:00:00 |
| // |
| // m = absl::CivilMonth(y); // 2015-01-01 00:00:00 |
| // d = absl::CivilDay(m); // 2015-01-01 00:00:00 |
| // hh = absl::CivilHour(d); // 2015-01-01 00:00:00 |
| // mm = absl::CivilMinute(hh); // 2015-01-01 00:00:00 |
| // ss = absl::CivilSecond(mm); // 2015-01-01 00:00:00 |
| // |
| // Each civil-time class is aligned to the civil-time field indicated in the |
| // class's name after normalization. Alignment is performed by setting all the |
| // inferior fields to their minimum valid value (as described above). The |
| // following are examples of how each of the six types would align the fields |
| // representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the |
| // string format used here is not important; it's just a shorthand way of |
| // showing the six YMDHMS fields.) |
| // |
| // absl::CivilSecond : 2015-11-22 12:34:56 |
| // absl::CivilMinute : 2015-11-22 12:34:00 |
| // absl::CivilHour : 2015-11-22 12:00:00 |
| // absl::CivilDay : 2015-11-22 00:00:00 |
| // absl::CivilMonth : 2015-11-01 00:00:00 |
| // absl::CivilYear : 2015-01-01 00:00:00 |
| // |
| // Each civil-time type performs arithmetic on the field to which it is |
| // aligned. This means that adding 1 to an absl::CivilDay increments the day |
| // field (normalizing as necessary), and subtracting 7 from an absl::CivilMonth |
| // operates on the month field (normalizing as necessary). All arithmetic |
| // produces a valid civil time. Difference requires two similarly aligned |
| // civil-time objects and returns the scalar answer in units of the objects' |
| // alignment. For example, the difference between two absl::CivilHour objects |
| // will give an answer in units of civil hours. |
| // |
| // ALIGNMENT CONVERSION |
| // |
| // The alignment of a civil-time object cannot change, but the object may be |
| // used to construct a new object with a different alignment. This is referred |
| // to as "realigning". When realigning to a type with the same or more |
| // precision (e.g., absl::CivilDay -> absl::CivilSecond), the conversion may be |
| // performed implicitly since no information is lost. However, if information |
| // could be discarded (e.g., CivilSecond -> CivilDay), the conversion must |
| // be explicit at the call site. |
| // |
| // Examples: |
| // |
| // void UseDay(absl::CivilDay day); |
| // |
| // absl::CivilSecond cs; |
| // UseDay(cs); // Won't compile because data may be discarded |
| // UseDay(absl::CivilDay(cs)); // OK: explicit conversion |
| // |
| // absl::CivilDay cd; |
| // UseDay(cd); // OK: no conversion needed |
| // |
| // absl::CivilMonth cm; |
| // UseDay(cm); // OK: implicit conversion to absl::CivilDay |
| // |
| // NORMALIZATION |
| // |
| // Normalization takes invalid values and adjusts them to produce valid values. |
| // Within the civil-time library, integer arguments passed to the Civil* |
| // constructors may be out-of-range, in which case they are normalized by |
| // carrying overflow into a field of courser granularity to produce valid |
| // civil-time objects. This normalization enables natural arithmetic on |
| // constructor arguments without worrying about the field's range. |
| // |
| // Examples: |
| // |
| // // Out-of-range; normalized to 2016-11-01 |
| // absl::CivilDay d(2016, 10, 32); |
| // // Out-of-range, negative: normalized to 2016-10-30T23 |
| // absl::CivilHour h1(2016, 10, 31, -1); |
| // // Normalization is cumulative: normalized to 2016-10-30T23 |
| // absl::CivilHour h2(2016, 10, 32, -25); |
| // |
| // Note: If normalization is undesired, you can signal an error by comparing |
| // the constructor arguments to the normalized values returned by the YMDHMS |
| // properties. |
| // |
| // COMPARISON |
| // |
| // Comparison between civil-time objects considers all six YMDHMS fields, |
| // regardless of the type's alignment. Comparison between differently aligned |
| // civil-time types is allowed. |
| // |
| // Examples: |
| // |
| // absl::CivilDay feb_3(2015, 2, 3); // 2015-02-03 00:00:00 |
| // absl::CivilDay mar_4(2015, 3, 4); // 2015-03-04 00:00:00 |
| // // feb_3 < mar_4 |
| // // absl::CivilYear(feb_3) == absl::CivilYear(mar_4) |
| // |
| // absl::CivilSecond feb_3_noon(2015, 2, 3, 12, 0, 0); // 2015-02-03 12:00:00 |
| // // feb_3 < feb_3_noon |
| // // feb_3 == absl::CivilDay(feb_3_noon) |
| // |
| // // Iterates all the days of February 2015. |
| // for (absl::CivilDay d(2015, 2, 1); d < absl::CivilMonth(2015, 3); ++d) { |
| // // ... |
| // } |
| // |
| // ARITHMETIC |
| // |
| // Civil-time types support natural arithmetic operators such as addition, |
| // subtraction, and difference. Arithmetic operates on the civil-time field |
| // indicated in the type's name. Difference operators require arguments with |
| // the same alignment and return the answer in units of the alignment. |
| // |
| // Example: |
| // |
| // absl::CivilDay a(2015, 2, 3); |
| // ++a; // 2015-02-04 00:00:00 |
| // --a; // 2015-02-03 00:00:00 |
| // absl::CivilDay b = a + 1; // 2015-02-04 00:00:00 |
| // absl::CivilDay c = 1 + b; // 2015-02-05 00:00:00 |
| // int n = c - a; // n = 2 (civil days) |
| // int m = c - absl::CivilMonth(c); // Won't compile: different types. |
| // |
| // ACCESSORS |
| // |
| // Each civil-time type has accessors for all six of the civil-time fields: |
| // year, month, day, hour, minute, and second. |
| // |
| // civil_year_t year() |
| // int month() |
| // int day() |
| // int hour() |
| // int minute() |
| // int second() |
| // |
| // Recall that fields inferior to the type's alignment will be set to their |
| // minimum valid value. |
| // |
| // Example: |
| // |
| // absl::CivilDay d(2015, 6, 28); |
| // // d.year() == 2015 |
| // // d.month() == 6 |
| // // d.day() == 28 |
| // // d.hour() == 0 |
| // // d.minute() == 0 |
| // // d.second() == 0 |
| // |
| // CASE STUDY: Adding a month to January 31. |
| // |
| // One of the classic questions that arises when considering a civil time |
| // library (or a date library or a date/time library) is this: |
| // "What is the result of adding a month to January 31?" |
| // This is an interesting question because it is unclear what is meant by a |
| // "month", and several different answers are possible, depending on context: |
| // |
| // 1. March 3 (or 2 if a leap year), if "add a month" means to add a month to |
| // the current month, and adjust the date to overflow the extra days into |
| // March. In this case the result of "February 31" would be normalized as |
| // within the civil-time library. |
| // 2. February 28 (or 29 if a leap year), if "add a month" means to add a |
| // month, and adjust the date while holding the resulting month constant. |
| // In this case, the result of "February 31" would be truncated to the last |
| // day in February. |
| // 3. An error. The caller may get some error, an exception, an invalid date |
| // object, or perhaps return `false`. This may make sense because there is |
| // no single unambiguously correct answer to the question. |
| // |
| // Practically speaking, any answer that is not what the programmer intended |
| // is the wrong answer. |
| // |
| // The Abseil time library avoids this problem by making it impossible to |
| // ask ambiguous questions. All civil-time objects are aligned to a particular |
| // civil-field boundary (such as aligned to a year, month, day, hour, minute, |
| // or second), and arithmetic operates on the field to which the object is |
| // aligned. This means that in order to "add a month" the object must first be |
| // aligned to a month boundary, which is equivalent to the first day of that |
| // month. |
| // |
| // Of course, there are ways to compute an answer the question at hand using |
| // this Abseil time library, but they require the programmer to be explicit |
| // about the answer they expect. To illustrate, let's see how to compute all |
| // three of the above possible answers to the question of "Jan 31 plus 1 |
| // month": |
| // |
| // Example: |
| // |
| // const absl::CivilDay d(2015, 1, 31); |
| // |
| // // Answer 1: |
| // // Add 1 to the month field in the constructor, and rely on normalization. |
| // const auto normalized = absl::CivilDay(d.year(), d.month() + 1, d.day()); |
| // // normalized == 2015-03-03 (aka Feb 31) |
| // |
| // // Answer 2: |
| // // Add 1 to month field, capping to the end of next month. |
| // const auto next_month = absl::CivilMonth(d) + 1; |
| // const auto last_day_of_next_month = absl::CivilDay(next_month + 1) - 1; |
| // const auto capped = std::min(normalized, last_day_of_next_month); |
| // // capped == 2015-02-28 |
| // |
| // // Answer 3: |
| // // Signal an error if the normalized answer is not in next month. |
| // if (absl::CivilMonth(normalized) != next_month) { |
| // // error, month overflow |
| // } |
| // |
| using CivilSecond = |
| time_internal::cctz::detail::civil_time<time_internal::second_tag>; |
| using CivilMinute = |
| time_internal::cctz::detail::civil_time<time_internal::minute_tag>; |
| using CivilHour = |
| time_internal::cctz::detail::civil_time<time_internal::hour_tag>; |
| using CivilDay = |
| time_internal::cctz::detail::civil_time<time_internal::day_tag>; |
| using CivilMonth = |
| time_internal::cctz::detail::civil_time<time_internal::month_tag>; |
| using CivilYear = |
| time_internal::cctz::detail::civil_time<time_internal::year_tag>; |
| |
| // civil_year_t |
| // |
| // Type alias of a civil-time year value. This type is guaranteed to (at least) |
| // support any year value supported by `time_t`. |
| // |
| // Example: |
| // |
| // absl::CivilSecond cs = ...; |
| // absl::civil_year_t y = cs.year(); |
| // cs = absl::CivilSecond(y, 1, 1, 0, 0, 0); // CivilSecond(CivilYear(cs)) |
| // |
| using civil_year_t = time_internal::cctz::year_t; |
| |
| // civil_diff_t |
| // |
| // Type alias of the difference between two civil-time values. |
| // This type is used to indicate arguments that are not |
| // normalized (such as parameters to the civil-time constructors), the results |
| // of civil-time subtraction, or the operand to civil-time addition. |
| // |
| // Example: |
| // |
| // absl::civil_diff_t n_sec = cs1 - cs2; // cs1 == cs2 + n_sec; |
| // |
| using civil_diff_t = time_internal::cctz::diff_t; |
| |
| // Weekday::monday, Weekday::tuesday, Weekday::wednesday, Weekday::thursday, |
| // Weekday::friday, Weekday::saturday, Weekday::sunday |
| // |
| // The Weekday enum class represents the civil-time concept of a "weekday" with |
| // members for all days of the week. |
| // |
| // absl::Weekday wd = absl::Weekday::thursday; |
| // |
| using Weekday = time_internal::cctz::weekday; |
| |
| // GetWeekday() |
| // |
| // Returns the absl::Weekday for the given (realigned) civil-time value. |
| // |
| // Example: |
| // |
| // absl::CivilDay a(2015, 8, 13); |
| // absl::Weekday wd = absl::GetWeekday(a); // wd == absl::Weekday::thursday |
| // |
| inline Weekday GetWeekday(CivilSecond cs) { |
| return time_internal::cctz::get_weekday(cs); |
| } |
| |
| // NextWeekday() |
| // PrevWeekday() |
| // |
| // Returns the absl::CivilDay that strictly follows or precedes a given |
| // absl::CivilDay, and that falls on the given absl::Weekday. |
| // |
| // Example, given the following month: |
| // |
| // August 2015 |
| // Su Mo Tu We Th Fr Sa |
| // 1 |
| // 2 3 4 5 6 7 8 |
| // 9 10 11 12 13 14 15 |
| // 16 17 18 19 20 21 22 |
| // 23 24 25 26 27 28 29 |
| // 30 31 |
| // |
| // absl::CivilDay a(2015, 8, 13); |
| // // absl::GetWeekday(a) == absl::Weekday::thursday |
| // absl::CivilDay b = absl::NextWeekday(a, absl::Weekday::thursday); |
| // // b = 2015-08-20 |
| // absl::CivilDay c = absl::PrevWeekday(a, absl::Weekday::thursday); |
| // // c = 2015-08-06 |
| // |
| // absl::CivilDay d = ... |
| // // Gets the following Thursday if d is not already Thursday |
| // absl::CivilDay thurs1 = absl::NextWeekday(d - 1, absl::Weekday::thursday); |
| // // Gets the previous Thursday if d is not already Thursday |
| // absl::CivilDay thurs2 = absl::PrevWeekday(d + 1, absl::Weekday::thursday); |
| // |
| inline CivilDay NextWeekday(CivilDay cd, Weekday wd) { |
| return CivilDay(time_internal::cctz::next_weekday(cd, wd)); |
| } |
| inline CivilDay PrevWeekday(CivilDay cd, Weekday wd) { |
| return CivilDay(time_internal::cctz::prev_weekday(cd, wd)); |
| } |
| |
| // GetYearDay() |
| // |
| // Returns the day-of-year for the given (realigned) civil-time value. |
| // |
| // Example: |
| // |
| // absl::CivilDay a(2015, 1, 1); |
| // int yd_jan_1 = absl::GetYearDay(a); // yd_jan_1 = 1 |
| // absl::CivilDay b(2015, 12, 31); |
| // int yd_dec_31 = absl::GetYearDay(b); // yd_dec_31 = 365 |
| // |
| inline int GetYearDay(CivilSecond cs) { |
| return time_internal::cctz::get_yearday(cs); |
| } |
| |
| // FormatCivilTime() |
| // |
| // Formats the given civil-time value into a string value of the following |
| // format: |
| // |
| // Type | Format |
| // --------------------------------- |
| // CivilSecond | YYYY-MM-DDTHH:MM:SS |
| // CivilMinute | YYYY-MM-DDTHH:MM |
| // CivilHour | YYYY-MM-DDTHH |
| // CivilDay | YYYY-MM-DD |
| // CivilMonth | YYYY-MM |
| // CivilYear | YYYY |
| // |
| // Example: |
| // |
| // absl::CivilDay d = absl::CivilDay(1969, 7, 20); |
| // std::string day_string = absl::FormatCivilTime(d); // "1969-07-20" |
| // |
| std::string FormatCivilTime(CivilSecond c); |
| std::string FormatCivilTime(CivilMinute c); |
| std::string FormatCivilTime(CivilHour c); |
| std::string FormatCivilTime(CivilDay c); |
| std::string FormatCivilTime(CivilMonth c); |
| std::string FormatCivilTime(CivilYear c); |
| |
| // Support for StrFormat(), StrCat(), etc |
| template <typename Sink> |
| void AbslStringify(Sink& sink, CivilSecond c) { |
| sink.Append(FormatCivilTime(c)); |
| } |
| template <typename Sink> |
| void AbslStringify(Sink& sink, CivilMinute c) { |
| sink.Append(FormatCivilTime(c)); |
| } |
| template <typename Sink> |
| void AbslStringify(Sink& sink, CivilHour c) { |
| sink.Append(FormatCivilTime(c)); |
| } |
| template <typename Sink> |
| void AbslStringify(Sink& sink, CivilDay c) { |
| sink.Append(FormatCivilTime(c)); |
| } |
| template <typename Sink> |
| void AbslStringify(Sink& sink, CivilMonth c) { |
| sink.Append(FormatCivilTime(c)); |
| } |
| template <typename Sink> |
| void AbslStringify(Sink& sink, CivilYear c) { |
| sink.Append(FormatCivilTime(c)); |
| } |
| |
| // absl::ParseCivilTime() |
| // |
| // Parses a civil-time value from the specified `absl::string_view` into the |
| // passed output parameter. Returns `true` upon successful parsing. |
| // |
| // The expected form of the input string is as follows: |
| // |
| // Type | Format |
| // --------------------------------- |
| // CivilSecond | YYYY-MM-DDTHH:MM:SS |
| // CivilMinute | YYYY-MM-DDTHH:MM |
| // CivilHour | YYYY-MM-DDTHH |
| // CivilDay | YYYY-MM-DD |
| // CivilMonth | YYYY-MM |
| // CivilYear | YYYY |
| // |
| // Example: |
| // |
| // absl::CivilDay d; |
| // bool ok = absl::ParseCivilTime("2018-01-02", &d); // OK |
| // |
| // Note that parsing will fail if the string's format does not match the |
| // expected type exactly. `ParseLenientCivilTime()` below is more lenient. |
| // |
| bool ParseCivilTime(absl::string_view s, CivilSecond* c); |
| bool ParseCivilTime(absl::string_view s, CivilMinute* c); |
| bool ParseCivilTime(absl::string_view s, CivilHour* c); |
| bool ParseCivilTime(absl::string_view s, CivilDay* c); |
| bool ParseCivilTime(absl::string_view s, CivilMonth* c); |
| bool ParseCivilTime(absl::string_view s, CivilYear* c); |
| |
| // ParseLenientCivilTime() |
| // |
| // Parses any of the formats accepted by `absl::ParseCivilTime()`, but is more |
| // lenient if the format of the string does not exactly match the associated |
| // type. |
| // |
| // Example: |
| // |
| // absl::CivilDay d; |
| // bool ok = absl::ParseLenientCivilTime("1969-07-20", &d); // OK |
| // ok = absl::ParseLenientCivilTime("1969-07-20T10", &d); // OK: T10 floored |
| // ok = absl::ParseLenientCivilTime("1969-07", &d); // OK: day defaults to 1 |
| // |
| bool ParseLenientCivilTime(absl::string_view s, CivilSecond* c); |
| bool ParseLenientCivilTime(absl::string_view s, CivilMinute* c); |
| bool ParseLenientCivilTime(absl::string_view s, CivilHour* c); |
| bool ParseLenientCivilTime(absl::string_view s, CivilDay* c); |
| bool ParseLenientCivilTime(absl::string_view s, CivilMonth* c); |
| bool ParseLenientCivilTime(absl::string_view s, CivilYear* c); |
| |
| namespace time_internal { // For functions found via ADL on civil-time tags. |
| |
| // Streaming Operators |
| // |
| // Each civil-time type may be sent to an output stream using operator<<(). |
| // The result matches the string produced by `FormatCivilTime()`. |
| // |
| // Example: |
| // |
| // absl::CivilDay d = absl::CivilDay(1969, 7, 20); |
| // std::cout << "Date is: " << d << "\n"; |
| // |
| std::ostream& operator<<(std::ostream& os, CivilYear y); |
| std::ostream& operator<<(std::ostream& os, CivilMonth m); |
| std::ostream& operator<<(std::ostream& os, CivilDay d); |
| std::ostream& operator<<(std::ostream& os, CivilHour h); |
| std::ostream& operator<<(std::ostream& os, CivilMinute m); |
| std::ostream& operator<<(std::ostream& os, CivilSecond s); |
| |
| // AbslParseFlag() |
| // |
| // Parses the command-line flag string representation `s` into a civil-time |
| // value. Flags must be specified in a format that is valid for |
| // `absl::ParseLenientCivilTime()`. |
| bool AbslParseFlag(absl::string_view s, CivilSecond* c, std::string* error); |
| bool AbslParseFlag(absl::string_view s, CivilMinute* c, std::string* error); |
| bool AbslParseFlag(absl::string_view s, CivilHour* c, std::string* error); |
| bool AbslParseFlag(absl::string_view s, CivilDay* c, std::string* error); |
| bool AbslParseFlag(absl::string_view s, CivilMonth* c, std::string* error); |
| bool AbslParseFlag(absl::string_view s, CivilYear* c, std::string* error); |
| |
| // AbslUnparseFlag() |
| // |
| // Unparses a civil-time value into a command-line string representation using |
| // the format specified by `absl::ParseCivilTime()`. |
| std::string AbslUnparseFlag(CivilSecond c); |
| std::string AbslUnparseFlag(CivilMinute c); |
| std::string AbslUnparseFlag(CivilHour c); |
| std::string AbslUnparseFlag(CivilDay c); |
| std::string AbslUnparseFlag(CivilMonth c); |
| std::string AbslUnparseFlag(CivilYear c); |
| |
| } // namespace time_internal |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_TIME_CIVIL_TIME_H_ |
| *¯* |
| fsoong/.intermediates/external/abseil-cpp/absl_log_absl_log_hdrs/gen/my_include_dir/absl/log/absl_log.hÄ)// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/absl_log.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header declares a family of `ABSL_LOG` macros as alternative spellings |
| // for macros in `log.h`. |
| // |
| // Basic invocation looks like this: |
| // |
| // ABSL_LOG(INFO) << "Found " << num_cookies << " cookies"; |
| // |
| // Most `ABSL_LOG` macros take a severity level argument. The severity levels |
| // are `INFO`, `WARNING`, `ERROR`, and `FATAL`. |
| // |
| // For full documentation, see comments in `log.h`, which includes full |
| // reference documentation on use of the equivalent `LOG` macro and has an |
| // identical set of macros without the ABSL_* prefix. |
| |
| #ifndef ABSL_LOG_ABSL_LOG_H_ |
| #define ABSL_LOG_ABSL_LOG_H_ |
| |
| #include "absl/log/internal/log_impl.h" |
| |
| #define ABSL_LOG(severity) ABSL_LOG_INTERNAL_LOG_IMPL(_##severity) |
| #define ABSL_PLOG(severity) ABSL_LOG_INTERNAL_PLOG_IMPL(_##severity) |
| #define ABSL_DLOG(severity) ABSL_LOG_INTERNAL_DLOG_IMPL(_##severity) |
| |
| #define ABSL_VLOG(verbose_level) ABSL_LOG_INTERNAL_VLOG_IMPL(verbose_level) |
| #define ABSL_DVLOG(verbose_level) ABSL_LOG_INTERNAL_DVLOG_IMPL(verbose_level) |
| |
| #define ABSL_LOG_IF(severity, condition) \ |
| ABSL_LOG_INTERNAL_LOG_IF_IMPL(_##severity, condition) |
| #define ABSL_PLOG_IF(severity, condition) \ |
| ABSL_LOG_INTERNAL_PLOG_IF_IMPL(_##severity, condition) |
| #define ABSL_DLOG_IF(severity, condition) \ |
| ABSL_LOG_INTERNAL_DLOG_IF_IMPL(_##severity, condition) |
| |
| #define ABSL_LOG_EVERY_N(severity, n) \ |
| ABSL_LOG_INTERNAL_LOG_EVERY_N_IMPL(_##severity, n) |
| #define ABSL_LOG_FIRST_N(severity, n) \ |
| ABSL_LOG_INTERNAL_LOG_FIRST_N_IMPL(_##severity, n) |
| #define ABSL_LOG_EVERY_POW_2(severity) \ |
| ABSL_LOG_INTERNAL_LOG_EVERY_POW_2_IMPL(_##severity) |
| #define ABSL_LOG_EVERY_N_SEC(severity, n_seconds) \ |
| ABSL_LOG_INTERNAL_LOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) |
| |
| #define ABSL_PLOG_EVERY_N(severity, n) \ |
| ABSL_LOG_INTERNAL_PLOG_EVERY_N_IMPL(_##severity, n) |
| #define ABSL_PLOG_FIRST_N(severity, n) \ |
| ABSL_LOG_INTERNAL_PLOG_FIRST_N_IMPL(_##severity, n) |
| #define ABSL_PLOG_EVERY_POW_2(severity) \ |
| ABSL_LOG_INTERNAL_PLOG_EVERY_POW_2_IMPL(_##severity) |
| #define ABSL_PLOG_EVERY_N_SEC(severity, n_seconds) \ |
| ABSL_LOG_INTERNAL_PLOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) |
| |
| #define ABSL_DLOG_EVERY_N(severity, n) \ |
| ABSL_LOG_INTERNAL_DLOG_EVERY_N_IMPL(_##severity, n) |
| #define ABSL_DLOG_FIRST_N(severity, n) \ |
| ABSL_LOG_INTERNAL_DLOG_FIRST_N_IMPL(_##severity, n) |
| #define ABSL_DLOG_EVERY_POW_2(severity) \ |
| ABSL_LOG_INTERNAL_DLOG_EVERY_POW_2_IMPL(_##severity) |
| #define ABSL_DLOG_EVERY_N_SEC(severity, n_seconds) \ |
| ABSL_LOG_INTERNAL_DLOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) |
| |
| #define ABSL_VLOG_EVERY_N(verbose_level, n) \ |
| ABSL_LOG_INTERNAL_VLOG_EVERY_N_IMPL(verbose_level, n) |
| #define ABSL_VLOG_FIRST_N(verbose_level, n) \ |
| ABSL_LOG_INTERNAL_VLOG_FIRST_N_IMPL(verbose_level, n) |
| #define ABSL_VLOG_EVERY_POW_2(verbose_level, n) \ |
| ABSL_LOG_INTERNAL_VLOG_EVERY_POW_2_IMPL(verbose_level, n) |
| #define ABSL_VLOG_EVERY_N_SEC(verbose_level, n) \ |
| ABSL_LOG_INTERNAL_VLOG_EVERY_N_SEC_IMPL(verbose_level, n) |
| |
| #define ABSL_LOG_IF_EVERY_N(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_IMPL(_##severity, condition, n) |
| #define ABSL_LOG_IF_FIRST_N(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_LOG_IF_FIRST_N_IMPL(_##severity, condition, n) |
| #define ABSL_LOG_IF_EVERY_POW_2(severity, condition) \ |
| ABSL_LOG_INTERNAL_LOG_IF_EVERY_POW_2_IMPL(_##severity, condition) |
| #define ABSL_LOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ |
| ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) |
| |
| #define ABSL_PLOG_IF_EVERY_N(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_IMPL(_##severity, condition, n) |
| #define ABSL_PLOG_IF_FIRST_N(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_PLOG_IF_FIRST_N_IMPL(_##severity, condition, n) |
| #define ABSL_PLOG_IF_EVERY_POW_2(severity, condition) \ |
| ABSL_LOG_INTERNAL_PLOG_IF_EVERY_POW_2_IMPL(_##severity, condition) |
| #define ABSL_PLOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ |
| ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) |
| |
| #define ABSL_DLOG_IF_EVERY_N(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_IMPL(_##severity, condition, n) |
| #define ABSL_DLOG_IF_FIRST_N(severity, condition, n) \ |
| ABSL_LOG_INTERNAL_DLOG_IF_FIRST_N_IMPL(_##severity, condition, n) |
| #define ABSL_DLOG_IF_EVERY_POW_2(severity, condition) \ |
| ABSL_LOG_INTERNAL_DLOG_IF_EVERY_POW_2_IMPL(_##severity, condition) |
| #define ABSL_DLOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ |
| ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) |
| |
| #endif // ABSL_LOG_ABSL_LOG_H_ |
| * |
| jsoong/.intermediates/external/abseil-cpp/absl_algorithm_hdrs/gen/my_include_dir/absl/algorithm/algorithm.h¤// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: algorithm.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file contains Google extensions to the standard <algorithm> C++ |
| // header. |
| |
| #ifndef ABSL_ALGORITHM_ALGORITHM_H_ |
| #define ABSL_ALGORITHM_ALGORITHM_H_ |
| |
| #include <algorithm> |
| #include <iterator> |
| #include <type_traits> |
| |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // equal() |
| // rotate() |
| // |
| // Historical note: Abseil once provided implementations of these algorithms |
| // prior to their adoption in C++14. New code should prefer to use the std |
| // variants. |
| // |
| // See the documentation for the STL <algorithm> header for more information: |
| // https://en.cppreference.com/w/cpp/header/algorithm |
| using std::equal; |
| using std::rotate; |
| |
| // linear_search() |
| // |
| // Performs a linear search for `value` using the iterator `first` up to |
| // but not including `last`, returning true if [`first`, `last`) contains an |
| // element equal to `value`. |
| // |
| // A linear search is of O(n) complexity which is guaranteed to make at most |
| // n = (`last` - `first`) comparisons. A linear search over short containers |
| // may be faster than a binary search, even when the container is sorted. |
| template <typename InputIterator, typename EqualityComparable> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool linear_search( |
| InputIterator first, InputIterator last, const EqualityComparable& value) { |
| return std::find(first, last, value) != last; |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_ALGORITHM_ALGORITHM_H_ |
| *«, |
| soong/.intermediates/external/abseil-cpp/absl_container_common_policy_traits_hdrs/gen/my_include_dir/absl/container/internal/common_policy_traits.h+// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_ |
| #define ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_ |
| |
| #include <cstddef> |
| #include <cstring> |
| #include <memory> |
| #include <new> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/meta/type_traits.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace container_internal { |
| |
| template <class Policy, class = void> |
| struct policy_trait_element_is_owner : std::false_type {}; |
| |
| template <class Policy> |
| struct policy_trait_element_is_owner< |
| Policy, |
| std::enable_if_t<!std::is_void<typename Policy::element_is_owner>::value>> |
| : Policy::element_is_owner {}; |
| |
| // Defines how slots are initialized/destroyed/moved. |
| template <class Policy, class = void> |
| struct common_policy_traits { |
| // The actual object stored in the container. |
| using slot_type = typename Policy::slot_type; |
| using reference = decltype(Policy::element(std::declval<slot_type*>())); |
| using value_type = typename std::remove_reference<reference>::type; |
| |
| // PRECONDITION: `slot` is UNINITIALIZED |
| // POSTCONDITION: `slot` is INITIALIZED |
| template <class Alloc, class... Args> |
| static void construct(Alloc* alloc, slot_type* slot, Args&&... args) { |
| Policy::construct(alloc, slot, std::forward<Args>(args)...); |
| } |
| |
| // PRECONDITION: `slot` is INITIALIZED |
| // POSTCONDITION: `slot` is UNINITIALIZED |
| // Returns std::true_type in case destroy is trivial. |
| template <class Alloc> |
| static auto destroy(Alloc* alloc, slot_type* slot) { |
| return Policy::destroy(alloc, slot); |
| } |
| |
| // Transfers the `old_slot` to `new_slot`. Any memory allocated by the |
| // allocator inside `old_slot` to `new_slot` can be transferred. |
| // |
| // OPTIONAL: defaults to: |
| // |
| // clone(new_slot, std::move(*old_slot)); |
| // destroy(old_slot); |
| // |
| // PRECONDITION: `new_slot` is UNINITIALIZED and `old_slot` is INITIALIZED |
| // POSTCONDITION: `new_slot` is INITIALIZED and `old_slot` is |
| // UNINITIALIZED |
| template <class Alloc> |
| static void transfer(Alloc* alloc, slot_type* new_slot, slot_type* old_slot) { |
| transfer_impl(alloc, new_slot, old_slot, Rank2{}); |
| } |
| |
| // PRECONDITION: `slot` is INITIALIZED |
| // POSTCONDITION: `slot` is INITIALIZED |
| // Note: we use remove_const_t so that the two overloads have different args |
| // in the case of sets with explicitly const value_types. |
| template <class P = Policy> |
| static auto element(absl::remove_const_t<slot_type>* slot) |
| -> decltype(P::element(slot)) { |
| return P::element(slot); |
| } |
| template <class P = Policy> |
| static auto element(const slot_type* slot) -> decltype(P::element(slot)) { |
| return P::element(slot); |
| } |
| |
| static constexpr bool transfer_uses_memcpy() { |
| return std::is_same<decltype(transfer_impl<std::allocator<char>>( |
| nullptr, nullptr, nullptr, Rank2{})), |
| std::true_type>::value; |
| } |
| |
| // Returns true if destroy is trivial and can be omitted. |
| template <class Alloc> |
| static constexpr bool destroy_is_trivial() { |
| return std::is_same<decltype(destroy<Alloc>(nullptr, nullptr)), |
| std::true_type>::value; |
| } |
| |
| private: |
| // Use go/ranked-overloads for dispatching. |
| struct Rank0 {}; |
| struct Rank1 : Rank0 {}; |
| struct Rank2 : Rank1 {}; |
| |
| // Use auto -> decltype as an enabler. |
| // P::transfer returns std::true_type if transfer uses memcpy (e.g. in |
| // node_slot_policy). |
| template <class Alloc, class P = Policy> |
| static auto transfer_impl(Alloc* alloc, slot_type* new_slot, |
| slot_type* old_slot, |
| Rank2) -> decltype(P::transfer(alloc, new_slot, |
| old_slot)) { |
| return P::transfer(alloc, new_slot, old_slot); |
| } |
| |
| // This overload returns true_type for the trait below. |
| // The conditional_t is to make the enabler type dependent. |
| template <class Alloc, |
| typename = std::enable_if_t<absl::is_trivially_relocatable< |
| std::conditional_t<false, Alloc, value_type>>::value>> |
| static std::true_type transfer_impl(Alloc*, slot_type* new_slot, |
| slot_type* old_slot, Rank1) { |
| // TODO(b/247130232): remove casts after fixing warnings. |
| // TODO(b/251814870): remove casts after fixing warnings. |
| std::memcpy( |
| static_cast<void*>(std::launder( |
| const_cast<std::remove_const_t<value_type>*>(&element(new_slot)))), |
| static_cast<const void*>(&element(old_slot)), sizeof(value_type)); |
| return {}; |
| } |
| |
| template <class Alloc> |
| static void transfer_impl(Alloc* alloc, slot_type* new_slot, |
| slot_type* old_slot, Rank0) { |
| construct(alloc, new_slot, std::move(element(old_slot))); |
| destroy(alloc, old_slot); |
| } |
| }; |
| |
| } // namespace container_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_ |
| *» |
| \soong/.intermediates/external/abseil-cpp/absl_time_hdrs/gen/my_include_dir/absl/time/clock.hÚ// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: clock.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file contains utility functions for working with the system-wide |
| // realtime clock. For descriptions of the main time abstractions used within |
| // this header file, consult the time.h header file. |
| #ifndef ABSL_TIME_CLOCK_H_ |
| #define ABSL_TIME_CLOCK_H_ |
| |
| #include <cstdint> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/macros.h" |
| #include "absl/time/time.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // Now() |
| // |
| // Returns the current time, expressed as an `absl::Time` absolute time value. |
| absl::Time Now(); |
| |
| // GetCurrentTimeNanos() |
| // |
| // Returns the current time, expressed as a count of nanoseconds since the Unix |
| // Epoch (https://en.wikipedia.org/wiki/Unix_time). Prefer `absl::Now()` instead |
| // for all but the most performance-sensitive cases (i.e. when you are calling |
| // this function hundreds of thousands of times per second). |
| int64_t GetCurrentTimeNanos(); |
| |
| // SleepFor() |
| // |
| // Sleeps for the specified duration, expressed as an `absl::Duration`. |
| // |
| // Notes: |
| // * Signal interruptions will not reduce the sleep duration. |
| // * Returns immediately when passed a nonpositive duration. |
| void SleepFor(absl::Duration duration); |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| // ----------------------------------------------------------------------------- |
| // Implementation Details |
| // ----------------------------------------------------------------------------- |
| |
| // In some build configurations we pass --detect-odr-violations to the |
| // gold linker. This causes it to flag weak symbol overrides as ODR |
| // violations. Because ODR only applies to C++ and not C, |
| // --detect-odr-violations ignores symbols not mangled with C++ names. |
| // By changing our extension points to be extern "C", we dodge this |
| // check. |
| extern "C" { |
| ABSL_DLL void ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)( |
| absl::Duration duration); |
| } // extern "C" |
| |
| inline void absl::SleepFor(absl::Duration duration) { |
| ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(duration); |
| } |
| |
| #endif // ABSL_TIME_CLOCK_H_ |
| *Â |
| vsoong/.intermediates/external/abseil-cpp/absl_log_internal_voidify_hdrs/gen/my_include_dir/absl/log/internal/voidify.hÇ
// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/internal/voidify.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This class does the dispatching of the completed `absl::LogEntry` to |
| // applicable `absl::LogSink`s, and is used to explicitly ignore values in the |
| // conditional logging macros. This avoids compiler warnings like "value |
| // computed is not used" and "statement has no effect". |
| |
| #ifndef ABSL_LOG_INTERNAL_VOIDIFY_H_ |
| #define ABSL_LOG_INTERNAL_VOIDIFY_H_ |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace log_internal { |
| |
| class Voidify final { |
| public: |
| // This has to be an operator with a precedence lower than << but higher than |
| // ?: |
| template <typename T> |
| ABSL_ATTRIBUTE_COLD void operator&&(T&& message) const&& { |
| // The dispatching of the completed `absl::LogEntry` to applicable |
| // `absl::LogSink`s happens here. |
| message.Flush(); |
| } |
| }; |
| |
| } // namespace log_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_LOG_INTERNAL_VOIDIFY_H_ |
| *Àh |
| rsoong/.intermediates/external/abseil-cpp/absl_log_internal_proto_hdrs/gen/my_include_dir/absl/log/internal/proto.hÉg// 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. |
| |
| // ----------------------------------------------------------------------------- |
| // File: internal/proto.h |
| // ----------------------------------------------------------------------------- |
| // |
| // Declares functions for serializing and deserializing data to and from memory |
| // buffers in protocol buffer wire format. This library takes no steps to |
| // ensure that the encoded data matches with any message specification. |
| |
| #ifndef ABSL_LOG_INTERNAL_PROTO_H_ |
| #define ABSL_LOG_INTERNAL_PROTO_H_ |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <limits> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/casts.h" |
| #include "absl/base/config.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/types/span.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace log_internal { |
| |
| // absl::Span<char> represents a view into the available space in a mutable |
| // buffer during encoding. Encoding functions shrink the span as they go so |
| // that the same view can be passed to a series of Encode functions. If the |
| // data do not fit, nothing is encoded, the view is set to size zero (so that |
| // all subsequent encode calls fail), and false is returned. Otherwise true is |
| // returned. |
| |
| // In particular, attempting to encode a series of data into an insufficient |
| // buffer has consistent and efficient behavior without any caller-side error |
| // checking. Individual values will be encoded in their entirety or not at all |
| // (unless one of the `Truncate` functions is used). Once a value is omitted |
| // because it does not fit, no subsequent values will be encoded to preserve |
| // ordering; the decoded sequence will be a prefix of the original sequence. |
| |
| // There are two ways to encode a message-typed field: |
| // |
| // * Construct its contents in a separate buffer and use `EncodeBytes` to copy |
| // it into the primary buffer with type, tag, and length. |
| // * Use `EncodeMessageStart` to write type and tag fields and reserve space for |
| // the length field, then encode the contents directly into the buffer, then |
| // use `EncodeMessageLength` to write the actual length into the reserved |
| // bytes. This works fine if the actual length takes fewer bytes to encode |
| // than were reserved, although you don't get your extra bytes back. |
| // This approach will always produce a valid encoding, but your protocol may |
| // require that the whole message field by omitted if the buffer is too small |
| // to contain all desired subfields. In this case, operate on a copy of the |
| // buffer view and assign back only if everything fit, i.e. if the last |
| // `Encode` call returned true. |
| |
| // Encodes the specified integer as a varint field and returns true if it fits. |
| // Used for int32_t, int64_t, uint32_t, uint64_t, bool, and enum field types. |
| // Consumes up to kMaxVarintSize * 2 bytes (20). |
| bool EncodeVarint(uint64_t tag, uint64_t value, absl::Span<char> *buf); |
| inline bool EncodeVarint(uint64_t tag, int64_t value, absl::Span<char> *buf) { |
| return EncodeVarint(tag, static_cast<uint64_t>(value), buf); |
| } |
| inline bool EncodeVarint(uint64_t tag, uint32_t value, absl::Span<char> *buf) { |
| return EncodeVarint(tag, static_cast<uint64_t>(value), buf); |
| } |
| inline bool EncodeVarint(uint64_t tag, int32_t value, absl::Span<char> *buf) { |
| return EncodeVarint(tag, static_cast<uint64_t>(value), buf); |
| } |
| |
| // Encodes the specified integer as a varint field using ZigZag encoding and |
| // returns true if it fits. |
| // Used for sint32 and sint64 field types. |
| // Consumes up to kMaxVarintSize * 2 bytes (20). |
| inline bool EncodeVarintZigZag(uint64_t tag, int64_t value, |
| absl::Span<char> *buf) { |
| if (value < 0) |
| return EncodeVarint(tag, 2 * static_cast<uint64_t>(-(value + 1)) + 1, buf); |
| return EncodeVarint(tag, 2 * static_cast<uint64_t>(value), buf); |
| } |
| |
| // Encodes the specified integer as a 64-bit field and returns true if it fits. |
| // Used for fixed64 and sfixed64 field types. |
| // Consumes up to kMaxVarintSize + 8 bytes (18). |
| bool Encode64Bit(uint64_t tag, uint64_t value, absl::Span<char> *buf); |
| inline bool Encode64Bit(uint64_t tag, int64_t value, absl::Span<char> *buf) { |
| return Encode64Bit(tag, static_cast<uint64_t>(value), buf); |
| } |
| inline bool Encode64Bit(uint64_t tag, uint32_t value, absl::Span<char> *buf) { |
| return Encode64Bit(tag, static_cast<uint64_t>(value), buf); |
| } |
| inline bool Encode64Bit(uint64_t tag, int32_t value, absl::Span<char> *buf) { |
| return Encode64Bit(tag, static_cast<uint64_t>(value), buf); |
| } |
| |
| // Encodes the specified double as a 64-bit field and returns true if it fits. |
| // Used for double field type. |
| // Consumes up to kMaxVarintSize + 8 bytes (18). |
| inline bool EncodeDouble(uint64_t tag, double value, absl::Span<char> *buf) { |
| return Encode64Bit(tag, absl::bit_cast<uint64_t>(value), buf); |
| } |
| |
| // Encodes the specified integer as a 32-bit field and returns true if it fits. |
| // Used for fixed32 and sfixed32 field types. |
| // Consumes up to kMaxVarintSize + 4 bytes (14). |
| bool Encode32Bit(uint64_t tag, uint32_t value, absl::Span<char> *buf); |
| inline bool Encode32Bit(uint64_t tag, int32_t value, absl::Span<char> *buf) { |
| return Encode32Bit(tag, static_cast<uint32_t>(value), buf); |
| } |
| |
| // Encodes the specified float as a 32-bit field and returns true if it fits. |
| // Used for float field type. |
| // Consumes up to kMaxVarintSize + 4 bytes (14). |
| inline bool EncodeFloat(uint64_t tag, float value, absl::Span<char> *buf) { |
| return Encode32Bit(tag, absl::bit_cast<uint32_t>(value), buf); |
| } |
| |
| // Encodes the specified bytes as a length-delimited field and returns true if |
| // they fit. |
| // Used for string, bytes, message, and packed-repeated field type. |
| // Consumes up to kMaxVarintSize * 2 + value.size() bytes (20 + value.size()). |
| bool EncodeBytes(uint64_t tag, absl::Span<const char> value, |
| absl::Span<char> *buf); |
| |
| // Encodes as many of the specified bytes as will fit as a length-delimited |
| // field and returns true as long as the field header (`tag_type` and `length`) |
| // fits. |
| // Used for string, bytes, message, and packed-repeated field type. |
| // Consumes up to kMaxVarintSize * 2 + value.size() bytes (20 + value.size()). |
| bool EncodeBytesTruncate(uint64_t tag, absl::Span<const char> value, |
| absl::Span<char> *buf); |
| |
| // Encodes the specified string as a length-delimited field and returns true if |
| // it fits. |
| // Used for string, bytes, message, and packed-repeated field type. |
| // Consumes up to kMaxVarintSize * 2 + value.size() bytes (20 + value.size()). |
| inline bool EncodeString(uint64_t tag, absl::string_view value, |
| absl::Span<char> *buf) { |
| return EncodeBytes(tag, value, buf); |
| } |
| |
| // Encodes as much of the specified string as will fit as a length-delimited |
| // field and returns true as long as the field header (`tag_type` and `length`) |
| // fits. |
| // Used for string, bytes, message, and packed-repeated field type. |
| // Consumes up to kMaxVarintSize * 2 + value.size() bytes (20 + value.size()). |
| inline bool EncodeStringTruncate(uint64_t tag, absl::string_view value, |
| absl::Span<char> *buf) { |
| return EncodeBytesTruncate(tag, value, buf); |
| } |
| |
| // Encodes the header for a length-delimited field containing up to `max_size` |
| // bytes or the number remaining in the buffer, whichever is less. If the |
| // header fits, a non-nullptr `Span` is returned; this must be passed to |
| // `EncodeMessageLength` after all contents are encoded to finalize the length |
| // field. If the header does not fit, a nullptr `Span` is returned which is |
| // safe to pass to `EncodeMessageLength` but need not be. |
| // Used for string, bytes, message, and packed-repeated field type. |
| // Consumes up to kMaxVarintSize * 2 bytes (20). |
| [[nodiscard]] absl::Span<char> EncodeMessageStart(uint64_t tag, |
| uint64_t max_size, |
| absl::Span<char> *buf); |
| |
| // Finalizes the length field in `msg` so that it encompasses all data encoded |
| // since the call to `EncodeMessageStart` which returned `msg`. Does nothing if |
| // `msg` is a `nullptr` `Span`. |
| void EncodeMessageLength(absl::Span<char> msg, const absl::Span<char> *buf); |
| |
| enum class WireType : uint64_t { |
| kVarint = 0, |
| k64Bit = 1, |
| kLengthDelimited = 2, |
| k32Bit = 5, |
| }; |
| |
| constexpr size_t VarintSize(uint64_t value) { |
| return value < 128 ? 1 : 1 + VarintSize(value >> 7); |
| } |
| constexpr size_t MinVarintSize() { |
| return VarintSize((std::numeric_limits<uint64_t>::min)()); |
| } |
| constexpr size_t MaxVarintSize() { |
| return VarintSize((std::numeric_limits<uint64_t>::max)()); |
| } |
| |
| constexpr uint64_t MaxVarintForSize(size_t size) { |
| return size >= 10 ? (std::numeric_limits<uint64_t>::max)() |
| : (static_cast<uint64_t>(1) << size * 7) - 1; |
| } |
| constexpr uint64_t MakeTagType(uint64_t tag, WireType type) { |
| return tag << 3 | static_cast<uint64_t>(type); |
| } |
| |
| // `BufferSizeFor` returns a number of bytes guaranteed to be sufficient to |
| // store encoded fields as `(tag, WireType)`, regardless of data values. This |
| // only makes sense for `WireType::kLengthDelimited` if you add in the length of |
| // the contents yourself, e.g. for string and bytes fields by adding the lengths |
| // of any encoded strings to the return value or for submessage fields by |
| // enumerating the fields you may encode into their contents. |
| constexpr size_t BufferSizeFor(uint64_t tag, WireType type) { |
| size_t buffer_size = VarintSize(MakeTagType(tag, type)); |
| switch (type) { |
| case WireType::kVarint: |
| buffer_size += MaxVarintSize(); |
| break; |
| case WireType::k64Bit: |
| buffer_size += size_t{8}; |
| break; |
| case WireType::kLengthDelimited: |
| buffer_size += MaxVarintSize(); |
| break; |
| case WireType::k32Bit: |
| buffer_size += size_t{4}; |
| break; |
| } |
| return buffer_size; |
| } |
| |
| // absl::Span<const char> represents a view into the un-processed space in a |
| // buffer during decoding. Decoding functions shrink the span as they go so |
| // that the same view can be decoded iteratively until all data are processed. |
| // In general, if the buffer is exhausted but additional bytes are expected by |
| // the decoder, it will return values as if the additional bytes were zeros. |
| // Length-delimited fields are an exception - if the encoded length field |
| // indicates more data bytes than are available in the buffer, the `bytes_value` |
| // and `string_value` accessors will return truncated views. |
| |
| class ProtoField final { |
| public: |
| // Consumes bytes from `data` and returns true if there were any bytes to |
| // decode. |
| bool DecodeFrom(absl::Span<const char> *data); |
| uint64_t tag() const { return tag_; } |
| WireType type() const { return type_; } |
| |
| // These value accessors will return nonsense if the data were not encoded in |
| // the corresponding wiretype from the corresponding C++ (or other language) |
| // type. |
| |
| double double_value() const { return absl::bit_cast<double>(value_); } |
| float float_value() const { |
| return absl::bit_cast<float>(static_cast<uint32_t>(value_)); |
| } |
| int32_t int32_value() const { return static_cast<int32_t>(value_); } |
| int64_t int64_value() const { return static_cast<int64_t>(value_); } |
| int32_t sint32_value() const { |
| if (value_ % 2) return static_cast<int32_t>(0 - ((value_ - 1) / 2) - 1); |
| return static_cast<int32_t>(value_ / 2); |
| } |
| int64_t sint64_value() const { |
| if (value_ % 2) return 0 - ((value_ - 1) / 2) - 1; |
| return value_ / 2; |
| } |
| uint32_t uint32_value() const { return static_cast<uint32_t>(value_); } |
| uint64_t uint64_value() const { return value_; } |
| bool bool_value() const { return value_ != 0; } |
| // To decode an enum, call int32_value() and cast to the appropriate type. |
| // Note that the official C++ proto compiler treats enum fields with values |
| // that do not correspond to a defined enumerator as unknown fields. |
| |
| // To decode fields within a submessage field, call |
| // `DecodeNextField(field.BytesValue())`. |
| absl::Span<const char> bytes_value() const { return data_; } |
| absl::string_view string_value() const { |
| const auto data = bytes_value(); |
| return absl::string_view(data.data(), data.size()); |
| } |
| // Returns the encoded length of a length-delimited field. This equals |
| // `bytes_value().size()` except when the latter has been truncated due to |
| // buffer underrun. |
| uint64_t encoded_length() const { return value_; } |
| |
| private: |
| uint64_t tag_; |
| WireType type_; |
| // For `kTypeVarint`, `kType64Bit`, and `kType32Bit`, holds the decoded value. |
| // For `kTypeLengthDelimited`, holds the decoded length. |
| uint64_t value_; |
| absl::Span<const char> data_; |
| }; |
| |
| } // namespace log_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_LOG_INTERNAL_PROTO_H_ |
| *¤A |
| hsoong/.intermediates/external/abseil-cpp/absl_log_log_entry_hdrs/gen/my_include_dir/absl/log/log_entry.h·@// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/log_entry.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header declares `class absl::LogEntry`, which represents a log record as |
| // passed to `LogSink::Send`. Data returned by pointer or by reference or by |
| // `absl::string_view` must be copied if they are needed after the lifetime of |
| // the `absl::LogEntry`. |
| |
| #ifndef ABSL_LOG_LOG_ENTRY_H_ |
| #define ABSL_LOG_LOG_ENTRY_H_ |
| |
| #include <cstddef> |
| #include <string> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/log_severity.h" |
| #include "absl/log/internal/config.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/time/time.h" |
| #include "absl/types/span.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| namespace log_internal { |
| // Test only friend. |
| class LogEntryTestPeer; |
| class LogMessage; |
| } // namespace log_internal |
| |
| // LogEntry |
| // |
| // Represents a single entry in a log, i.e., one `LOG` statement or failed |
| // `CHECK`. |
| // |
| // `LogEntry` is thread-compatible. |
| class LogEntry final { |
| public: |
| using tid_t = log_internal::Tid; |
| |
| // For non-verbose log entries, `verbosity()` returns `kNoVerbosityLevel`. |
| static constexpr int kNoVerbosityLevel = -1; |
| static constexpr int kNoVerboseLevel = -1; // TO BE removed |
| |
| // Pass `LogEntry` by reference, and do not store it as its state does not |
| // outlive the call to `LogSink::Send()`. |
| LogEntry(const LogEntry&) = delete; |
| LogEntry& operator=(const LogEntry&) = delete; |
| |
| // Source file and line where the log message occurred. Taken from `__FILE__` |
| // and `__LINE__` unless overridden by `LOG(...).AtLocation(...)`. |
| // |
| // Take special care not to use the values returned by `source_filename()` and |
| // `source_basename()` after the lifetime of the entry. This is always |
| // incorrect, but it will often work in practice because they usually point |
| // into a statically allocated character array obtained from `__FILE__`. |
| // Statements like `LOG(INFO).AtLocation(std::string(...), ...)` will expose |
| // the bug. If you need the data later, you must copy them. |
| absl::string_view source_filename() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return full_filename_; |
| } |
| absl::string_view source_basename() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return base_filename_; |
| } |
| int source_line() const { return line_; } |
| |
| // LogEntry::prefix() |
| // |
| // True unless the metadata prefix was suppressed once by |
| // `LOG(...).NoPrefix()` or globally by `absl::EnableLogPrefix(false)`. |
| // Implies `text_message_with_prefix() == text_message()`. |
| bool prefix() const { return prefix_; } |
| |
| // LogEntry::log_severity() |
| // |
| // Returns this entry's severity. For `LOG`, taken from the first argument; |
| // for `CHECK`, always `absl::LogSeverity::kFatal`. |
| absl::LogSeverity log_severity() const { return severity_; } |
| |
| // LogEntry::verbosity() |
| // |
| // Returns this entry's verbosity, or `kNoVerbosityLevel` for a non-verbose |
| // entry. Taken from the argument to `VLOG` or from |
| // `LOG(...).WithVerbosity(...)`. |
| int verbosity() const { return verbose_level_; } |
| |
| // LogEntry::timestamp() |
| // |
| // Returns the time at which this entry was written. Captured during |
| // evaluation of `LOG`, but can be overridden by |
| // `LOG(...).WithTimestamp(...)`. |
| // |
| // Take care not to rely on timestamps increasing monotonically, or even to |
| // rely on timestamps having any particular relationship with reality (since |
| // they can be overridden). |
| absl::Time timestamp() const { return timestamp_; } |
| |
| // LogEntry::tid() |
| // |
| // Returns the ID of the thread that wrote this entry. Captured during |
| // evaluation of `LOG`, but can be overridden by `LOG(...).WithThreadID(...)`. |
| // |
| // Take care not to *rely* on reported thread IDs as they can be overridden as |
| // specified above. |
| tid_t tid() const { return tid_; } |
| |
| // Text-formatted version of the log message. An underlying buffer holds |
| // these contiguous data: |
| // |
| // * A prefix formed by formatting metadata (timestamp, filename, line number, |
| // etc.) |
| // The prefix may be empty - see `LogEntry::prefix()` - and may rarely be |
| // truncated if the metadata are very long. |
| // * The streamed data |
| // The data may be empty if nothing was streamed, or may be truncated to fit |
| // the buffer. |
| // * A newline |
| // * A nul terminator |
| // |
| // The newline and nul terminator will be present even if the prefix and/or |
| // data are truncated. |
| // |
| // These methods give access to the most commonly useful substrings of the |
| // buffer's contents. Other combinations can be obtained with substring |
| // arithmetic. |
| // |
| // The buffer does not outlive the entry; if you need the data later, you must |
| // copy them. |
| absl::string_view text_message_with_prefix_and_newline() const |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return absl::string_view( |
| text_message_with_prefix_and_newline_and_nul_.data(), |
| text_message_with_prefix_and_newline_and_nul_.size() - 1); |
| } |
| absl::string_view text_message_with_prefix() const |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return absl::string_view( |
| text_message_with_prefix_and_newline_and_nul_.data(), |
| text_message_with_prefix_and_newline_and_nul_.size() - 2); |
| } |
| absl::string_view text_message_with_newline() const |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return absl::string_view( |
| text_message_with_prefix_and_newline_and_nul_.data() + prefix_len_, |
| text_message_with_prefix_and_newline_and_nul_.size() - prefix_len_ - 1); |
| } |
| absl::string_view text_message() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return absl::string_view( |
| text_message_with_prefix_and_newline_and_nul_.data() + prefix_len_, |
| text_message_with_prefix_and_newline_and_nul_.size() - prefix_len_ - 2); |
| } |
| const char* text_message_with_prefix_and_newline_c_str() const |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return text_message_with_prefix_and_newline_and_nul_.data(); |
| } |
| |
| // Returns a serialized protobuf holding the operands streamed into this |
| // log message. The message definition is not yet published. |
| // |
| // The buffer does not outlive the entry; if you need the data later, you must |
| // copy them. |
| absl::string_view encoded_message() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return encoding_; |
| } |
| |
| // LogEntry::stacktrace() |
| // |
| // Optional stacktrace, e.g. for `FATAL` logs and failed `CHECK`s. |
| // |
| // Fatal entries are dispatched to each sink twice: first with all data and |
| // metadata but no stacktrace, and then with the stacktrace. This is done |
| // because stacktrace collection is sometimes slow and fallible, and it's |
| // critical to log enough information to diagnose the failure even if the |
| // stacktrace collection hangs. |
| // |
| // The buffer does not outlive the entry; if you need the data later, you must |
| // copy them. |
| absl::string_view stacktrace() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return stacktrace_; |
| } |
| |
| private: |
| LogEntry() = default; |
| |
| absl::string_view full_filename_; |
| absl::string_view base_filename_; |
| int line_; |
| bool prefix_; |
| absl::LogSeverity severity_; |
| int verbose_level_; // >=0 for `VLOG`, etc.; otherwise `kNoVerbosityLevel`. |
| absl::Time timestamp_; |
| tid_t tid_; |
| absl::Span<const char> text_message_with_prefix_and_newline_and_nul_; |
| size_t prefix_len_; |
| absl::string_view encoding_; |
| std::string stacktrace_; |
| |
| friend class log_internal::LogEntryTestPeer; |
| friend class log_internal::LogMessage; |
| }; |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_LOG_LOG_ENTRY_H_ |
| *8 |
| psoong/.intermediates/external/abseil-cpp/absl_base_log_severity_hdrs/gen/my_include_dir/absl/base/log_severity.h¢7// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_BASE_LOG_SEVERITY_H_ |
| #define ABSL_BASE_LOG_SEVERITY_H_ |
| |
| #include <array> |
| #include <ostream> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // absl::LogSeverity |
| // |
| // Four severity levels are defined. Logging APIs should terminate the program |
| // when a message is logged at severity `kFatal`; the other levels have no |
| // special semantics. |
| // |
| // Values other than the four defined levels (e.g. produced by `static_cast`) |
| // are valid, but their semantics when passed to a function, macro, or flag |
| // depend on the function, macro, or flag. The usual behavior is to normalize |
| // such values to a defined severity level, however in some cases values other |
| // than the defined levels are useful for comparison. |
| // |
| // Example: |
| // |
| // // Effectively disables all logging: |
| // SetMinLogLevel(static_cast<absl::LogSeverity>(100)); |
| // |
| // Abseil flags may be defined with type `LogSeverity`. Dependency layering |
| // constraints require that the `AbslParseFlag()` overload be declared and |
| // defined in the flags library itself rather than here. The `AbslUnparseFlag()` |
| // overload is defined there as well for consistency. |
| // |
| // absl::LogSeverity Flag String Representation |
| // |
| // An `absl::LogSeverity` has a string representation used for parsing |
| // command-line flags based on the enumerator name (e.g. `kFatal`) or |
| // its unprefixed name (without the `k`) in any case-insensitive form. (E.g. |
| // "FATAL", "fatal" or "Fatal" are all valid.) Unparsing such flags produces an |
| // unprefixed string representation in all caps (e.g. "FATAL") or an integer. |
| // |
| // Additionally, the parser accepts arbitrary integers (as if the type were |
| // `int`). |
| // |
| // Examples: |
| // |
| // --my_log_level=kInfo |
| // --my_log_level=INFO |
| // --my_log_level=info |
| // --my_log_level=0 |
| // |
| // `DFATAL` and `kLogDebugFatal` are similarly accepted. |
| // |
| // Unparsing a flag produces the same result as `absl::LogSeverityName()` for |
| // the standard levels and a base-ten integer otherwise. |
| enum class LogSeverity : int { |
| kInfo = 0, |
| kWarning = 1, |
| kError = 2, |
| kFatal = 3, |
| }; |
| |
| // LogSeverities() |
| // |
| // Returns an iterable of all standard `absl::LogSeverity` values, ordered from |
| // least to most severe. |
| constexpr std::array<absl::LogSeverity, 4> LogSeverities() { |
| return {{absl::LogSeverity::kInfo, absl::LogSeverity::kWarning, |
| absl::LogSeverity::kError, absl::LogSeverity::kFatal}}; |
| } |
| |
| // `absl::kLogDebugFatal` equals `absl::LogSeverity::kFatal` in debug builds |
| // (i.e. when `NDEBUG` is not defined) and `absl::LogSeverity::kError` |
| // otherwise. Avoid ODR-using this variable as it has internal linkage and thus |
| // distinct storage in different TUs. |
| #ifdef NDEBUG |
| static constexpr absl::LogSeverity kLogDebugFatal = absl::LogSeverity::kError; |
| #else |
| static constexpr absl::LogSeverity kLogDebugFatal = absl::LogSeverity::kFatal; |
| #endif |
| |
| // LogSeverityName() |
| // |
| // Returns the all-caps string representation (e.g. "INFO") of the specified |
| // severity level if it is one of the standard levels and "UNKNOWN" otherwise. |
| constexpr const char* LogSeverityName(absl::LogSeverity s) { |
| switch (s) { |
| case absl::LogSeverity::kInfo: return "INFO"; |
| case absl::LogSeverity::kWarning: return "WARNING"; |
| case absl::LogSeverity::kError: return "ERROR"; |
| case absl::LogSeverity::kFatal: return "FATAL"; |
| } |
| return "UNKNOWN"; |
| } |
| |
| // NormalizeLogSeverity() |
| // |
| // Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal` |
| // normalize to `kError` (**NOT** `kFatal`). |
| constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) { |
| absl::LogSeverity n = s; |
| if (n < absl::LogSeverity::kInfo) n = absl::LogSeverity::kInfo; |
| if (n > absl::LogSeverity::kFatal) n = absl::LogSeverity::kError; |
| return n; |
| } |
| constexpr absl::LogSeverity NormalizeLogSeverity(int s) { |
| return absl::NormalizeLogSeverity(static_cast<absl::LogSeverity>(s)); |
| } |
| |
| // operator<< |
| // |
| // The exact representation of a streamed `absl::LogSeverity` is deliberately |
| // unspecified; do not rely on it. |
| std::ostream& operator<<(std::ostream& os, absl::LogSeverity s); |
| |
| // Enums representing a lower bound for LogSeverity. APIs that only operate on |
| // messages of at least a certain level (for example, `SetMinLogLevel()`) use |
| // this type to specify that level. absl::LogSeverityAtLeast::kInfinity is |
| // a level above all threshold levels and therefore no log message will |
| // ever meet this threshold. |
| enum class LogSeverityAtLeast : int { |
| kInfo = static_cast<int>(absl::LogSeverity::kInfo), |
| kWarning = static_cast<int>(absl::LogSeverity::kWarning), |
| kError = static_cast<int>(absl::LogSeverity::kError), |
| kFatal = static_cast<int>(absl::LogSeverity::kFatal), |
| kInfinity = 1000, |
| }; |
| |
| std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtLeast s); |
| |
| // Enums representing an upper bound for LogSeverity. APIs that only operate on |
| // messages of at most a certain level (for example, buffer all messages at or |
| // below a certain level) use this type to specify that level. |
| // absl::LogSeverityAtMost::kNegativeInfinity is a level below all threshold |
| // levels and therefore will exclude all log messages. |
| enum class LogSeverityAtMost : int { |
| kNegativeInfinity = -1000, |
| kInfo = static_cast<int>(absl::LogSeverity::kInfo), |
| kWarning = static_cast<int>(absl::LogSeverity::kWarning), |
| kError = static_cast<int>(absl::LogSeverity::kError), |
| kFatal = static_cast<int>(absl::LogSeverity::kFatal), |
| }; |
| |
| std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtMost s); |
| |
| #define COMPOP(op1, op2, T) \ |
| constexpr bool operator op1(absl::T lhs, absl::LogSeverity rhs) { \ |
| return static_cast<absl::LogSeverity>(lhs) op1 rhs; \ |
| } \ |
| constexpr bool operator op2(absl::LogSeverity lhs, absl::T rhs) { \ |
| return lhs op2 static_cast<absl::LogSeverity>(rhs); \ |
| } |
| |
| // Comparisons between `LogSeverity` and `LogSeverityAtLeast`/ |
| // `LogSeverityAtMost` are only supported in one direction. |
| // Valid checks are: |
| // LogSeverity >= LogSeverityAtLeast |
| // LogSeverity < LogSeverityAtLeast |
| // LogSeverity <= LogSeverityAtMost |
| // LogSeverity > LogSeverityAtMost |
| COMPOP(>, <, LogSeverityAtLeast) |
| COMPOP(<=, >=, LogSeverityAtLeast) |
| COMPOP(<, >, LogSeverityAtMost) |
| COMPOP(>=, <=, LogSeverityAtMost) |
| #undef COMPOP |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_LOG_SEVERITY_H_ |
| *øl |
| nsoong/.intermediates/external/abseil-cpp/absl_base_nullability_hdrs/gen/my_include_dir/absl/base/nullability.h
l// Copyright 2023 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: nullability.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header file defines a set of annotations for designating the expected |
| // nullability of pointers. These annotations allow you to designate pointers in |
| // one of three classification states: |
| // |
| // * "Non-null" (for pointers annotated `absl_nonnull`), indicating that it is |
| // invalid for the given pointer to ever be null. |
| // * "Nullable" (for pointers annotated `absl_nullable`), indicating that it is |
| // valid for the given pointer to be null. |
| // * "Unknown" (for pointers annotated `absl_nullability_unknown`), indicating |
| // that the given pointer has not yet been classified as either nullable or |
| // non-null. This is the default state of unannotated pointers. |
| // |
| // NOTE: Unannotated pointers implicitly bear the annotation |
| // `absl_nullability_unknown`; you should rarely, if ever, see this annotation |
| // used in the codebase explicitly. |
| // |
| // ----------------------------------------------------------------------------- |
| // Nullability and Contracts |
| // ----------------------------------------------------------------------------- |
| // |
| // These nullability annotations allow you to more clearly specify contracts on |
| // software components by narrowing the *preconditions*, *postconditions*, and |
| // *invariants* of pointer state(s) in any given interface. It then depends on |
| // context who is responsible for fulfilling the annotation's requirements. |
| // |
| // For example, a function may receive a pointer argument. Designating that |
| // pointer argument as "non-null" tightens the precondition of the contract of |
| // that function. It is then the responsibility of anyone calling such a |
| // function to ensure that the passed pointer is not null. |
| // |
| // Similarly, a function may have a pointer as a return value. Designating that |
| // return value as "non-null" tightens the postcondition of the contract of that |
| // function. In this case, however, it is the responsibility of the function |
| // itself to ensure that the returned pointer is not null. |
| // |
| // Clearly defining these contracts allows providers (and consumers) of such |
| // pointers to have more confidence in their null state. If a function declares |
| // a return value as "non-null", for example, the caller should not need to |
| // check whether the returned value is `nullptr`; it can simply assume the |
| // pointer is valid. |
| // |
| // Of course most interfaces already have expectations on the nullability state |
| // of pointers, and these expectations are, in effect, a contract; often, |
| // however, those contracts are either poorly or partially specified, assumed, |
| // or misunderstood. These nullability annotations are designed to allow you to |
| // formalize those contracts within the codebase. |
| // |
| // ----------------------------------------------------------------------------- |
| // Annotation Syntax |
| // ----------------------------------------------------------------------------- |
| // |
| // The annotations should be positioned as a qualifier for the pointer type. For |
| // example, the position of `const` when declaring a const pointer (not a |
| // pointer to a const type) is the position you should also use for these |
| // annotations. |
| // |
| // Example: |
| // |
| // // A const non-null pointer to an `Employee`. |
| // Employee* absl_nonnull const e; |
| // |
| // // A non-null pointer to a const `Employee`. |
| // const Employee* absl_nonnull e; |
| // |
| // // A non-null pointer to a const nullable pointer to an `Employee`. |
| // Employee* absl_nullable const* absl_nonnull e = nullptr; |
| // |
| // // A non-null function pointer. |
| // void (*absl_nonnull func)(int, double); |
| // |
| // // A non-null array of `Employee`s as a parameter. |
| // void func(Employee employees[absl_nonnull]); |
| // |
| // // A non-null std::unique_ptr to an `Employee`. |
| // // As with `const`, it is possible to place the annotation on either side of |
| // // a named type not ending in `*`, but placing it before the type it |
| // // describes is preferred, unless inconsistent with surrounding code. |
| // absl_nonnull std::unique_ptr<Employee> employee; |
| // |
| // // Invalid annotation usage â this attempts to declare a pointer to a |
| // // nullable `Employee`, which is meaningless. |
| // absl_nullable Employee* e; |
| // |
| // ----------------------------------------------------------------------------- |
| // Using Nullability Annotations |
| // ----------------------------------------------------------------------------- |
| // |
| // Each annotation acts as a form of documentation about the contract for the |
| // given pointer. Each annotation requires providers or consumers of these |
| // pointers across API boundaries to take appropriate steps when setting or |
| // using these pointers: |
| // |
| // * "Non-null" pointers should never be null. It is the responsibility of the |
| // provider of this pointer to ensure that the pointer may never be set to |
| // null. Consumers of such pointers can treat such pointers as non-null. |
| // * "Nullable" pointers may or may not be null. Consumers of such pointers |
| // should precede any usage of that pointer (e.g. a dereference operation) |
| // with a a `nullptr` check. |
| // * "Unknown" pointers may be either "non-null" or "nullable" but have not been |
| // definitively determined to be in either classification state. Providers of |
| // such pointers across API boundaries should determine -- over time -- to |
| // annotate the pointer in either of the above two states. Consumers of such |
| // pointers across an API boundary should continue to treat such pointers as |
| // they currently do. |
| // |
| // Example: |
| // |
| // // PaySalary() requires the passed pointer to an `Employee` to be non-null. |
| // void PaySalary(Employee* absl_nonnull e) { |
| // pay(e->salary); // OK to dereference |
| // } |
| // |
| // // CompleteTransaction() guarantees the returned pointer to an `Account` to |
| // // be non-null. |
| // Account* absl_nonnull balance CompleteTransaction(double fee) { |
| // ... |
| // } |
| // |
| // // Note that specifying a nullability annotation does not prevent someone |
| // // from violating the contract: |
| // |
| // Employee* absl_nullable find(Map& employees, std::string_view name); |
| // |
| // void g(Map& employees) { |
| // Employee *e = find(employees, "Pat"); |
| // // `e` can now be null. |
| // PaySalary(e); // Violates contract, but compiles! |
| // } |
| // |
| // Nullability annotations, in other words, are useful for defining and |
| // narrowing contracts; *enforcement* of those contracts depends on use and any |
| // additional (static or dynamic analysis) tooling. |
| // |
| // NOTE: The "unknown" annotation state indicates that a pointer's contract has |
| // not yet been positively identified. The unknown state therefore acts as a |
| // form of documentation of your technical debt, and a codebase that adopts |
| // nullability annotations should aspire to annotate every pointer as either |
| // "non-null" or "nullable". |
| // |
| // ----------------------------------------------------------------------------- |
| // Applicability of Nullability Annotations |
| // ----------------------------------------------------------------------------- |
| // |
| // By default, nullability annotations are applicable to raw and smart |
| // pointers. User-defined types can indicate compatibility with nullability |
| // annotations by adding the ABSL_NULLABILITY_COMPATIBLE attribute. |
| // |
| // // Example: |
| // struct ABSL_NULLABILITY_COMPATIBLE MyPtr { |
| // ... |
| // }; |
| // |
| // Note: Compilers that don't support the `nullability_on_classes` feature will |
| // allow nullability annotations to be applied to any type, not just ones |
| // marked with `ABSL_NULLABILITY_COMPATIBLE`. |
| // |
| // DISCLAIMER: |
| // =========================================================================== |
| // These nullability annotations are primarily a human readable signal about the |
| // intended contract of the pointer. They are not *types* and do not currently |
| // provide any correctness guarantees. For example, a pointer annotated as |
| // `absl_nonnull` is *not guaranteed* to be non-null, and the compiler won't |
| // alert or prevent assignment of a `T* absl_nullable` to a `T* absl_nonnull`. |
| // =========================================================================== |
| #ifndef ABSL_BASE_NULLABILITY_H_ |
| #define ABSL_BASE_NULLABILITY_H_ |
| |
| #include "absl/base/config.h" |
| #include "absl/base/internal/nullability_deprecated.h" |
| |
| // ABSL_POINTERS_DEFAULT_NONNULL |
| // |
| // This macro specifies that all unannotated pointer types within the given |
| // file are designated as nonnull (instead of the default "unknown"). This macro |
| // exists as a standalone statement and applies default nonnull behavior to all |
| // subsequent pointers; as a result, place this macro as the first non-comment, |
| // non-`#include` line in a file. |
| // |
| // Example: |
| // |
| // #include "absl/base/nullability.h" |
| // |
| // ABSL_POINTERS_DEFAULT_NONNULL |
| // |
| // void FillMessage(Message *m); // implicitly non-null |
| // T* absl_nullable GetNullablePtr(); // explicitly nullable |
| // T* absl_nullability_unknown GetUnknownPtr(); // explicitly unknown |
| // |
| // The macro can be safely used in header files â it will not affect any files |
| // that include it. |
| // |
| // In files with the macro, plain `T*` syntax means `T* absl_nonnull`, and the |
| // exceptions (`absl_nullable` and `absl_nullability_unknown`) must be marked |
| // explicitly. The same holds, correspondingly, for smart pointer types. |
| // |
| // For comparison, without the macro, all unannotated pointers would default to |
| // unknown, and otherwise require explicit annotations to change this behavior: |
| // |
| // #include "absl/base/nullability.h" |
| // |
| // void FillMessage(Message* absl_nonnull m); // explicitly non-null |
| // T* absl_nullable GetNullablePtr(); // explicitly nullable |
| // T* GetUnknownPtr(); // implicitly unknown |
| // |
| // No-op except for being a human readable signal. |
| #define ABSL_POINTERS_DEFAULT_NONNULL |
| |
| #if defined(__clang__) && !defined(__OBJC__) && \ |
| ABSL_HAVE_FEATURE(nullability_on_classes) |
| // absl_nonnull (default with `ABSL_POINTERS_DEFAULT_NONNULL`) |
| // |
| // The indicated pointer is never null. It is the responsibility of the provider |
| // of this pointer across an API boundary to ensure that the pointer is never |
| // set to null. Consumers of this pointer across an API boundary may safely |
| // dereference the pointer. |
| // |
| // Example: |
| // |
| // // `employee` is designated as not null. |
| // void PaySalary(Employee* absl_nonnull employee) { |
| // pay(*employee); // OK to dereference |
| // } |
| #define absl_nonnull _Nonnull |
| |
| // absl_nullable |
| // |
| // The indicated pointer may, by design, be either null or non-null. Consumers |
| // of this pointer across an API boundary should perform a `nullptr` check |
| // before performing any operation using the pointer. |
| // |
| // Example: |
| // |
| // // `employee` may be null. |
| // void PaySalary(Employee* absl_nullable employee) { |
| // if (employee != nullptr) { |
| // Pay(*employee); // OK to dereference |
| // } |
| // } |
| #define absl_nullable _Nullable |
| |
| // absl_nullability_unknown (default without `ABSL_POINTERS_DEFAULT_NONNULL`) |
| // |
| // The indicated pointer has not yet been determined to be definitively |
| // "non-null" or "nullable." Providers of such pointers across API boundaries |
| // should, over time, annotate such pointers as either "non-null" or "nullable." |
| // Consumers of these pointers across an API boundary should treat such pointers |
| // with the same caution they treat currently unannotated pointers. Most |
| // existing code will have "unknown" pointers, which should eventually be |
| // migrated into one of the above two nullability states: `absl_nonnull` or |
| // `absl_nullable`. |
| // |
| // NOTE: For files that do not specify `ABSL_POINTERS_DEFAULT_NONNULL`, |
| // because this annotation is the global default state, unannotated pointers are |
| // are assumed to have "unknown" semantics. This assumption is designed to |
| // minimize churn and reduce clutter within the codebase. |
| // |
| // Example: |
| // |
| // // `employee`s nullability state is unknown. |
| // void PaySalary(Employee* absl_nullability_unknown employee) { |
| // Pay(*employee); // Potentially dangerous. API provider should investigate. |
| // } |
| // |
| // Note that a pointer without an annotation, by default, is assumed to have the |
| // annotation `NullabilityUnknown`. |
| // |
| // // `employee`s nullability state is unknown. |
| // void PaySalary(Employee* employee) { |
| // Pay(*employee); // Potentially dangerous. API provider should investigate. |
| // } |
| #define absl_nullability_unknown _Null_unspecified |
| #else |
| // No-op for non-Clang compilers or Objective-C. |
| #define absl_nonnull |
| // No-op for non-Clang compilers or Objective-C. |
| #define absl_nullable |
| // No-op for non-Clang compilers or Objective-C. |
| #define absl_nullability_unknown |
| #endif |
| |
| // ABSL_NULLABILITY_COMPATIBLE |
| // |
| // Indicates that a class is compatible with nullability annotations. |
| // |
| // For example: |
| // |
| // struct ABSL_NULLABILITY_COMPATIBLE MyPtr { |
| // ... |
| // }; |
| // |
| // Note: Compilers that don't support the `nullability_on_classes` feature will |
| // allow nullability annotations to be applied to any type, not just ones marked |
| // with `ABSL_NULLABILITY_COMPATIBLE`. |
| #if ABSL_HAVE_FEATURE(nullability_on_classes) |
| #define ABSL_NULLABILITY_COMPATIBLE _Nullable |
| #else |
| #define ABSL_NULLABILITY_COMPATIBLE |
| #endif |
| |
| #endif // ABSL_BASE_NULLABILITY_H_ |
| *м |
| dsoong/.intermediates/external/abseil-cpp/absl_strings_hdrs/gen/my_include_dir/absl/strings/str_cat.hæ»// |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: str_cat.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This package contains functions for efficiently concatenating and appending |
| // strings: `StrCat()` and `StrAppend()`. Most of the work within these routines |
| // is actually handled through use of a special AlphaNum type, which was |
| // designed to be used as a parameter type that efficiently manages conversion |
| // to strings and avoids copies in the above operations. |
| // |
| // Any routine accepting either a string or a number may accept `AlphaNum`. |
| // The basic idea is that by accepting a `const AlphaNum &` as an argument |
| // to your function, your callers will automagically convert bools, integers, |
| // and floating point values to strings for you. |
| // |
| // NOTE: Use of `AlphaNum` outside of the //absl/strings package is unsupported |
| // except for the specific case of function parameters of type `AlphaNum` or |
| // `const AlphaNum &`. In particular, instantiating `AlphaNum` directly as a |
| // stack variable is not supported. |
| // |
| // Conversion from 8-bit values is not accepted because, if it were, then an |
| // attempt to pass ':' instead of ":" might result in a 58 ending up in your |
| // result. |
| // |
| // Bools convert to "0" or "1". Pointers to types other than `char *` are not |
| // valid inputs. No output is generated for null `char *` pointers. |
| // |
| // Floating point numbers are formatted with six-digit precision, which is |
| // the default for "std::cout <<" or printf "%g" (the same as "%.6g"). |
| // |
| // You can convert to hexadecimal output rather than decimal output using the |
| // `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to |
| // `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using |
| // a `PadSpec` enum. |
| // |
| // User-defined types can be formatted with the `AbslStringify()` customization |
| // point. The API relies on detecting an overload in the user-defined type's |
| // namespace of a free (non-member) `AbslStringify()` function as a definition |
| // (typically declared as a friend and implemented in-line. |
| // with the following signature: |
| // |
| // class MyClass { ... }; |
| // |
| // template <typename Sink> |
| // void AbslStringify(Sink& sink, const MyClass& value); |
| // |
| // An `AbslStringify()` overload for a type should only be declared in the same |
| // file and namespace as said type. |
| // |
| // Note that `AbslStringify()` also supports use with `absl::StrFormat()` and |
| // `absl::Substitute()`. |
| // |
| // Example: |
| // |
| // struct Point { |
| // // To add formatting support to `Point`, we simply need to add a free |
| // // (non-member) function `AbslStringify()`. This method specifies how |
| // // Point should be printed when absl::StrCat() is called on it. You can add |
| // // such a free function using a friend declaration within the body of the |
| // // class. The sink parameter is a templated type to avoid requiring |
| // // dependencies. |
| // template <typename Sink> friend void AbslStringify(Sink& |
| // sink, const Point& p) { |
| // absl::Format(&sink, "(%v, %v)", p.x, p.y); |
| // } |
| // |
| // int x; |
| // int y; |
| // }; |
| // ----------------------------------------------------------------------------- |
| |
| #ifndef ABSL_STRINGS_STR_CAT_H_ |
| #define ABSL_STRINGS_STR_CAT_H_ |
| |
| #include <algorithm> |
| #include <array> |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <initializer_list> |
| #include <limits> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/port.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/strings/has_absl_stringify.h" |
| #include "absl/strings/internal/resize_uninitialized.h" |
| #include "absl/strings/internal/stringify_sink.h" |
| #include "absl/strings/numbers.h" |
| #include "absl/strings/string_view.h" |
| |
| #if !defined(ABSL_USES_STD_STRING_VIEW) |
| #include <string_view> |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| namespace strings_internal { |
| // AlphaNumBuffer allows a way to pass a string to StrCat without having to do |
| // memory allocation. It is simply a pair of a fixed-size character array, and |
| // a size. Please don't use outside of absl, yet. |
| template <size_t max_size> |
| struct AlphaNumBuffer { |
| std::array<char, max_size> data; |
| size_t size; |
| }; |
| |
| } // namespace strings_internal |
| |
| // Enum that specifies the number of significant digits to return in a `Hex` or |
| // `Dec` conversion and fill character to use. A `kZeroPad2` value, for example, |
| // would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value |
| // would produce hexadecimal strings such as " a"," f". |
| enum PadSpec : uint8_t { |
| kNoPad = 1, |
| kZeroPad2, |
| kZeroPad3, |
| kZeroPad4, |
| kZeroPad5, |
| kZeroPad6, |
| kZeroPad7, |
| kZeroPad8, |
| kZeroPad9, |
| kZeroPad10, |
| kZeroPad11, |
| kZeroPad12, |
| kZeroPad13, |
| kZeroPad14, |
| kZeroPad15, |
| kZeroPad16, |
| kZeroPad17, |
| kZeroPad18, |
| kZeroPad19, |
| kZeroPad20, |
| |
| kSpacePad2 = kZeroPad2 + 64, |
| kSpacePad3, |
| kSpacePad4, |
| kSpacePad5, |
| kSpacePad6, |
| kSpacePad7, |
| kSpacePad8, |
| kSpacePad9, |
| kSpacePad10, |
| kSpacePad11, |
| kSpacePad12, |
| kSpacePad13, |
| kSpacePad14, |
| kSpacePad15, |
| kSpacePad16, |
| kSpacePad17, |
| kSpacePad18, |
| kSpacePad19, |
| kSpacePad20, |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // Hex |
| // ----------------------------------------------------------------------------- |
| // |
| // `Hex` stores a set of hexadecimal string conversion parameters for use |
| // within `AlphaNum` string conversions. |
| struct Hex { |
| uint64_t value; |
| uint8_t width; |
| char fill; |
| |
| template <typename Int> |
| explicit Hex( |
| Int v, PadSpec spec = absl::kNoPad, |
| std::enable_if_t<sizeof(Int) == 1 && !std::is_pointer<Int>::value, bool> = |
| true) |
| : Hex(spec, static_cast<uint8_t>(v)) {} |
| template <typename Int> |
| explicit Hex( |
| Int v, PadSpec spec = absl::kNoPad, |
| std::enable_if_t<sizeof(Int) == 2 && !std::is_pointer<Int>::value, bool> = |
| true) |
| : Hex(spec, static_cast<uint16_t>(v)) {} |
| template <typename Int> |
| explicit Hex( |
| Int v, PadSpec spec = absl::kNoPad, |
| std::enable_if_t<sizeof(Int) == 4 && !std::is_pointer<Int>::value, bool> = |
| true) |
| : Hex(spec, static_cast<uint32_t>(v)) {} |
| template <typename Int> |
| explicit Hex( |
| Int v, PadSpec spec = absl::kNoPad, |
| std::enable_if_t<sizeof(Int) == 8 && !std::is_pointer<Int>::value, bool> = |
| true) |
| : Hex(spec, static_cast<uint64_t>(v)) {} |
| template <typename Pointee> |
| explicit Hex(Pointee* absl_nullable v, PadSpec spec = absl::kNoPad) |
| : Hex(spec, reinterpret_cast<uintptr_t>(v)) {} |
| |
| template <typename S> |
| friend void AbslStringify(S& sink, Hex hex) { |
| static_assert( |
| numbers_internal::kFastToBufferSize >= 32, |
| "This function only works when output buffer >= 32 bytes long"); |
| char buffer[numbers_internal::kFastToBufferSize]; |
| char* const end = &buffer[numbers_internal::kFastToBufferSize]; |
| auto real_width = |
| absl::numbers_internal::FastHexToBufferZeroPad16(hex.value, end - 16); |
| if (real_width >= hex.width) { |
| sink.Append(absl::string_view(end - real_width, real_width)); |
| } else { |
| // Pad first 16 chars because FastHexToBufferZeroPad16 pads only to 16 and |
| // max pad width can be up to 20. |
| std::memset(end - 32, hex.fill, 16); |
| // Patch up everything else up to the real_width. |
| std::memset(end - real_width - 16, hex.fill, 16); |
| sink.Append(absl::string_view(end - hex.width, hex.width)); |
| } |
| } |
| |
| private: |
| Hex(PadSpec spec, uint64_t v) |
| : value(v), |
| width(spec == absl::kNoPad |
| ? 1 |
| : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2 |
| : spec - absl::kZeroPad2 + 2), |
| fill(spec >= absl::kSpacePad2 ? ' ' : '0') {} |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // Dec |
| // ----------------------------------------------------------------------------- |
| // |
| // `Dec` stores a set of decimal string conversion parameters for use |
| // within `AlphaNum` string conversions. Dec is slower than the default |
| // integer conversion, so use it only if you need padding. |
| struct Dec { |
| uint64_t value; |
| uint8_t width; |
| char fill; |
| bool neg; |
| |
| template <typename Int> |
| explicit Dec(Int v, PadSpec spec = absl::kNoPad, |
| std::enable_if_t<sizeof(Int) <= 8, bool> = true) |
| : value(v >= 0 ? static_cast<uint64_t>(v) |
| : uint64_t{0} - static_cast<uint64_t>(v)), |
| width(spec == absl::kNoPad ? 1 |
| : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2 |
| : spec - absl::kZeroPad2 + 2), |
| fill(spec >= absl::kSpacePad2 ? ' ' : '0'), |
| neg(v < 0) {} |
| |
| template <typename S> |
| friend void AbslStringify(S& sink, Dec dec) { |
| assert(dec.width <= numbers_internal::kFastToBufferSize); |
| char buffer[numbers_internal::kFastToBufferSize]; |
| char* const end = &buffer[numbers_internal::kFastToBufferSize]; |
| char* const minfill = end - dec.width; |
| char* writer = end; |
| uint64_t val = dec.value; |
| while (val > 9) { |
| *--writer = '0' + (val % 10); |
| val /= 10; |
| } |
| *--writer = '0' + static_cast<char>(val); |
| if (dec.neg) *--writer = '-'; |
| |
| ptrdiff_t fillers = writer - minfill; |
| if (fillers > 0) { |
| // Tricky: if the fill character is ' ', then it's <fill><+/-><digits> |
| // But...: if the fill character is '0', then it's <+/-><fill><digits> |
| bool add_sign_again = false; |
| if (dec.neg && dec.fill == '0') { // If filling with '0', |
| ++writer; // ignore the sign we just added |
| add_sign_again = true; // and re-add the sign later. |
| } |
| writer -= fillers; |
| std::fill_n(writer, fillers, dec.fill); |
| if (add_sign_again) *--writer = '-'; |
| } |
| |
| sink.Append(absl::string_view(writer, static_cast<size_t>(end - writer))); |
| } |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // AlphaNum |
| // ----------------------------------------------------------------------------- |
| // |
| // The `AlphaNum` class acts as the main parameter type for `StrCat()` and |
| // `StrAppend()`, providing efficient conversion of numeric, boolean, decimal, |
| // and hexadecimal values (through the `Dec` and `Hex` types) into strings. |
| // `AlphaNum` should only be used as a function parameter. Do not instantiate |
| // `AlphaNum` directly as a stack variable. |
| |
| class AlphaNum { |
| public: |
| // No bool ctor -- bools convert to an integral type. |
| // A bool ctor would also convert incoming pointers (bletch). |
| |
| // Prevent brace initialization |
| template <typename T> |
| AlphaNum(std::initializer_list<T>) = delete; // NOLINT(runtime/explicit) |
| |
| AlphaNum(int x) // NOLINT(runtime/explicit) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
| AlphaNum(unsigned int x) // NOLINT(runtime/explicit) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
| AlphaNum(long x) // NOLINT(*) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
| AlphaNum(unsigned long x) // NOLINT(*) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
| AlphaNum(long long x) // NOLINT(*) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
| AlphaNum(unsigned long long x) // NOLINT(*) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
| |
| AlphaNum(float f) // NOLINT(runtime/explicit) |
| : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} |
| AlphaNum(double f) // NOLINT(runtime/explicit) |
| : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} |
| |
| template <size_t size> |
| AlphaNum( // NOLINT(runtime/explicit) |
| const strings_internal::AlphaNumBuffer<size>& buf |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| : piece_(&buf.data[0], buf.size) {} |
| |
| AlphaNum(const char* absl_nullable c_str // NOLINT(runtime/explicit) |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| : piece_(NullSafeStringView(c_str)) {} |
| AlphaNum(absl::string_view pc // NOLINT(runtime/explicit) |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| : piece_(pc) {} |
| |
| #if !defined(ABSL_USES_STD_STRING_VIEW) |
| AlphaNum(std::string_view pc // NOLINT(runtime/explicit) |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| : piece_(pc.data(), pc.size()) {} |
| #endif // !ABSL_USES_STD_STRING_VIEW |
| |
| template <typename T, typename = typename std::enable_if< |
| HasAbslStringify<T>::value>::type> |
| AlphaNum( // NOLINT(runtime/explicit) |
| const T& v ABSL_ATTRIBUTE_LIFETIME_BOUND, |
| strings_internal::StringifySink&& sink ABSL_ATTRIBUTE_LIFETIME_BOUND = {}) |
| : piece_(strings_internal::ExtractStringification(sink, v)) {} |
| |
| template <typename Allocator> |
| AlphaNum( // NOLINT(runtime/explicit) |
| const std::basic_string<char, std::char_traits<char>, Allocator>& str |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| : piece_(str) {} |
| |
| // Use string literals ":" instead of character literals ':'. |
| AlphaNum(char c) = delete; // NOLINT(runtime/explicit) |
| |
| AlphaNum(const AlphaNum&) = delete; |
| AlphaNum& operator=(const AlphaNum&) = delete; |
| |
| absl::string_view::size_type size() const { return piece_.size(); } |
| const char* absl_nullable data() const { return piece_.data(); } |
| absl::string_view Piece() const { return piece_; } |
| |
| // Match unscoped enums. Use integral promotion so that a `char`-backed |
| // enum becomes a wider integral type AlphaNum will accept. |
| template <typename T, |
| typename = typename std::enable_if< |
| std::is_enum<T>{} && std::is_convertible<T, int>{} && |
| !HasAbslStringify<T>::value>::type> |
| AlphaNum(T e) // NOLINT(runtime/explicit) |
| : AlphaNum(+e) {} |
| |
| // This overload matches scoped enums. We must explicitly cast to the |
| // underlying type, but use integral promotion for the same reason as above. |
| template <typename T, |
| typename std::enable_if<std::is_enum<T>{} && |
| !std::is_convertible<T, int>{} && |
| !HasAbslStringify<T>::value, |
| char*>::type = nullptr> |
| AlphaNum(T e) // NOLINT(runtime/explicit) |
| : AlphaNum(+static_cast<typename std::underlying_type<T>::type>(e)) {} |
| |
| // vector<bool>::reference and const_reference require special help to |
| // convert to `AlphaNum` because it requires two user defined conversions. |
| template < |
| typename T, |
| typename std::enable_if< |
| std::is_class<T>::value && |
| (std::is_same<T, std::vector<bool>::reference>::value || |
| std::is_same<T, std::vector<bool>::const_reference>::value)>::type* = |
| nullptr> |
| AlphaNum(T e) : AlphaNum(static_cast<bool>(e)) {} // NOLINT(runtime/explicit) |
| |
| private: |
| absl::string_view piece_; |
| char digits_[numbers_internal::kFastToBufferSize]; |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // StrCat() |
| // ----------------------------------------------------------------------------- |
| // |
| // Merges given strings or numbers, using no delimiter(s), returning the merged |
| // result as a string. |
| // |
| // `StrCat()` is designed to be the fastest possible way to construct a string |
| // out of a mix of raw C strings, string_views, strings, bool values, |
| // and numeric values. |
| // |
| // Don't use `StrCat()` for user-visible strings. The localization process |
| // works poorly on strings built up out of fragments. |
| // |
| // For clarity and performance, don't use `StrCat()` when appending to a |
| // string. Use `StrAppend()` instead. In particular, avoid using any of these |
| // (anti-)patterns: |
| // |
| // str.append(StrCat(...)) |
| // str += StrCat(...) |
| // str = StrCat(str, ...) |
| // |
| // The last case is the worst, with a potential to change a loop |
| // from a linear time operation with O(1) dynamic allocations into a |
| // quadratic time operation with O(n) dynamic allocations. |
| // |
| // See `StrAppend()` below for more information. |
| |
| namespace strings_internal { |
| |
| // Do not call directly - this is not part of the public API. |
| std::string CatPieces(std::initializer_list<absl::string_view> pieces); |
| void AppendPieces(std::string* absl_nonnull dest, |
| std::initializer_list<absl::string_view> pieces); |
| |
| template <typename Integer> |
| std::string IntegerToString(Integer i) { |
| // Any integer (signed/unsigned) up to 64 bits can be formatted into a buffer |
| // with 22 bytes (including NULL at the end). |
| constexpr size_t kMaxDigits10 = 22; |
| std::string result; |
| strings_internal::STLStringResizeUninitialized(&result, kMaxDigits10); |
| char* start = &result[0]; |
| // note: this can be optimized to not write last zero. |
| char* end = numbers_internal::FastIntToBuffer(i, start); |
| auto size = static_cast<size_t>(end - start); |
| assert((size < result.size()) && |
| "StrCat(Integer) does not fit into kMaxDigits10"); |
| result.erase(size); |
| return result; |
| } |
| template <typename Float> |
| std::string FloatToString(Float f) { |
| std::string result; |
| strings_internal::STLStringResizeUninitialized( |
| &result, numbers_internal::kSixDigitsToBufferSize); |
| char* start = &result[0]; |
| result.erase(numbers_internal::SixDigitsToBuffer(f, start)); |
| return result; |
| } |
| |
| // `SingleArgStrCat` overloads take built-in `int`, `long` and `long long` types |
| // (signed / unsigned) to avoid ambiguity on the call side. If we used int32_t |
| // and int64_t, then at least one of the three (`int` / `long` / `long long`) |
| // would have been ambiguous when passed to `SingleArgStrCat`. |
| inline std::string SingleArgStrCat(int x) { return IntegerToString(x); } |
| inline std::string SingleArgStrCat(unsigned int x) { |
| return IntegerToString(x); |
| } |
| // NOLINTNEXTLINE |
| inline std::string SingleArgStrCat(long x) { return IntegerToString(x); } |
| // NOLINTNEXTLINE |
| inline std::string SingleArgStrCat(unsigned long x) { |
| return IntegerToString(x); |
| } |
| // NOLINTNEXTLINE |
| inline std::string SingleArgStrCat(long long x) { return IntegerToString(x); } |
| // NOLINTNEXTLINE |
| inline std::string SingleArgStrCat(unsigned long long x) { |
| return IntegerToString(x); |
| } |
| inline std::string SingleArgStrCat(float x) { return FloatToString(x); } |
| inline std::string SingleArgStrCat(double x) { return FloatToString(x); } |
| |
| // As of September 2023, the SingleArgStrCat() optimization is only enabled for |
| // libc++. The reasons for this are: |
| // 1) The SSO size for libc++ is 23, while libstdc++ and MSSTL have an SSO size |
| // of 15. Since IntegerToString unconditionally resizes the string to 22 bytes, |
| // this causes both libstdc++ and MSSTL to allocate. |
| // 2) strings_internal::STLStringResizeUninitialized() only has an |
| // implementation that avoids initialization when using libc++. This isn't as |
| // relevant as (1), and the cost should be benchmarked if (1) ever changes on |
| // libstc++ or MSSTL. |
| #ifdef _LIBCPP_VERSION |
| #define ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE true |
| #else |
| #define ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE false |
| #endif |
| |
| template <typename T, typename = std::enable_if_t< |
| ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE && |
| std::is_arithmetic<T>{} && !std::is_same<T, char>{}>> |
| using EnableIfFastCase = T; |
| |
| #undef ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE |
| |
| } // namespace strings_internal |
| |
| [[nodiscard]] inline std::string StrCat() { return std::string(); } |
| |
| template <typename T> |
| [[nodiscard]] inline std::string StrCat( |
| strings_internal::EnableIfFastCase<T> a) { |
| return strings_internal::SingleArgStrCat(a); |
| } |
| [[nodiscard]] inline std::string StrCat(const AlphaNum& a) { |
| return std::string(a.data(), a.size()); |
| } |
| |
| [[nodiscard]] std::string StrCat(const AlphaNum& a, const AlphaNum& b); |
| [[nodiscard]] std::string StrCat(const AlphaNum& a, const AlphaNum& b, |
| const AlphaNum& c); |
| [[nodiscard]] std::string StrCat(const AlphaNum& a, const AlphaNum& b, |
| const AlphaNum& c, const AlphaNum& d); |
| |
| // Support 5 or more arguments |
| template <typename... AV> |
| [[nodiscard]] inline std::string StrCat(const AlphaNum& a, const AlphaNum& b, |
| const AlphaNum& c, const AlphaNum& d, |
| const AlphaNum& e, const AV&... args) { |
| return strings_internal::CatPieces( |
| {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), |
| static_cast<const AlphaNum&>(args).Piece()...}); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| // StrAppend() |
| // ----------------------------------------------------------------------------- |
| // |
| // Appends a string or set of strings to an existing string, in a similar |
| // fashion to `StrCat()`. |
| // |
| // WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the |
| // a, b, c, parameters be a reference into str. For speed, `StrAppend()` does |
| // not try to check each of its input arguments to be sure that they are not |
| // a subset of the string being appended to. That is, while this will work: |
| // |
| // std::string s = "foo"; |
| // s += s; |
| // |
| // This output is undefined: |
| // |
| // std::string s = "foo"; |
| // StrAppend(&s, s); |
| // |
| // This output is undefined as well, since `absl::string_view` does not own its |
| // data: |
| // |
| // std::string s = "foobar"; |
| // absl::string_view p = s; |
| // StrAppend(&s, p); |
| |
| inline void StrAppend(std::string* absl_nonnull) {} |
| void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a); |
| void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a, |
| const AlphaNum& b); |
| void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a, |
| const AlphaNum& b, const AlphaNum& c); |
| void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a, |
| const AlphaNum& b, const AlphaNum& c, const AlphaNum& d); |
| |
| // Support 5 or more arguments |
| template <typename... AV> |
| inline void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a, |
| const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, |
| const AlphaNum& e, const AV&... args) { |
| strings_internal::AppendPieces( |
| dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), |
| static_cast<const AlphaNum&>(args).Piece()...}); |
| } |
| |
| // Helper function for the future StrCat default floating-point format, %.6g |
| // This is fast. |
| inline strings_internal::AlphaNumBuffer< |
| numbers_internal::kSixDigitsToBufferSize> |
| SixDigits(double d) { |
| strings_internal::AlphaNumBuffer<numbers_internal::kSixDigitsToBufferSize> |
| result; |
| result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]); |
| return result; |
| } |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_STR_CAT_H_ |
| *Ò |
| tsoong/.intermediates/external/abseil-cpp/absl_base_hdrs/gen/my_include_dir/absl/base/internal/tsan_mutex_interface.hÙ// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // This file is intended solely for spinlock.h. |
| // It provides ThreadSanitizer annotations for custom mutexes. |
| // See <sanitizer/tsan_interface.h> for meaning of these annotations. |
| |
| #ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_ |
| #define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_ |
| |
| #include "absl/base/config.h" |
| |
| // ABSL_INTERNAL_HAVE_TSAN_INTERFACE |
| // Macro intended only for internal use. |
| // |
| // Checks whether LLVM Thread Sanitizer interfaces are available. |
| // First made available in LLVM 5.0 (Sep 2017). |
| #ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE |
| #error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set." |
| #endif |
| |
| #if defined(ABSL_HAVE_THREAD_SANITIZER) && defined(__has_include) |
| #if __has_include(<sanitizer/tsan_interface.h>) |
| #define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1 |
| #endif |
| #endif |
| |
| #ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE |
| #include <sanitizer/tsan_interface.h> |
| |
| #define ABSL_TSAN_MUTEX_CREATE __tsan_mutex_create |
| #define ABSL_TSAN_MUTEX_DESTROY __tsan_mutex_destroy |
| #define ABSL_TSAN_MUTEX_PRE_LOCK __tsan_mutex_pre_lock |
| #define ABSL_TSAN_MUTEX_POST_LOCK __tsan_mutex_post_lock |
| #define ABSL_TSAN_MUTEX_PRE_UNLOCK __tsan_mutex_pre_unlock |
| #define ABSL_TSAN_MUTEX_POST_UNLOCK __tsan_mutex_post_unlock |
| #define ABSL_TSAN_MUTEX_PRE_SIGNAL __tsan_mutex_pre_signal |
| #define ABSL_TSAN_MUTEX_POST_SIGNAL __tsan_mutex_post_signal |
| #define ABSL_TSAN_MUTEX_PRE_DIVERT __tsan_mutex_pre_divert |
| #define ABSL_TSAN_MUTEX_POST_DIVERT __tsan_mutex_post_divert |
| |
| #else |
| |
| #define ABSL_TSAN_MUTEX_CREATE(...) |
| #define ABSL_TSAN_MUTEX_DESTROY(...) |
| #define ABSL_TSAN_MUTEX_PRE_LOCK(...) |
| #define ABSL_TSAN_MUTEX_POST_LOCK(...) |
| #define ABSL_TSAN_MUTEX_PRE_UNLOCK(...) |
| #define ABSL_TSAN_MUTEX_POST_UNLOCK(...) |
| #define ABSL_TSAN_MUTEX_PRE_SIGNAL(...) |
| #define ABSL_TSAN_MUTEX_POST_SIGNAL(...) |
| #define ABSL_TSAN_MUTEX_PRE_DIVERT(...) |
| #define ABSL_TSAN_MUTEX_POST_DIVERT(...) |
| |
| #endif |
| |
| #endif // ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_ |
| *g |
| {soong/.intermediates/external/abseil-cpp/absl_strings_cordz_info_hdrs/gen/my_include_dir/absl/strings/internal/cordz_info.hf// Copyright 2019 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_CORDZ_INFO_H_ |
| #define ABSL_STRINGS_INTERNAL_CORDZ_INFO_H_ |
| |
| #include <atomic> |
| #include <cstdint> |
| #include <functional> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/internal/raw_logging.h" |
| #include "absl/base/internal/spinlock.h" |
| #include "absl/base/thread_annotations.h" |
| #include "absl/strings/internal/cord_internal.h" |
| #include "absl/strings/internal/cordz_functions.h" |
| #include "absl/strings/internal/cordz_handle.h" |
| #include "absl/strings/internal/cordz_statistics.h" |
| #include "absl/strings/internal/cordz_update_tracker.h" |
| #include "absl/synchronization/mutex.h" |
| #include "absl/types/span.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // CordzInfo tracks a profiled Cord. Each of these objects can be in two places. |
| // If a Cord is alive, the CordzInfo will be in the global_cordz_infos map, and |
| // can also be retrieved via the linked list starting with |
| // global_cordz_infos_head and continued via the cordz_info_next() method. When |
| // a Cord has reached the end of its lifespan, the CordzInfo object will be |
| // migrated out of the global_cordz_infos list and the global_cordz_infos_map, |
| // and will either be deleted or appended to the global_delete_queue. If it is |
| // placed on the global_delete_queue, the CordzInfo object will be cleaned in |
| // the destructor of a CordzSampleToken object. |
| class ABSL_LOCKABLE CordzInfo : public CordzHandle { |
| public: |
| using MethodIdentifier = CordzUpdateTracker::MethodIdentifier; |
| |
| // TrackCord creates a CordzInfo instance which tracks important metrics of |
| // a sampled cord, and stores the created CordzInfo instance into `cord'. All |
| // CordzInfo instances are placed in a global list which is used to discover |
| // and snapshot all actively tracked cords. Callers are responsible for |
| // calling UntrackCord() before the tracked Cord instance is deleted, or to |
| // stop tracking the sampled Cord. Callers are also responsible for guarding |
| // changes to the 'tree' value of a Cord (InlineData.tree) through the Lock() |
| // and Unlock() calls. Any change resulting in a new tree value for the cord |
| // requires a call to SetCordRep() before the old tree has been unreffed |
| // and/or deleted. `method` identifies the Cord public API method initiating |
| // the cord to be sampled. |
| // Requires `cord` to hold a tree, and `cord.cordz_info()` to be null. |
| static void TrackCord(InlineData& cord, MethodIdentifier method, |
| int64_t sampling_stride); |
| |
| // Identical to TrackCord(), except that this function fills the |
| // `parent_stack` and `parent_method` properties of the returned CordzInfo |
| // instance from the provided `src` instance if `src` is sampled. |
| // This function should be used for sampling 'copy constructed' and 'copy |
| // assigned' cords. This function allows 'cord` to be already sampled, in |
| // which case the CordzInfo will be newly created from `src`. |
| static void TrackCord(InlineData& cord, const InlineData& src, |
| MethodIdentifier method); |
| |
| // Maybe sample the cord identified by 'cord' for method 'method'. |
| // Uses `cordz_should_profile` to randomly pick cords to be sampled, and if |
| // so, invokes `TrackCord` to start sampling `cord`. |
| static void MaybeTrackCord(InlineData& cord, MethodIdentifier method); |
| |
| // Maybe sample the cord identified by 'cord' for method 'method'. |
| // `src` identifies a 'parent' cord which is assigned to `cord`, typically the |
| // input cord for a copy constructor, or an assign method such as `operator=` |
| // `cord` will be sampled if (and only if) `src` is sampled. |
| // If `cord` is currently being sampled and `src` is not being sampled, then |
| // this function will stop sampling the cord and reset the cord's cordz_info. |
| // |
| // Previously this function defined that `cord` will be sampled if either |
| // `src` is sampled, or if `cord` is randomly picked for sampling. However, |
| // this can cause issues, as there may be paths where some cord is assigned an |
| // indirect copy of it's own value. As such a 'string of copies' would then |
| // remain sampled (`src.is_profiled`), then assigning such a cord back to |
| // 'itself' creates a cycle where the cord will converge to 'always sampled`. |
| // |
| // For example: |
| // |
| // Cord x; |
| // for (...) { |
| // // Copy ctor --> y.is_profiled := x.is_profiled | random(...) |
| // Cord y = x; |
| // ... |
| // // Assign x = y --> x.is_profiled = y.is_profiled | random(...) |
| // // ==> x.is_profiled |= random(...) |
| // // ==> x converges to 'always profiled' |
| // x = y; |
| // } |
| static void MaybeTrackCord(InlineData& cord, const InlineData& src, |
| MethodIdentifier method); |
| |
| // Stops tracking changes for a sampled cord, and deletes the provided info. |
| // This function must be called before the sampled cord instance is deleted, |
| // and before the root cordrep of the sampled cord is unreffed. |
| // This function may extend the lifetime of the cordrep in cases where the |
| // CordInfo instance is being held by a concurrent collection thread. |
| void Untrack(); |
| |
| // Invokes UntrackCord() on `info` if `info` is not null. |
| static void MaybeUntrackCord(CordzInfo* info); |
| |
| CordzInfo() = delete; |
| CordzInfo(const CordzInfo&) = delete; |
| CordzInfo& operator=(const CordzInfo&) = delete; |
| |
| // Retrieves the oldest existing CordzInfo. |
| static CordzInfo* Head(const CordzSnapshot& snapshot) |
| ABSL_NO_THREAD_SAFETY_ANALYSIS; |
| |
| // Retrieves the next oldest existing CordzInfo older than 'this' instance. |
| CordzInfo* Next(const CordzSnapshot& snapshot) const |
| ABSL_NO_THREAD_SAFETY_ANALYSIS; |
| |
| // Locks this instance for the update identified by `method`. |
| // Increases the count for `method` in `update_tracker`. |
| void Lock(MethodIdentifier method) ABSL_EXCLUSIVE_LOCK_FUNCTION(mutex_); |
| |
| // Unlocks this instance. If the contained `rep` has been set to null |
| // indicating the Cord has been cleared or is otherwise no longer sampled, |
| // then this method will delete this CordzInfo instance. |
| void Unlock() ABSL_UNLOCK_FUNCTION(mutex_); |
| |
| // Asserts that this CordzInfo instance is locked. |
| void AssertHeld() ABSL_ASSERT_EXCLUSIVE_LOCK(mutex_); |
| |
| // Updates the `rep` property of this instance. This methods is invoked by |
| // Cord logic each time the root node of a sampled Cord changes, and before |
| // the old root reference count is deleted. This guarantees that collection |
| // code can always safely take a reference on the tracked cord. |
| // Requires a lock to be held through the `Lock()` method. |
| // TODO(b/117940323): annotate with ABSL_EXCLUSIVE_LOCKS_REQUIRED once all |
| // Cord code is in a state where this can be proven true by the compiler. |
| void SetCordRep(CordRep* rep); |
| |
| // Returns the current `rep` property of this instance with a reference |
| // added, or null if this instance represents a cord that has since been |
| // deleted or untracked. |
| CordRep* RefCordRep() const ABSL_LOCKS_EXCLUDED(mutex_); |
| |
| // Returns the current value of `rep_` for testing purposes only. |
| CordRep* GetCordRepForTesting() const ABSL_NO_THREAD_SAFETY_ANALYSIS { |
| return rep_; |
| } |
| |
| // Sets the current value of `rep_` for testing purposes only. |
| void SetCordRepForTesting(CordRep* rep) ABSL_NO_THREAD_SAFETY_ANALYSIS { |
| rep_ = rep; |
| } |
| |
| // Returns the stack trace for where the cord was first sampled. Cords are |
| // potentially sampled when they promote from an inlined cord to a tree or |
| // ring representation, which is not necessarily the location where the cord |
| // was first created. Some cords are created as inlined cords, and only as |
| // data is added do they become a non-inlined cord. However, typically the |
| // location represents reasonably well where the cord is 'created'. |
| absl::Span<void* const> GetStack() const; |
| |
| // Returns the stack trace for a sampled cord's 'parent stack trace'. This |
| // value may be set if the cord is sampled (promoted) after being created |
| // from, or being assigned the value of an existing (sampled) cord. |
| absl::Span<void* const> GetParentStack() const; |
| |
| // Retrieves the CordzStatistics associated with this Cord. The statistics |
| // are only updated when a Cord goes through a mutation, such as an Append |
| // or RemovePrefix. |
| CordzStatistics GetCordzStatistics() const; |
| |
| int64_t sampling_stride() const { return sampling_stride_; } |
| |
| private: |
| using SpinLock = absl::base_internal::SpinLock; |
| using SpinLockHolder = ::absl::base_internal::SpinLockHolder; |
| |
| // Global cordz info list. CordzInfo stores a pointer to the global list |
| // instance to harden against ODR violations. |
| struct List { |
| constexpr explicit List(absl::ConstInitType) |
| : mutex(absl::kConstInit, |
| absl::base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL) {} |
| |
| SpinLock mutex; |
| std::atomic<CordzInfo*> head ABSL_GUARDED_BY(mutex){nullptr}; |
| }; |
| |
| static constexpr size_t kMaxStackDepth = 64; |
| |
| explicit CordzInfo(CordRep* rep, const CordzInfo* src, |
| MethodIdentifier method, int64_t weight); |
| ~CordzInfo() override; |
| |
| // Sets `rep_` without holding a lock. |
| void UnsafeSetCordRep(CordRep* rep) ABSL_NO_THREAD_SAFETY_ANALYSIS; |
| |
| void Track(); |
| |
| // Returns the parent method from `src`, which is either `parent_method_` or |
| // `method_` depending on `parent_method_` being kUnknown. |
| // Returns kUnknown if `src` is null. |
| static MethodIdentifier GetParentMethod(const CordzInfo* src); |
| |
| // Fills the provided stack from `src`, copying either `parent_stack_` or |
| // `stack_` depending on `parent_stack_` being empty, returning the size of |
| // the parent stack. |
| // Returns 0 if `src` is null. |
| static size_t FillParentStack(const CordzInfo* src, void** stack); |
| |
| void ODRCheck() const { |
| #ifndef NDEBUG |
| ABSL_RAW_CHECK(list_ == &global_list_, "ODR violation in Cord"); |
| #endif |
| } |
| |
| // Non-inlined implementation of `MaybeTrackCord`, which is executed if |
| // either `src` is sampled or `cord` is sampled, and either untracks or |
| // tracks `cord` as documented per `MaybeTrackCord`. |
| static void MaybeTrackCordImpl(InlineData& cord, const InlineData& src, |
| MethodIdentifier method); |
| |
| ABSL_CONST_INIT static List global_list_; |
| List* const list_ = &global_list_; |
| |
| // ci_prev_ and ci_next_ require the global list mutex to be held. |
| // Unfortunately we can't use thread annotations such that the thread safety |
| // analysis understands that list_ and global_list_ are one and the same. |
| std::atomic<CordzInfo*> ci_prev_{nullptr}; |
| std::atomic<CordzInfo*> ci_next_{nullptr}; |
| |
| mutable absl::Mutex mutex_; |
| CordRep* rep_ ABSL_GUARDED_BY(mutex_); |
| |
| void* stack_[kMaxStackDepth]; |
| void* parent_stack_[kMaxStackDepth]; |
| const size_t stack_depth_; |
| const size_t parent_stack_depth_; |
| const MethodIdentifier method_; |
| const MethodIdentifier parent_method_; |
| CordzUpdateTracker update_tracker_; |
| const absl::Time create_time_; |
| const int64_t sampling_stride_; |
| }; |
| |
| inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord( |
| InlineData& cord, MethodIdentifier method) { |
| auto stride = cordz_should_profile(); |
| if (ABSL_PREDICT_FALSE(stride > 0)) { |
| TrackCord(cord, method, stride); |
| } |
| } |
| |
| inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord( |
| InlineData& cord, const InlineData& src, MethodIdentifier method) { |
| if (ABSL_PREDICT_FALSE(InlineData::is_either_profiled(cord, src))) { |
| MaybeTrackCordImpl(cord, src, method); |
| } |
| } |
| |
| inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeUntrackCord( |
| CordzInfo* info) { |
| if (ABSL_PREDICT_FALSE(info)) { |
| info->Untrack(); |
| } |
| } |
| |
| inline void CordzInfo::AssertHeld() ABSL_ASSERT_EXCLUSIVE_LOCK(mutex_) { |
| #ifndef NDEBUG |
| mutex_.AssertHeld(); |
| #endif |
| } |
| |
| inline void CordzInfo::SetCordRep(CordRep* rep) { |
| AssertHeld(); |
| rep_ = rep; |
| } |
| |
| inline void CordzInfo::UnsafeSetCordRep(CordRep* rep) { rep_ = rep; } |
| |
| // Android local modification: locally silence an incorrect warning that |
| // causes build failures in code that uses -Werror. |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wthread-safety-negative" |
| inline CordRep* CordzInfo::RefCordRep() const ABSL_LOCKS_EXCLUDED(mutex_) { |
| MutexLock lock(&mutex_); |
| return rep_ ? CordRep::Ref(rep_) : nullptr; |
| } |
| #pragma clang diagnostic pop |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORDZ_INFO_H_ |
| *®k |
| soong/.intermediates/external/abseil-cpp/absl_strings_str_format_internal_hdrs/gen/my_include_dir/absl/strings/internal/str_format/constexpr_parser.hj// Copyright 2022 The Abseil Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CONSTEXPR_PARSER_H_ |
| #define ABSL_STRINGS_INTERNAL_STR_FORMAT_CONSTEXPR_PARSER_H_ |
| |
| #include <cassert> |
| #include <cstdint> |
| #include <cstdio> |
| #include <limits> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/const_init.h" |
| #include "absl/base/optimization.h" |
| #include "absl/strings/internal/str_format/extension.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace str_format_internal { |
| |
| // The analyzed properties of a single specified conversion. |
| struct UnboundConversion { |
| // This is a user defined default constructor on purpose to skip the |
| // initialization of parts of the object that are not necessary. |
| UnboundConversion() {} // NOLINT |
| |
| // This constructor is provided for the static checker. We don't want to do |
| // the unnecessary initialization in the normal case. |
| explicit constexpr UnboundConversion(absl::ConstInitType) |
| : arg_position{}, width{}, precision{} {} |
| |
| class InputValue { |
| public: |
| constexpr void set_value(int value) { |
| assert(value >= 0); |
| value_ = value; |
| } |
| constexpr int value() const { return value_; } |
| |
| // Marks the value as "from arg". aka the '*' format. |
| // Requires `value >= 1`. |
| // When set, is_from_arg() return true and get_from_arg() returns the |
| // original value. |
| // `value()`'s return value is unspecified in this state. |
| constexpr void set_from_arg(int value) { |
| assert(value > 0); |
| value_ = -value - 1; |
| } |
| constexpr bool is_from_arg() const { return value_ < -1; } |
| constexpr int get_from_arg() const { |
| assert(is_from_arg()); |
| return -value_ - 1; |
| } |
| |
| private: |
| int value_ = -1; |
| }; |
| |
| // No need to initialize. It will always be set in the parser. |
| int arg_position; |
| |
| InputValue width; |
| InputValue precision; |
| |
| Flags flags = Flags::kBasic; |
| LengthMod length_mod = LengthMod::none; |
| FormatConversionChar conv = FormatConversionCharInternal::kNone; |
| }; |
| |
| // Helper tag class for the table below. |
| // It allows fast `char -> ConversionChar/LengthMod/Flags` checking and |
| // conversions. |
| class ConvTag { |
| public: |
| constexpr ConvTag(FormatConversionChar conversion_char) // NOLINT |
| : tag_(static_cast<uint8_t>(conversion_char)) {} |
| constexpr ConvTag(LengthMod length_mod) // NOLINT |
| : tag_(0x80 | static_cast<uint8_t>(length_mod)) {} |
| constexpr ConvTag(Flags flags) // NOLINT |
| : tag_(0xc0 | static_cast<uint8_t>(flags)) {} |
| constexpr ConvTag() : tag_(0xFF) {} |
| |
| constexpr bool is_conv() const { return (tag_ & 0x80) == 0; } |
| constexpr bool is_length() const { return (tag_ & 0xC0) == 0x80; } |
| constexpr bool is_flags() const { return (tag_ & 0xE0) == 0xC0; } |
| |
| constexpr FormatConversionChar as_conv() const { |
| assert(is_conv()); |
| assert(!is_length()); |
| assert(!is_flags()); |
| return static_cast<FormatConversionChar>(tag_); |
| } |
| constexpr LengthMod as_length() const { |
| assert(!is_conv()); |
| assert(is_length()); |
| assert(!is_flags()); |
| return static_cast<LengthMod>(tag_ & 0x3F); |
| } |
| constexpr Flags as_flags() const { |
| assert(!is_conv()); |
| assert(!is_length()); |
| assert(is_flags()); |
| return static_cast<Flags>(tag_ & 0x1F); |
| } |
| |
| private: |
| uint8_t tag_; |
| }; |
| |
| struct ConvTagHolder { |
| using CC = FormatConversionCharInternal; |
| using LM = LengthMod; |
| |
| // Abbreviations to fit in the table below. |
| static constexpr auto kFSign = Flags::kSignCol; |
| static constexpr auto kFAlt = Flags::kAlt; |
| static constexpr auto kFPos = Flags::kShowPos; |
| static constexpr auto kFLeft = Flags::kLeft; |
| static constexpr auto kFZero = Flags::kZero; |
| |
| static constexpr ConvTag value[256] = { |
| {}, {}, {}, {}, {}, {}, {}, {}, // 00-07 |
| {}, {}, {}, {}, {}, {}, {}, {}, // 08-0f |
| {}, {}, {}, {}, {}, {}, {}, {}, // 10-17 |
| {}, {}, {}, {}, {}, {}, {}, {}, // 18-1f |
| kFSign, {}, {}, kFAlt, {}, {}, {}, {}, // !"#$%&' |
| {}, {}, {}, kFPos, {}, kFLeft, {}, {}, // ()*+,-./ |
| kFZero, {}, {}, {}, {}, {}, {}, {}, // 01234567 |
| {}, {}, {}, {}, {}, {}, {}, {}, // 89:;<=>? |
| {}, CC::A, {}, {}, {}, CC::E, CC::F, CC::G, // @ABCDEFG |
| {}, {}, {}, {}, LM::L, {}, {}, {}, // HIJKLMNO |
| {}, {}, {}, {}, {}, {}, {}, {}, // PQRSTUVW |
| CC::X, {}, {}, {}, {}, {}, {}, {}, // XYZ[\]^_ |
| {}, CC::a, {}, CC::c, CC::d, CC::e, CC::f, CC::g, // `abcdefg |
| LM::h, CC::i, LM::j, {}, LM::l, {}, CC::n, CC::o, // hijklmno |
| CC::p, LM::q, {}, CC::s, LM::t, CC::u, CC::v, {}, // pqrstuvw |
| CC::x, {}, LM::z, {}, {}, {}, {}, {}, // xyz{|}! |
| {}, {}, {}, {}, {}, {}, {}, {}, // 80-87 |
| {}, {}, {}, {}, {}, {}, {}, {}, // 88-8f |
| {}, {}, {}, {}, {}, {}, {}, {}, // 90-97 |
| {}, {}, {}, {}, {}, {}, {}, {}, // 98-9f |
| {}, {}, {}, {}, {}, {}, {}, {}, // a0-a7 |
| {}, {}, {}, {}, {}, {}, {}, {}, // a8-af |
| {}, {}, {}, {}, {}, {}, {}, {}, // b0-b7 |
| {}, {}, {}, {}, {}, {}, {}, {}, // b8-bf |
| {}, {}, {}, {}, {}, {}, {}, {}, // c0-c7 |
| {}, {}, {}, {}, {}, {}, {}, {}, // c8-cf |
| {}, {}, {}, {}, {}, {}, {}, {}, // d0-d7 |
| {}, {}, {}, {}, {}, {}, {}, {}, // d8-df |
| {}, {}, {}, {}, {}, {}, {}, {}, // e0-e7 |
| {}, {}, {}, {}, {}, {}, {}, {}, // e8-ef |
| {}, {}, {}, {}, {}, {}, {}, {}, // f0-f7 |
| {}, {}, {}, {}, {}, {}, {}, {}, // f8-ff |
| }; |
| }; |
| |
| // Keep a single table for all the conversion chars and length modifiers. |
| constexpr ConvTag GetTagForChar(char c) { |
| return ConvTagHolder::value[static_cast<unsigned char>(c)]; |
| } |
| |
| constexpr bool CheckFastPathSetting(const UnboundConversion& conv) { |
| bool width_precision_needed = |
| conv.width.value() >= 0 || conv.precision.value() >= 0; |
| if (width_precision_needed && conv.flags == Flags::kBasic) { |
| #if defined(__clang__) |
| // Some compilers complain about this in constexpr even when not executed, |
| // so only enable the error dump in clang. |
| fprintf(stderr, |
| "basic=%d left=%d show_pos=%d sign_col=%d alt=%d zero=%d " |
| "width=%d precision=%d\n", |
| conv.flags == Flags::kBasic ? 1 : 0, |
| FlagsContains(conv.flags, Flags::kLeft) ? 1 : 0, |
| FlagsContains(conv.flags, Flags::kShowPos) ? 1 : 0, |
| FlagsContains(conv.flags, Flags::kSignCol) ? 1 : 0, |
| FlagsContains(conv.flags, Flags::kAlt) ? 1 : 0, |
| FlagsContains(conv.flags, Flags::kZero) ? 1 : 0, conv.width.value(), |
| conv.precision.value()); |
| #endif // defined(__clang__) |
| return false; |
| } |
| return true; |
| } |
| |
| constexpr int ParseDigits(char& c, const char*& pos, const char* const end) { |
| int digits = c - '0'; |
| // We do not want to overflow `digits` so we consume at most digits10 |
| // digits. If there are more digits the parsing will fail later on when the |
| // digit doesn't match the expected characters. |
| int num_digits = std::numeric_limits<int>::digits10; |
| for (;;) { |
| if (ABSL_PREDICT_FALSE(pos == end)) break; |
| c = *pos++; |
| if ('0' > c || c > '9') break; |
| --num_digits; |
| if (ABSL_PREDICT_FALSE(!num_digits)) break; |
| digits = 10 * digits + c - '0'; |
| } |
| return digits; |
| } |
| |
| template <bool is_positional> |
| constexpr const char* ConsumeConversion(const char* pos, const char* const end, |
| UnboundConversion* conv, |
| int* next_arg) { |
| const char* const original_pos = pos; |
| char c = 0; |
| // Read the next char into `c` and update `pos`. Returns false if there are |
| // no more chars to read. |
| #define ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR() \ |
| do { \ |
| if (ABSL_PREDICT_FALSE(pos == end)) return nullptr; \ |
| c = *pos++; \ |
| } while (0) |
| |
| if (is_positional) { |
| ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); |
| if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; |
| conv->arg_position = ParseDigits(c, pos, end); |
| assert(conv->arg_position > 0); |
| if (ABSL_PREDICT_FALSE(c != '$')) return nullptr; |
| } |
| |
| ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); |
| |
| // We should start with the basic flag on. |
| assert(conv->flags == Flags::kBasic); |
| |
| // Any non alpha character makes this conversion not basic. |
| // This includes flags (-+ #0), width (1-9, *) or precision (.). |
| // All conversion characters and length modifiers are alpha characters. |
| if (c < 'A') { |
| while (c <= '0') { |
| auto tag = GetTagForChar(c); |
| if (tag.is_flags()) { |
| conv->flags = conv->flags | tag.as_flags(); |
| ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); |
| } else { |
| break; |
| } |
| } |
| |
| if (c <= '9') { |
| if (c >= '0') { |
| int maybe_width = ParseDigits(c, pos, end); |
| if (!is_positional && c == '$') { |
| if (ABSL_PREDICT_FALSE(*next_arg != 0)) return nullptr; |
| // Positional conversion. |
| *next_arg = -1; |
| return ConsumeConversion<true>(original_pos, end, conv, next_arg); |
| } |
| conv->flags = conv->flags | Flags::kNonBasic; |
| conv->width.set_value(maybe_width); |
| } else if (c == '*') { |
| conv->flags = conv->flags | Flags::kNonBasic; |
| ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); |
| if (is_positional) { |
| if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; |
| conv->width.set_from_arg(ParseDigits(c, pos, end)); |
| if (ABSL_PREDICT_FALSE(c != '$')) return nullptr; |
| ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); |
| } else { |
| conv->width.set_from_arg(++*next_arg); |
| } |
| } |
| } |
| |
| if (c == '.') { |
| conv->flags = conv->flags | Flags::kNonBasic; |
| ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); |
| if ('0' <= c && c <= '9') { |
| conv->precision.set_value(ParseDigits(c, pos, end)); |
| } else if (c == '*') { |
| ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); |
| if (is_positional) { |
| if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr; |
| conv->precision.set_from_arg(ParseDigits(c, pos, end)); |
| if (c != '$') return nullptr; |
| ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); |
| } else { |
| conv->precision.set_from_arg(++*next_arg); |
| } |
| } else { |
| conv->precision.set_value(0); |
| } |
| } |
| } |
| |
| auto tag = GetTagForChar(c); |
| |
| if (ABSL_PREDICT_FALSE(c == 'v' && conv->flags != Flags::kBasic)) { |
| return nullptr; |
| } |
| |
| if (ABSL_PREDICT_FALSE(!tag.is_conv())) { |
| if (ABSL_PREDICT_FALSE(!tag.is_length())) return nullptr; |
| |
| // It is a length modifier. |
| LengthMod length_mod = tag.as_length(); |
| ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); |
| if (c == 'h' && length_mod == LengthMod::h) { |
| conv->length_mod = LengthMod::hh; |
| ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); |
| } else if (c == 'l' && length_mod == LengthMod::l) { |
| conv->length_mod = LengthMod::ll; |
| ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); |
| } else { |
| conv->length_mod = length_mod; |
| } |
| tag = GetTagForChar(c); |
| |
| if (ABSL_PREDICT_FALSE(c == 'v')) return nullptr; |
| if (ABSL_PREDICT_FALSE(!tag.is_conv())) return nullptr; |
| |
| // `wchar_t` args are marked non-basic so `Bind()` will copy the length mod. |
| if (conv->length_mod == LengthMod::l && c == 'c') { |
| conv->flags = conv->flags | Flags::kNonBasic; |
| } |
| } |
| #undef ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR |
| |
| assert(CheckFastPathSetting(*conv)); |
| (void)(&CheckFastPathSetting); |
| |
| conv->conv = tag.as_conv(); |
| if (!is_positional) conv->arg_position = ++*next_arg; |
| return pos; |
| } |
| |
| // Consume conversion spec prefix (not including '%') of [p, end) if valid. |
| // Examples of valid specs would be e.g.: "s", "d", "-12.6f". |
| // If valid, it returns the first character following the conversion spec, |
| // and the spec part is broken down and returned in 'conv'. |
| // If invalid, returns nullptr. |
| constexpr const char* ConsumeUnboundConversion(const char* p, const char* end, |
| UnboundConversion* conv, |
| int* next_arg) { |
| if (*next_arg < 0) return ConsumeConversion<true>(p, end, conv, next_arg); |
| return ConsumeConversion<false>(p, end, conv, next_arg); |
| } |
| |
| } // namespace str_format_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_CONSTEXPR_PARSER_H_ |
| * |
| fsoong/.intermediates/external/abseil-cpp/absl_log_log_sink_hdrs/gen/my_include_dir/absl/log/log_sink.h©// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: log/log_sink.h |
| // ----------------------------------------------------------------------------- |
| // |
| // This header declares the interface class `absl::LogSink`. |
| |
| #ifndef ABSL_LOG_LOG_SINK_H_ |
| #define ABSL_LOG_LOG_SINK_H_ |
| |
| #include "absl/base/config.h" |
| #include "absl/log/log_entry.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // absl::LogSink |
| // |
| // `absl::LogSink` is an interface which can be extended to intercept and |
| // process particular messages (with `LOG.ToSinkOnly()` or |
| // `LOG.ToSinkAlso()`) or all messages (if registered with |
| // `absl::AddLogSink`). Implementations must not take any locks that might be |
| // held by the `LOG` caller. |
| class LogSink { |
| public: |
| virtual ~LogSink() = default; |
| |
| // LogSink::Send() |
| // |
| // `Send` is called synchronously during the log statement. `Send` must be |
| // thread-safe. |
| // |
| // It is safe to use `LOG` within an implementation of `Send`. `ToSinkOnly` |
| // and `ToSinkAlso` are safe in general but can be used to create an infinite |
| // loop if you try. |
| virtual void Send(const absl::LogEntry& entry) = 0; |
| |
| // LogSink::Flush() |
| // |
| // Sinks that buffer messages should override this method to flush the buffer |
| // and return. `Flush` must be thread-safe. |
| virtual void Flush() {} |
| |
| protected: |
| LogSink() = default; |
| // Implementations may be copyable and/or movable. |
| LogSink(const LogSink&) = default; |
| LogSink& operator=(const LogSink&) = default; |
| |
| private: |
| // https://lld.llvm.org/missingkeyfunction.html#missing-key-function |
| virtual void KeyFunction() const final; // NOLINT(readability/inheritance) |
| }; |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_LOG_LOG_SINK_H_ |
| *× |
| rsoong/.intermediates/external/abseil-cpp/absl_strings_str_format_hdrs/gen/my_include_dir/absl/strings/str_format.hß// |
| // Copyright 2018 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // ----------------------------------------------------------------------------- |
| // File: str_format.h |
| // ----------------------------------------------------------------------------- |
| // |
| // The `str_format` library is a typesafe replacement for the family of |
| // `printf()` string formatting routines within the `<cstdio>` standard library |
| // header. Like the `printf` family, `str_format` uses a "format string" to |
| // perform argument substitutions based on types. See the `FormatSpec` section |
| // below for format string documentation. |
| // |
| // Example: |
| // |
| // std::string s = absl::StrFormat( |
| // "%s %s You have $%d!", "Hello", name, dollars); |
| // |
| // The library consists of the following basic utilities: |
| // |
| // * `absl::StrFormat()`, a type-safe replacement for `std::sprintf()`, to |
| // write a format string to a `string` value. |
| // * `absl::StrAppendFormat()` to append a format string to a `string` |
| // * `absl::StreamFormat()` to more efficiently write a format string to a |
| // stream, such as`std::cout`. |
| // * `absl::PrintF()`, `absl::FPrintF()` and `absl::SNPrintF()` as |
| // drop-in replacements for `std::printf()`, `std::fprintf()` and |
| // `std::snprintf()`. |
| // |
| // Note: An `absl::SPrintF()` drop-in replacement is not supported as it |
| // is generally unsafe due to buffer overflows. Use `absl::StrFormat` which |
| // returns the string as output instead of expecting a pre-allocated buffer. |
| // |
| // Additionally, you can provide a format string (and its associated arguments) |
| // using one of the following abstractions: |
| // |
| // * A `FormatSpec` class template fully encapsulates a format string and its |
| // type arguments and is usually provided to `str_format` functions as a |
| // variadic argument of type `FormatSpec<Arg...>`. The `FormatSpec<Args...>` |
| // template is evaluated at compile-time, providing type safety. |
| // * A `ParsedFormat` instance, which encapsulates a specific, pre-compiled |
| // format string for a specific set of type(s), and which can be passed |
| // between API boundaries. (The `FormatSpec` type should not be used |
| // directly except as an argument type for wrapper functions.) |
| // |
| // The `str_format` library provides the ability to output its format strings to |
| // arbitrary sink types: |
| // |
| // * A generic `Format()` function to write outputs to arbitrary sink types, |
| // which must implement a `FormatRawSink` interface. |
| // |
| // * A `FormatUntyped()` function that is similar to `Format()` except it is |
| // loosely typed. `FormatUntyped()` is not a template and does not perform |
| // any compile-time checking of the format string; instead, it returns a |
| // boolean from a runtime check. |
| // |
| // In addition, the `str_format` library provides extension points for |
| // augmenting formatting to new types. See "StrFormat Extensions" below. |
| |
| #ifndef ABSL_STRINGS_STR_FORMAT_H_ |
| #define ABSL_STRINGS_STR_FORMAT_H_ |
| |
| #include <cstdint> |
| #include <cstdio> |
| #include <string> |
| #include <type_traits> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/base/config.h" |
| #include "absl/base/nullability.h" |
| #include "absl/strings/internal/str_format/arg.h" // IWYU pragma: export |
| #include "absl/strings/internal/str_format/bind.h" // IWYU pragma: export |
| #include "absl/strings/internal/str_format/checker.h" // IWYU pragma: export |
| #include "absl/strings/internal/str_format/extension.h" // IWYU pragma: export |
| #include "absl/strings/internal/str_format/parser.h" // IWYU pragma: export |
| #include "absl/strings/string_view.h" |
| #include "absl/types/span.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // UntypedFormatSpec |
| // |
| // A type-erased class that can be used directly within untyped API entry |
| // points. An `UntypedFormatSpec` is specifically used as an argument to |
| // `FormatUntyped()`. |
| // |
| // Example: |
| // |
| // absl::UntypedFormatSpec format("%d"); |
| // std::string out; |
| // CHECK(absl::FormatUntyped(&out, format, {absl::FormatArg(1)})); |
| class UntypedFormatSpec { |
| public: |
| UntypedFormatSpec() = delete; |
| UntypedFormatSpec(const UntypedFormatSpec&) = delete; |
| UntypedFormatSpec& operator=(const UntypedFormatSpec&) = delete; |
| |
| explicit UntypedFormatSpec(string_view s) : spec_(s) {} |
| |
| protected: |
| explicit UntypedFormatSpec( |
| const str_format_internal::ParsedFormatBase* absl_nonnull pc) |
| : spec_(pc) {} |
| |
| private: |
| friend str_format_internal::UntypedFormatSpecImpl; |
| str_format_internal::UntypedFormatSpecImpl spec_; |
| }; |
| |
| // FormatStreamed() |
| // |
| // Takes a streamable argument and returns an object that can print it |
| // with '%s'. Allows printing of types that have an `operator<<` but no |
| // intrinsic type support within `StrFormat()` itself. |
| // |
| // Example: |
| // |
| // absl::StrFormat("%s", absl::FormatStreamed(obj)); |
| template <typename T> |
| str_format_internal::StreamedWrapper<T> FormatStreamed(const T& v) { |
| return str_format_internal::StreamedWrapper<T>(v); |
| } |
| |
| // FormatCountCapture |
| // |
| // This class provides a way to safely wrap `StrFormat()` captures of `%n` |
| // conversions, which denote the number of characters written by a formatting |
| // operation to this point, into an integer value. |
| // |
| // This wrapper is designed to allow safe usage of `%n` within `StrFormat(); in |
| // the `printf()` family of functions, `%n` is not safe to use, as the `int *` |
| // buffer can be used to capture arbitrary data. |
| // |
| // Example: |
| // |
| // int n = 0; |
| // std::string s = absl::StrFormat("%s%d%n", "hello", 123, |
| // absl::FormatCountCapture(&n)); |
| // EXPECT_EQ(8, n); |
| class FormatCountCapture { |
| public: |
| explicit FormatCountCapture(int* absl_nonnull p) : p_(p) {} |
| |
| private: |
| // FormatCountCaptureHelper is used to define FormatConvertImpl() for this |
| // class. |
| friend struct str_format_internal::FormatCountCaptureHelper; |
| // Unused() is here because of the false positive from -Wunused-private-field |
| // p_ is used in the templated function of the friend FormatCountCaptureHelper |
| // class. |
| int* absl_nonnull Unused() { return p_; } |
| int* absl_nonnull p_; |
| }; |
| |
| // FormatSpec |
| // |
| // The `FormatSpec` type defines the makeup of a format string within the |
| // `str_format` library. It is a variadic class template that is evaluated at |
| // compile-time, according to the format string and arguments that are passed to |
| // it. |
| // |
| // You should not need to manipulate this type directly. You should only name it |
| // if you are writing wrapper functions which accept format arguments that will |
| // be provided unmodified to functions in this library. Such a wrapper function |
| // might be a class method that provides format arguments and/or internally uses |
| // the result of formatting. |
| // |
| // For a `FormatSpec` to be valid at compile-time, it must be provided as |
| // either: |
| // |
| // * A `constexpr` literal or `absl::string_view`, which is how it is most often |
| // used. |
| // * A `ParsedFormat` instantiation, which ensures the format string is |
| // valid before use. (See below.) |
| // |
| // Example: |
| // |
| // // Provided as a string literal. |
| // absl::StrFormat("Welcome to %s, Number %d!", "The Village", 6); |
| // |
| // // Provided as a constexpr absl::string_view. |
| // constexpr absl::string_view formatString = "Welcome to %s, Number %d!"; |
| // absl::StrFormat(formatString, "The Village", 6); |
| // |
| // // Provided as a pre-compiled ParsedFormat object. |
| // // Note that this example is useful only for illustration purposes. |
| // absl::ParsedFormat<'s', 'd'> formatString("Welcome to %s, Number %d!"); |
| // absl::StrFormat(formatString, "TheVillage", 6); |
| // |
| // A format string generally follows the POSIX syntax as used within the POSIX |
| // `printf` specification. (Exceptions are noted below.) |
| // |
| // (See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html) |
| // |
| // In specific, the `FormatSpec` supports the following type specifiers: |
| // * `c` for characters |
| // * `s` for strings |
| // * `d` or `i` for integers |
| // * `o` for unsigned integer conversions into octal |
| // * `x` or `X` for unsigned integer conversions into hex |
| // * `u` for unsigned integers |
| // * `f` or `F` for floating point values into decimal notation |
| // * `e` or `E` for floating point values into exponential notation |
| // * `a` or `A` for floating point values into hex exponential notation |
| // * `g` or `G` for floating point values into decimal or exponential |
| // notation based on their precision |
| // * `p` for pointer address values |
| // * `n` for the special case of writing out the number of characters |
| // written to this point. The resulting value must be captured within an |
| // `absl::FormatCountCapture` type. |
| // * `v` for values using the default format for a deduced type. These deduced |
| // types include many of the primitive types denoted here as well as |
| // user-defined types containing the proper extensions. (See below for more |
| // information.) |
| // |
| // Implementation-defined behavior: |
| // * A null pointer provided to "%s" or "%p" is output as "(nil)". |
| // * A non-null pointer provided to "%p" is output in hex as if by %#x or |
| // %#lx. |
| // |
| // NOTE: `o`, `x\X` and `u` will convert signed values to their unsigned |
| // counterpart before formatting. |
| // |
| // Examples: |
| // "%c", 'a' -> "a" |
| // "%c", 32 -> " " |
| // "%s", "C" -> "C" |
| // "%s", std::string("C++") -> "C++" |
| // "%d", -10 -> "-10" |
| // "%o", 10 -> "12" |
| // "%x", 16 -> "10" |
| // "%f", 123456789 -> "123456789.000000" |
| // "%e", .01 -> "1.00000e-2" |
| // "%a", -3.0 -> "-0x1.8p+1" |
| // "%g", .01 -> "1e-2" |
| // "%p", (void*)&value -> "0x7ffdeb6ad2a4" |
| // |
| // int n = 0; |
| // std::string s = absl::StrFormat( |
| // "%s%d%n", "hello", 123, absl::FormatCountCapture(&n)); |
| // EXPECT_EQ(8, n); |
| // |
| // NOTE: the `v` specifier (for "value") is a type specifier not present in the |
| // POSIX specification. %v will format values according to their deduced type. |
| // `v` uses `d` for signed integer values, `u` for unsigned integer values, `g` |
| // for floating point values, and formats boolean values as "true"/"false" |
| // (instead of 1 or 0 for booleans formatted using d). `const char*` is not |
| // supported; please use `std::string` and `string_view`. `char` is also not |
| // supported due to ambiguity of the type. This specifier does not support |
| // modifiers. |
| // |
| // The `FormatSpec` intrinsically supports all of these fundamental C++ types: |
| // |
| // * Characters: `char`, `signed char`, `unsigned char`, `wchar_t` |
| // * Integers: `int`, `short`, `unsigned short`, `unsigned`, `long`, |
| // `unsigned long`, `long long`, `unsigned long long` |
| // * Enums: printed as their underlying integral value |
| // * Floating-point: `float`, `double`, `long double` |
| // |
| // However, in the `str_format` library, a format conversion specifies a broader |
| // C++ conceptual category instead of an exact type. For example, `%s` binds to |
| // any string-like argument, so `std::string`, `std::wstring`, |
| // `absl::string_view`, `const char*`, and `const wchar_t*` are all accepted. |
| // Likewise, `%d` accepts any integer-like argument, etc. |
| |
| template <typename... Args> |
| using FormatSpec = str_format_internal::FormatSpecTemplate< |
| str_format_internal::ArgumentToConv<Args>()...>; |
| |
| // ParsedFormat |
| // |
| // A `ParsedFormat` is a class template representing a preparsed `FormatSpec`, |
| // with template arguments specifying the conversion characters used within the |
| // format string. Such characters must be valid format type specifiers, and |
| // these type specifiers are checked at compile-time. |
| // |
| // Instances of `ParsedFormat` can be created, copied, and reused to speed up |
| // formatting loops. A `ParsedFormat` may either be constructed statically, or |
| // dynamically through its `New()` factory function, which only constructs a |
| // runtime object if the format is valid at that time. |
| // |
| // Example: |
| // |
| // // Verified at compile time. |
| // absl::ParsedFormat<'s', 'd'> format_string("Welcome to %s, Number %d!"); |
| // absl::StrFormat(format_string, "TheVillage", 6); |
| // |
| // // Verified at runtime. |
| // auto format_runtime = absl::ParsedFormat<'d'>::New(format_string); |
| // if (format_runtime) { |
| // value = absl::StrFormat(*format_runtime, i); |
| // } else { |
| // ... error case ... |
| // } |
| |
| #if defined(__cpp_nontype_template_parameter_auto) |
| // If C++17 is available, an 'extended' format is also allowed that can specify |
| // multiple conversion characters per format argument, using a combination of |
| // `absl::FormatConversionCharSet` enum values (logically a set union) |
| // via the `|` operator. (Single character-based arguments are still accepted, |
| // but cannot be combined). Some common conversions also have predefined enum |
| // values, such as `absl::FormatConversionCharSet::kIntegral`. |
| // |
| // Example: |
| // // Extended format supports multiple conversion characters per argument, |
| // // specified via a combination of `FormatConversionCharSet` enums. |
| // using MyFormat = absl::ParsedFormat<absl::FormatConversionCharSet::d | |
| // absl::FormatConversionCharSet::x>; |
| // MyFormat GetFormat(bool use_hex) { |
| // if (use_hex) return MyFormat("foo %x bar"); |
| // return MyFormat("foo %d bar"); |
| // } |
| // // `format` can be used with any value that supports 'd' and 'x', |
| // // like `int`. |
| // auto format = GetFormat(use_hex); |
| // value = StringF(format, i); |
| template <auto... Conv> |
| using ParsedFormat = absl::str_format_internal::ExtendedParsedFormat< |
| absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; |
| #else |
| template <char... Conv> |
| using ParsedFormat = str_format_internal::ExtendedParsedFormat< |
| absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; |
| #endif // defined(__cpp_nontype_template_parameter_auto) |
| |
| // StrFormat() |
| // |
| // Returns a `string` given a `printf()`-style format string and zero or more |
| // additional arguments. Use it as you would `sprintf()`. `StrFormat()` is the |
| // primary formatting function within the `str_format` library, and should be |
| // used in most cases where you need type-safe conversion of types into |
| // formatted strings. |
| // |
| // The format string generally consists of ordinary character data along with |
| // one or more format conversion specifiers (denoted by the `%` character). |
| // Ordinary character data is returned unchanged into the result string, while |
| // each conversion specification performs a type substitution from |
| // `StrFormat()`'s other arguments. See the comments for `FormatSpec` for full |
| // information on the makeup of this format string. |
| // |
| // Example: |
| // |
| // std::string s = absl::StrFormat( |
| // "Welcome to %s, Number %d!", "The Village", 6); |
| // EXPECT_EQ("Welcome to The Village, Number 6!", s); |
| // |
| // Returns an empty string in case of error. |
| template <typename... Args> |
| [[nodiscard]] std::string StrFormat(const FormatSpec<Args...>& format, |
| const Args&... args) { |
| return str_format_internal::FormatPack( |
| str_format_internal::UntypedFormatSpecImpl::Extract(format), |
| {str_format_internal::FormatArgImpl(args)...}); |
| } |
| |
| // StrAppendFormat() |
| // |
| // Appends to a `dst` string given a format string, and zero or more additional |
| // arguments, returning `*dst` as a convenience for chaining purposes. Appends |
| // nothing in case of error (but possibly alters its capacity). |
| // |
| // Example: |
| // |
| // std::string orig("For example PI is approximately "); |
| // std::cout << StrAppendFormat(&orig, "%12.6f", 3.14); |
| template <typename... Args> |
| std::string& StrAppendFormat(std::string* absl_nonnull dst, |
| const FormatSpec<Args...>& format, |
| const Args&... args) { |
| return str_format_internal::AppendPack( |
| dst, str_format_internal::UntypedFormatSpecImpl::Extract(format), |
| {str_format_internal::FormatArgImpl(args)...}); |
| } |
| |
| // StreamFormat() |
| // |
| // Writes to an output stream given a format string and zero or more arguments, |
| // generally in a manner that is more efficient than streaming the result of |
| // `absl::StrFormat()`. The returned object must be streamed before the full |
| // expression ends. |
| // |
| // Example: |
| // |
| // std::cout << StreamFormat("%12.6f", 3.14); |
| template <typename... Args> |
| [[nodiscard]] str_format_internal::Streamable StreamFormat( |
| const FormatSpec<Args...>& format, const Args&... args) { |
| return str_format_internal::Streamable( |
| str_format_internal::UntypedFormatSpecImpl::Extract(format), |
| {str_format_internal::FormatArgImpl(args)...}); |
| } |
| |
| // PrintF() |
| // |
| // Writes to stdout given a format string and zero or more arguments. This |
| // function is functionally equivalent to `std::printf()` (and type-safe); |
| // prefer `absl::PrintF()` over `std::printf()`. |
| // |
| // Example: |
| // |
| // std::string_view s = "Ulaanbaatar"; |
| // absl::PrintF("The capital of Mongolia is %s", s); |
| // |
| // Outputs: "The capital of Mongolia is Ulaanbaatar" |
| // |
| template <typename... Args> |
| int PrintF(const FormatSpec<Args...>& format, const Args&... args) { |
| return str_format_internal::FprintF( |
| stdout, str_format_internal::UntypedFormatSpecImpl::Extract(format), |
| {str_format_internal::FormatArgImpl(args)...}); |
| } |
| |
| // FPrintF() |
| // |
| // Writes to a file given a format string and zero or more arguments. This |
| // function is functionally equivalent to `std::fprintf()` (and type-safe); |
| // prefer `absl::FPrintF()` over `std::fprintf()`. |
| // |
| // Example: |
| // |
| // std::string_view s = "Ulaanbaatar"; |
| // absl::FPrintF(stdout, "The capital of Mongolia is %s", s); |
| // |
| // Outputs: "The capital of Mongolia is Ulaanbaatar" |
| // |
| template <typename... Args> |
| int FPrintF(std::FILE* absl_nonnull output, const FormatSpec<Args...>& format, |
| const Args&... args) { |
| return str_format_internal::FprintF( |
| output, str_format_internal::UntypedFormatSpecImpl::Extract(format), |
| {str_format_internal::FormatArgImpl(args)...}); |
| } |
| |
| // SNPrintF() |
| // |
| // Writes to a sized buffer given a format string and zero or more arguments. |
| // This function is functionally equivalent to `std::snprintf()` (and |
| // type-safe); prefer `absl::SNPrintF()` over `std::snprintf()`. |
| // |
| // In particular, a successful call to `absl::SNPrintF()` writes at most `size` |
| // bytes of the formatted output to `output`, including a NUL-terminator, and |
| // returns the number of bytes that would have been written if truncation did |
| // not occur. In the event of an error, a negative value is returned and `errno` |
| // is set. |
| // |
| // Example: |
| // |
| // std::string_view s = "Ulaanbaatar"; |
| // char output[128]; |
| // absl::SNPrintF(output, sizeof(output), |
| // "The capital of Mongolia is %s", s); |
| // |
| // Post-condition: output == "The capital of Mongolia is Ulaanbaatar" |
| // |
| template <typename... Args> |
| int SNPrintF(char* absl_nonnull output, std::size_t size, |
| const FormatSpec<Args...>& format, const Args&... args) { |
| return str_format_internal::SnprintF( |
| output, size, str_format_internal::UntypedFormatSpecImpl::Extract(format), |
| {str_format_internal::FormatArgImpl(args)...}); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| // Custom Output Formatting Functions |
| // ----------------------------------------------------------------------------- |
| |
| // FormatRawSink |
| // |
| // FormatRawSink is a type erased wrapper around arbitrary sink objects |
| // specifically used as an argument to `Format()`. |
| // |
| // All the object has to do define an overload of `AbslFormatFlush()` for the |
| // sink, usually by adding a ADL-based free function in the same namespace as |
| // the sink: |
| // |
| // void AbslFormatFlush(MySink* dest, absl::string_view part); |
| // |
| // where `dest` is the pointer passed to `absl::Format()`. The function should |
| // append `part` to `dest`. |
| // |
| // FormatRawSink does not own the passed sink object. The passed object must |
| // outlive the FormatRawSink. |
| class FormatRawSink { |
| public: |
| // Implicitly convert from any type that provides the hook function as |
| // described above. |
| template <typename T, |
| typename = typename std::enable_if<std::is_constructible< |
| str_format_internal::FormatRawSinkImpl, T*>::value>::type> |
| FormatRawSink(T* absl_nonnull raw) // NOLINT |
| : sink_(raw) {} |
| |
| private: |
| friend str_format_internal::FormatRawSinkImpl; |
| str_format_internal::FormatRawSinkImpl sink_; |
| }; |
| |
| // Format() |
| // |
| // Writes a formatted string to an arbitrary sink object (implementing the |
| // `absl::FormatRawSink` interface), using a format string and zero or more |
| // additional arguments. |
| // |
| // By default, `std::string`, `std::ostream`, and `absl::Cord` are supported as |
| // destination objects. If a `std::string` is used the formatted string is |
| // appended to it. |
| // |
| // `absl::Format()` is a generic version of `absl::StrAppendFormat()`, for |
| // custom sinks. The format string, like format strings for `StrFormat()`, is |
| // checked at compile-time. |
| // |
| // On failure, this function returns `false` and the state of the sink is |
| // unspecified. |
| template <typename... Args> |
| bool Format(FormatRawSink raw_sink, const FormatSpec<Args...>& format, |
| const Args&... args) { |
| return str_format_internal::FormatUntyped( |
| str_format_internal::FormatRawSinkImpl::Extract(raw_sink), |
| str_format_internal::UntypedFormatSpecImpl::Extract(format), |
| {str_format_internal::FormatArgImpl(args)...}); |
| } |
| |
| // FormatArg |
| // |
| // A type-erased handle to a format argument specifically used as an argument to |
| // `FormatUntyped()`. You may construct `FormatArg` by passing |
| // reference-to-const of any printable type. `FormatArg` is both copyable and |
| // assignable. The source data must outlive the `FormatArg` instance. See |
| // example below. |
| // |
| using FormatArg = str_format_internal::FormatArgImpl; |
| |
| // FormatUntyped() |
| // |
| // Writes a formatted string to an arbitrary sink object (implementing the |
| // `absl::FormatRawSink` interface), using an `UntypedFormatSpec` and zero or |
| // more additional arguments. |
| // |
| // This function acts as the most generic formatting function in the |
| // `str_format` library. The caller provides a raw sink, an unchecked format |
| // string, and (usually) a runtime specified list of arguments; no compile-time |
| // checking of formatting is performed within this function. As a result, a |
| // caller should check the return value to verify that no error occurred. |
| // On failure, this function returns `false` and the state of the sink is |
| // unspecified. |
| // |
| // The arguments are provided in an `absl::Span<const absl::FormatArg>`. |
| // Each `absl::FormatArg` object binds to a single argument and keeps a |
| // reference to it. The values used to create the `FormatArg` objects must |
| // outlive this function call. |
| // |
| // Example: |
| // |
| // std::optional<std::string> FormatDynamic( |
| // const std::string& in_format, |
| // const vector<std::string>& in_args) { |
| // std::string out; |
| // std::vector<absl::FormatArg> args; |
| // for (const auto& v : in_args) { |
| // // It is important that 'v' is a reference to the objects in in_args. |
| // // The values we pass to FormatArg must outlive the call to |
| // // FormatUntyped. |
| // args.emplace_back(v); |
| // } |
| // absl::UntypedFormatSpec format(in_format); |
| // if (!absl::FormatUntyped(&out, format, args)) { |
| // return std::nullopt; |
| // } |
| // return std::move(out); |
| // } |
| // |
| [[nodiscard]] inline bool FormatUntyped(FormatRawSink raw_sink, |
| const UntypedFormatSpec& format, |
| absl::Span<const FormatArg> args) { |
| return str_format_internal::FormatUntyped( |
| str_format_internal::FormatRawSinkImpl::Extract(raw_sink), |
| str_format_internal::UntypedFormatSpecImpl::Extract(format), args); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // StrFormat Extensions |
| //------------------------------------------------------------------------------ |
| // |
| // AbslStringify() |
| // |
| // A simpler customization API for formatting user-defined types using |
| // absl::StrFormat(). The API relies on detecting an overload in the |
| // user-defined type's namespace of a free (non-member) `AbslStringify()` |
| // function as a friend definition with the following signature: |
| // |
| // template <typename Sink> |
| // void AbslStringify(Sink& sink, const X& value); |
| // |
| // An `AbslStringify()` overload for a type should only be declared in the same |
| // file and namespace as said type. |
| // |
| // Note that unlike with AbslFormatConvert(), AbslStringify() does not allow |
| // customization of allowed conversion characters. AbslStringify() uses `%v` as |
| // the underlying conversion specifier. Additionally, AbslStringify() supports |
| // use with absl::StrCat while AbslFormatConvert() does not. |
| // |
| // Example: |
| // |
| // struct Point { |
| // // To add formatting support to `Point`, we simply need to add a free |
| // // (non-member) function `AbslStringify()`. This method prints in the |
| // // request format using the underlying `%v` specifier. You can add such a |
| // // free function using a friend declaration within the body of the class. |
| // // The sink parameter is a templated type to avoid requiring dependencies. |
| // template <typename Sink> |
| // friend void AbslStringify(Sink& sink, const Point& p) { |
| // absl::Format(&sink, "(%v, %v)", p.x, p.y); |
| // } |
| // |
| // int x; |
| // int y; |
| // }; |
| // |
| // AbslFormatConvert() |
| // |
| // The StrFormat library provides a customization API for formatting |
| // user-defined types using absl::StrFormat(). The API relies on detecting an |
| // overload in the user-defined type's namespace of a free (non-member) |
| // `AbslFormatConvert()` function, usually as a friend definition with the |
| // following signature: |
| // |
| // absl::FormatConvertResult<...> AbslFormatConvert( |
| // const X& value, |
| // const absl::FormatConversionSpec& spec, |
| // absl::FormatSink *sink); |
| // |
| // An `AbslFormatConvert()` overload for a type should only be declared in the |
| // same file and namespace as said type. |
| // |
| // The abstractions within this definition include: |
| // |
| // * An `absl::FormatConversionSpec` to specify the fields to pull from a |
| // user-defined type's format string |
| // * An `absl::FormatSink` to hold the converted string data during the |
| // conversion process. |
| // * An `absl::FormatConvertResult` to hold the status of the returned |
| // formatting operation |
| // |
| // The return type encodes all the conversion characters that your |
| // AbslFormatConvert() routine accepts. The return value should be {true}. |
| // A return value of {false} will result in `StrFormat()` returning |
| // an empty string. This result will be propagated to the result of |
| // `FormatUntyped`. |
| // |
| // Example: |
| // |
| // struct Point { |
| // // To add formatting support to `Point`, we simply need to add a free |
| // // (non-member) function `AbslFormatConvert()`. This method interprets |
| // // `spec` to print in the request format. The allowed conversion characters |
| // // can be restricted via the type of the result, in this example |
| // // string and integral formatting are allowed (but not, for instance |
| // // floating point characters like "%f"). You can add such a free function |
| // // using a friend declaration within the body of the class: |
| // friend absl::FormatConvertResult<absl::FormatConversionCharSet::kString | |
| // absl::FormatConversionCharSet::kIntegral> |
| // AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec, |
| // absl::FormatSink* s) { |
| // if (spec.conversion_char() == absl::FormatConversionChar::s) { |
| // absl::Format(s, "x=%vy=%v", p.x, p.y); |
| // } else { |
| // absl::Format(s, "%v,%v", p.x, p.y); |
| // } |
| // return {true}; |
| // } |
| // |
| // int x; |
| // int y; |
| // }; |
| |
| // clang-format off |
| |
| // FormatConversionChar |
| // |
| // Specifies the formatting character provided in the format string |
| // passed to `StrFormat()`. |
| enum class FormatConversionChar : uint8_t { |
| c, s, // text |
| d, i, o, u, x, X, // int |
| f, F, e, E, g, G, a, A, // float |
| n, p, v // misc |
| }; |
| // clang-format on |
| |
| // FormatConversionSpec |
| // |
| // Specifies modifications to the conversion of the format string, through use |
| // of one or more format flags in the source format string. |
| class FormatConversionSpec { |
| public: |
| // FormatConversionSpec::is_basic() |
| // |
| // Indicates that width and precision are not specified, and no additional |
| // flags are set for this conversion character in the format string. |
| bool is_basic() const { return impl_.is_basic(); } |
| |
| // FormatConversionSpec::has_left_flag() |
| // |
| // Indicates whether the result should be left justified for this conversion |
| // character in the format string. This flag is set through use of a '-' |
| // character in the format string. E.g. "%-s" |
| bool has_left_flag() const { return impl_.has_left_flag(); } |
| |
| // FormatConversionSpec::has_show_pos_flag() |
| // |
| // Indicates whether a sign column is prepended to the result for this |
| // conversion character in the format string, even if the result is positive. |
| // This flag is set through use of a '+' character in the format string. |
| // E.g. "%+d" |
| bool has_show_pos_flag() const { return impl_.has_show_pos_flag(); } |
| |
| // FormatConversionSpec::has_sign_col_flag() |
| // |
| // Indicates whether a mandatory sign column is added to the result for this |
| // conversion character. This flag is set through use of a space character |
| // (' ') in the format string. E.g. "% i" |
| bool has_sign_col_flag() const { return impl_.has_sign_col_flag(); } |
| |
| // FormatConversionSpec::has_alt_flag() |
| // |
| // Indicates whether an "alternate" format is applied to the result for this |
| // conversion character. Alternative forms depend on the type of conversion |
| // character, and unallowed alternatives are undefined. This flag is set |
| // through use of a '#' character in the format string. E.g. "%#h" |
| bool has_alt_flag() const { return impl_.has_alt_flag(); } |
| |
| // FormatConversionSpec::has_zero_flag() |
| // |
| // Indicates whether zeroes should be prepended to the result for this |
| // conversion character instead of spaces. This flag is set through use of the |
| // '0' character in the format string. E.g. "%0f" |
| bool has_zero_flag() const { return impl_.has_zero_flag(); } |
| |
| // FormatConversionSpec::conversion_char() |
| // |
| // Returns the underlying conversion character. |
| FormatConversionChar conversion_char() const { |
| return impl_.conversion_char(); |
| } |
| |
| // FormatConversionSpec::width() |
| // |
| // Returns the specified width (indicated through use of a non-zero integer |
| // value or '*' character) of the conversion character. If width is |
| // unspecified, it returns a negative value. |
| int width() const { return impl_.width(); } |
| |
| // FormatConversionSpec::precision() |
| // |
| // Returns the specified precision (through use of the '.' character followed |
| // by a non-zero integer value or '*' character) of the conversion character. |
| // If precision is unspecified, it returns a negative value. |
| int precision() const { return impl_.precision(); } |
| |
| private: |
| explicit FormatConversionSpec( |
| str_format_internal::FormatConversionSpecImpl impl) |
| : impl_(impl) {} |
| |
| friend str_format_internal::FormatConversionSpecImpl; |
| |
| absl::str_format_internal::FormatConversionSpecImpl impl_; |
| }; |
| |
| // Type safe OR operator for FormatConversionCharSet to allow accepting multiple |
| // conversion chars in custom format converters. |
| constexpr FormatConversionCharSet operator|(FormatConversionCharSet a, |
| FormatConversionCharSet b) { |
| return static_cast<FormatConversionCharSet>(static_cast<uint64_t>(a) | |
| static_cast<uint64_t>(b)); |
| } |
| |
| // FormatConversionCharSet |
| // |
| // Specifies the _accepted_ conversion types as a template parameter to |
| // FormatConvertResult for custom implementations of `AbslFormatConvert`. |
| // Note the helper predefined alias definitions (kIntegral, etc.) below. |
| enum class FormatConversionCharSet : uint64_t { |
| // text |
| c = str_format_internal::FormatConversionCharToConvInt('c'), |
| s = str_format_internal::FormatConversionCharToConvInt('s'), |
| // integer |
| d = str_format_internal::FormatConversionCharToConvInt('d'), |
| i = str_format_internal::FormatConversionCharToConvInt('i'), |
| o = str_format_internal::FormatConversionCharToConvInt('o'), |
| u = str_format_internal::FormatConversionCharToConvInt('u'), |
| x = str_format_internal::FormatConversionCharToConvInt('x'), |
| X = str_format_internal::FormatConversionCharToConvInt('X'), |
| // Float |
| f = str_format_internal::FormatConversionCharToConvInt('f'), |
| F = str_format_internal::FormatConversionCharToConvInt('F'), |
| e = str_format_internal::FormatConversionCharToConvInt('e'), |
| E = str_format_internal::FormatConversionCharToConvInt('E'), |
| g = str_format_internal::FormatConversionCharToConvInt('g'), |
| G = str_format_internal::FormatConversionCharToConvInt('G'), |
| a = str_format_internal::FormatConversionCharToConvInt('a'), |
| A = str_format_internal::FormatConversionCharToConvInt('A'), |
| // misc |
| n = str_format_internal::FormatConversionCharToConvInt('n'), |
| p = str_format_internal::FormatConversionCharToConvInt('p'), |
| v = str_format_internal::FormatConversionCharToConvInt('v'), |
| |
| // Used for width/precision '*' specification. |
| kStar = static_cast<uint64_t>( |
| absl::str_format_internal::FormatConversionCharSetInternal::kStar), |
| // Some predefined values: |
| kIntegral = d | i | u | o | x | X, |
| kFloating = a | e | f | g | A | E | F | G, |
| kNumeric = kIntegral | kFloating, |
| kString = s, |
| kPointer = p, |
| }; |
| |
| // FormatSink |
| // |
| // A format sink is a generic abstraction to which conversions may write their |
| // formatted string data. `absl::FormatConvert()` uses this sink to write its |
| // formatted string. |
| // |
| class FormatSink { |
| public: |
| // FormatSink::Append() |
| // |
| // Appends `count` copies of `ch` to the format sink. |
| void Append(size_t count, char ch) { sink_->Append(count, ch); } |
| |
| // Overload of FormatSink::Append() for appending the characters of a string |
| // view to a format sink. |
| void Append(string_view v) { sink_->Append(v); } |
| |
| // FormatSink::PutPaddedString() |
| // |
| // Appends `precision` number of bytes of `v` to the format sink. If this is |
| // less than `width`, spaces will be appended first (if `left` is false), or |
| // after (if `left` is true) to ensure the total amount appended is |
| // at least `width`. |
| bool PutPaddedString(string_view v, int width, int precision, bool left) { |
| return sink_->PutPaddedString(v, width, precision, left); |
| } |
| |
| // Support `absl::Format(&sink, format, args...)`. |
| friend void AbslFormatFlush(FormatSink* absl_nonnull sink, |
| absl::string_view v) { |
| sink->Append(v); |
| } |
| |
| private: |
| friend str_format_internal::FormatSinkImpl; |
| explicit FormatSink(str_format_internal::FormatSinkImpl* absl_nonnull s) |
| : sink_(s) {} |
| str_format_internal::FormatSinkImpl* absl_nonnull sink_; |
| }; |
| |
| // FormatConvertResult |
| // |
| // Indicates whether a call to AbslFormatConvert() was successful. |
| // This return type informs the StrFormat extension framework (through |
| // ADL but using the return type) of what conversion characters are supported. |
| // It is strongly discouraged to return {false}, as this will result in an |
| // empty string in StrFormat. |
| template <FormatConversionCharSet C> |
| struct FormatConvertResult { |
| bool value; |
| }; |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_STR_FORMAT_H_ |
| *áZ |
| osoong/.intermediates/external/abseil-cpp/absl_base_hdrs/gen/my_include_dir/absl/base/internal/thread_identity.híY// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // Each active thread has an ThreadIdentity that may represent the thread in |
| // various level interfaces. ThreadIdentity objects are never deallocated. |
| // When a thread terminates, its ThreadIdentity object may be reused for a |
| // thread created later. |
| |
| #ifndef ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_ |
| #define ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_ |
| |
| #ifndef _WIN32 |
| #include <pthread.h> |
| // Defines __GOOGLE_GRTE_VERSION__ (via glibc-specific features.h) when |
| // supported. |
| #include <unistd.h> |
| #endif |
| |
| #include <atomic> |
| #include <cstdint> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/internal/per_thread_tls.h" |
| #include "absl/base/optimization.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| struct SynchLocksHeld; |
| struct SynchWaitParams; |
| |
| namespace base_internal { |
| |
| class SpinLock; |
| struct ThreadIdentity; |
| |
| // Used by the implementation of absl::Mutex and absl::CondVar. |
| struct PerThreadSynch { |
| // The internal representation of absl::Mutex and absl::CondVar rely |
| // on the alignment of PerThreadSynch. Both store the address of the |
| // PerThreadSynch in the high-order bits of their internal state, |
| // which means the low kLowZeroBits of the address of PerThreadSynch |
| // must be zero. |
| static constexpr int kLowZeroBits = 8; |
| static constexpr int kAlignment = 1 << kLowZeroBits; |
| |
| // Returns the associated ThreadIdentity. |
| // This can be implemented as a cast because we guarantee |
| // PerThreadSynch is the first element of ThreadIdentity. |
| ThreadIdentity* thread_identity() { |
| return reinterpret_cast<ThreadIdentity*>(this); |
| } |
| |
| PerThreadSynch* next; // Circular waiter queue; initialized to 0. |
| PerThreadSynch* skip; // If non-zero, all entries in Mutex queue |
| // up to and including "skip" have same |
| // condition as this, and will be woken later |
| bool may_skip; // if false while on mutex queue, a mutex unlocker |
| // is using this PerThreadSynch as a terminator. Its |
| // skip field must not be filled in because the loop |
| // might then skip over the terminator. |
| bool wake; // This thread is to be woken from a Mutex. |
| // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the |
| // waiter is waiting on the mutex as part of a CV Wait or Mutex Await. |
| // |
| // The value of "x->cond_waiter" is meaningless if "x" is not on a |
| // Mutex waiter list. |
| bool cond_waiter; |
| bool maybe_unlocking; // Valid at head of Mutex waiter queue; |
| // true if UnlockSlow could be searching |
| // for a waiter to wake. Used for an optimization |
| // in Enqueue(). true is always a valid value. |
| // Can be reset to false when the unlocker or any |
| // writer releases the lock, or a reader fully |
| // releases the lock. It may not be set to false |
| // by a reader that decrements the count to |
| // non-zero. protected by mutex spinlock |
| bool suppress_fatal_errors; // If true, try to proceed even in the face |
| // of broken invariants. This is used within |
| // fatal signal handlers to improve the |
| // chances of debug logging information being |
| // output successfully. |
| int priority; // Priority of thread (updated every so often). |
| |
| // State values: |
| // kAvailable: This PerThreadSynch is available. |
| // kQueued: This PerThreadSynch is unavailable, it's currently queued on a |
| // Mutex or CondVar waistlist. |
| // |
| // Transitions from kQueued to kAvailable require a release |
| // barrier. This is needed as a waiter may use "state" to |
| // independently observe that it's no longer queued. |
| // |
| // Transitions from kAvailable to kQueued require no barrier, they |
| // are externally ordered by the Mutex. |
| enum State { kAvailable, kQueued }; |
| std::atomic<State> state; |
| |
| // The wait parameters of the current wait. waitp is null if the |
| // thread is not waiting. Transitions from null to non-null must |
| // occur before the enqueue commit point (state = kQueued in |
| // Enqueue() and CondVarEnqueue()). Transitions from non-null to |
| // null must occur after the wait is finished (state = kAvailable in |
| // Mutex::Block() and CondVar::WaitCommon()). This field may be |
| // changed only by the thread that describes this PerThreadSynch. A |
| // special case is Fer(), which calls Enqueue() on another thread, |
| // but with an identical SynchWaitParams pointer, thus leaving the |
| // pointer unchanged. |
| SynchWaitParams* waitp; |
| |
| intptr_t readers; // Number of readers in mutex. |
| |
| // When priority will next be read (cycles). |
| int64_t next_priority_read_cycles; |
| |
| // Locks held; used during deadlock detection. |
| // Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity(). |
| SynchLocksHeld* all_locks; |
| }; |
| |
| // The instances of this class are allocated in NewThreadIdentity() with an |
| // alignment of PerThreadSynch::kAlignment and never destroyed. Initialization |
| // should happen in OneTimeInitThreadIdentity(). |
| // |
| // Instances may be reused by new threads - fields should be reset in |
| // ResetThreadIdentityBetweenReuse(). |
| // |
| // NOTE: The layout of fields in this structure is critical, please do not |
| // add, remove, or modify the field placements without fully auditing the |
| // layout. |
| struct ThreadIdentity { |
| // Must be the first member. The Mutex implementation requires that |
| // the PerThreadSynch object associated with each thread is |
| // PerThreadSynch::kAlignment aligned. We provide this alignment on |
| // ThreadIdentity itself. |
| PerThreadSynch per_thread_synch; |
| |
| // Private: Reserved for absl::synchronization_internal::Waiter. |
| struct WaiterState { |
| alignas(void*) char data[256]; |
| } waiter_state; |
| |
| // Used by PerThreadSem::{Get,Set}ThreadBlockedCounter(). |
| std::atomic<int>* blocked_count_ptr; |
| |
| // The following variables are mostly read/written just by the |
| // thread itself. The only exception is that these are read by |
| // a ticker thread as a hint. |
| std::atomic<int> ticker; // Tick counter, incremented once per second. |
| std::atomic<int> wait_start; // Ticker value when thread started waiting. |
| std::atomic<bool> is_idle; // Has thread become idle yet? |
| |
| ThreadIdentity* next; |
| }; |
| |
| // Returns the ThreadIdentity object representing the calling thread; guaranteed |
| // to be unique for its lifetime. The returned object will remain valid for the |
| // program's lifetime; although it may be re-assigned to a subsequent thread. |
| // If one does not exist, return nullptr instead. |
| // |
| // Does not malloc(*), and is async-signal safe. |
| // [*] Technically pthread_setspecific() does malloc on first use; however this |
| // is handled internally within tcmalloc's initialization already. Note that |
| // darwin does *not* use tcmalloc, so this can catch you if using MallocHooks |
| // on Apple platforms. Whatever function is calling your MallocHooks will need |
| // to watch for recursion on Apple platforms. |
| // |
| // New ThreadIdentity objects can be constructed and associated with a thread |
| // by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h. |
| ThreadIdentity* CurrentThreadIdentityIfPresent(); |
| |
| using ThreadIdentityReclaimerFunction = void (*)(void*); |
| |
| // Sets the current thread identity to the given value. 'reclaimer' is a |
| // pointer to the global function for cleaning up instances on thread |
| // destruction. |
| void SetCurrentThreadIdentity(ThreadIdentity* identity, |
| ThreadIdentityReclaimerFunction reclaimer); |
| |
| // Removes the currently associated ThreadIdentity from the running thread. |
| // This must be called from inside the ThreadIdentityReclaimerFunction, and only |
| // from that function. |
| void ClearCurrentThreadIdentity(); |
| |
| // May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode |
| // index> |
| #ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC |
| #error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be directly set |
| #else |
| #define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0 |
| #endif |
| |
| #ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS |
| #error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be directly set |
| #else |
| #define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1 |
| #endif |
| |
| #ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11 |
| #error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be directly set |
| #else |
| #define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2 |
| #endif |
| |
| #ifdef ABSL_THREAD_IDENTITY_MODE |
| #error ABSL_THREAD_IDENTITY_MODE cannot be directly set |
| #elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE) |
| #define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE |
| #elif defined(_WIN32) && !defined(__MINGW32__) |
| #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 |
| #elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL) |
| #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 |
| #elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \ |
| (__GOOGLE_GRTE_VERSION__ >= 20140228L) |
| // Support for async-safe TLS was specifically added in GRTEv4. It's not |
| // present in the upstream eglibc. |
| // Note: Current default for production systems. |
| #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS |
| #else |
| #define ABSL_THREAD_IDENTITY_MODE \ |
| ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC |
| #endif |
| |
| #if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \ |
| ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11 |
| |
| #if ABSL_PER_THREAD_TLS |
| ABSL_CONST_INIT extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* |
| thread_identity_ptr; |
| #elif defined(ABSL_HAVE_THREAD_LOCAL) |
| ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr; |
| #else |
| #error Thread-local storage not detected on this platform |
| #endif |
| |
| // thread_local variables cannot be in headers exposed by DLLs or in certain |
| // build configurations on Apple platforms. However, it is important for |
| // performance reasons in general that `CurrentThreadIdentityIfPresent` be |
| // inlined. In the other cases we opt to have the function not be inlined. Note |
| // that `CurrentThreadIdentityIfPresent` is declared above so we can exclude |
| // this entire inline definition. |
| #if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL) && \ |
| !defined(ABSL_CONSUME_DLL) |
| #define ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT 1 |
| #endif |
| |
| #ifdef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT |
| inline ThreadIdentity* CurrentThreadIdentityIfPresent() { |
| return thread_identity_ptr; |
| } |
| #endif |
| |
| #elif ABSL_THREAD_IDENTITY_MODE != \ |
| ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC |
| #error Unknown ABSL_THREAD_IDENTITY_MODE |
| #endif |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_ |
| *ó |
| soong/.intermediates/external/abseil-cpp/absl_strings_cordz_handle_hdrs/gen/my_include_dir/absl/strings/internal/cordz_handle.hï// Copyright 2019 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_CORDZ_HANDLE_H_ |
| #define ABSL_STRINGS_INTERNAL_CORDZ_HANDLE_H_ |
| |
| #include <atomic> |
| #include <vector> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/internal/raw_logging.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // This base class allows multiple types of object (CordzInfo and |
| // CordzSampleToken) to exist simultaneously on the delete queue (pointed to by |
| // global_dq_tail and traversed using dq_prev_ and dq_next_). The |
| // delete queue guarantees that once a profiler creates a CordzSampleToken and |
| // has gained visibility into a CordzInfo object, that CordzInfo object will not |
| // be deleted prematurely. This allows the profiler to inspect all CordzInfo |
| // objects that are alive without needing to hold a global lock. |
| class ABSL_DLL CordzHandle { |
| public: |
| CordzHandle() : CordzHandle(false) {} |
| |
| bool is_snapshot() const { return is_snapshot_; } |
| |
| // Returns true if this instance is safe to be deleted because it is either a |
| // snapshot, which is always safe to delete, or not included in the global |
| // delete queue and thus not included in any snapshot. |
| // Callers are responsible for making sure this instance can not be newly |
| // discovered by other threads. For example, CordzInfo instances first de-list |
| // themselves from the global CordzInfo list before determining if they are |
| // safe to be deleted directly. |
| // If SafeToDelete returns false, callers MUST use the Delete() method to |
| // safely queue CordzHandle instances for deletion. |
| bool SafeToDelete() const; |
| |
| // Deletes the provided instance, or puts it on the delete queue to be deleted |
| // once there are no more sample tokens (snapshot) instances potentially |
| // referencing the instance. `handle` should not be null. |
| static void Delete(CordzHandle* handle); |
| |
| // Returns the current entries in the delete queue in LIFO order. |
| static std::vector<const CordzHandle*> DiagnosticsGetDeleteQueue(); |
| |
| // Returns true if the provided handle is nullptr or guarded by this handle. |
| // Since the CordzSnapshot token is itself a CordzHandle, this method will |
| // allow tests to check if that token is keeping an arbitrary CordzHandle |
| // alive. |
| bool DiagnosticsHandleIsSafeToInspect(const CordzHandle* handle) const; |
| |
| // Returns the current entries in the delete queue, in LIFO order, that are |
| // protected by this. CordzHandle objects are only placed on the delete queue |
| // after CordzHandle::Delete is called with them as an argument. Only |
| // CordzHandle objects that are not also CordzSnapshot objects will be |
| // included in the return vector. For each of the handles in the return |
| // vector, the earliest that their memory can be freed is when this |
| // CordzSnapshot object is deleted. |
| std::vector<const CordzHandle*> DiagnosticsGetSafeToInspectDeletedHandles(); |
| |
| protected: |
| explicit CordzHandle(bool is_snapshot); |
| virtual ~CordzHandle(); |
| |
| private: |
| const bool is_snapshot_; |
| |
| // dq_prev_ and dq_next_ require the global queue mutex to be held. |
| // Unfortunately we can't use thread annotations such that the thread safety |
| // analysis understands that queue_ and global_queue_ are one and the same. |
| CordzHandle* dq_prev_ = nullptr; |
| CordzHandle* dq_next_ = nullptr; |
| }; |
| |
| class CordzSnapshot : public CordzHandle { |
| public: |
| CordzSnapshot() : CordzHandle(true) {} |
| }; |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORDZ_HANDLE_H_ |
| *Ëk |
| soong/.intermediates/external/abseil-cpp/absl_time_internal_cctz_civil_time_hdrs/gen/my_include_dir/absl/time/internal/cctz/include/cctz/civil_time.h°j// Copyright 2016 Google Inc. All Rights Reserved. |
| // |
| // 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_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_ |
| #define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_ |
| |
| #include "absl/base/config.h" |
| #include "absl/time/internal/cctz/include/cctz/civil_time_detail.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace time_internal { |
| namespace cctz { |
| |
| // The term "civil time" refers to the legally recognized human-scale time |
| // that is represented by the six fields YYYY-MM-DD hh:mm:ss. Modern-day civil |
| // time follows the Gregorian Calendar and is a time-zone-independent concept. |
| // A "date" is perhaps the most common example of a civil time (represented in |
| // this library as cctz::civil_day). This library provides six classes and a |
| // handful of functions that help with rounding, iterating, and arithmetic on |
| // civil times while avoiding complications like daylight-saving time (DST). |
| // |
| // The following six classes form the core of this civil-time library: |
| // |
| // * civil_second |
| // * civil_minute |
| // * civil_hour |
| // * civil_day |
| // * civil_month |
| // * civil_year |
| // |
| // Each class is a simple value type with the same interface for construction |
| // and the same six accessors for each of the civil fields (year, month, day, |
| // hour, minute, and second, aka YMDHMS). These classes differ only in their |
| // alignment, which is indicated by the type name and specifies the field on |
| // which arithmetic operates. |
| // |
| // Each class can be constructed by passing up to six optional integer |
| // arguments representing the YMDHMS fields (in that order) to the |
| // constructor. Omitted fields are assigned their minimum valid value. Hours, |
| // minutes, and seconds will be set to 0, month and day will be set to 1, and |
| // since there is no minimum valid year, it will be set to 1970. So, a |
| // default-constructed civil-time object will have YMDHMS fields representing |
| // "1970-01-01 00:00:00". Fields that are out-of-range are normalized (e.g., |
| // October 32 -> November 1) so that all civil-time objects represent valid |
| // values. |
| // |
| // Each civil-time class is aligned to the civil-time field indicated in the |
| // class's name after normalization. Alignment is performed by setting all the |
| // inferior fields to their minimum valid value (as described above). The |
| // following are examples of how each of the six types would align the fields |
| // representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the |
| // string format used here is not important; it's just a shorthand way of |
| // showing the six YMDHMS fields.) |
| // |
| // civil_second 2015-11-22 12:34:56 |
| // civil_minute 2015-11-22 12:34:00 |
| // civil_hour 2015-11-22 12:00:00 |
| // civil_day 2015-11-22 00:00:00 |
| // civil_month 2015-11-01 00:00:00 |
| // civil_year 2015-01-01 00:00:00 |
| // |
| // Each civil-time type performs arithmetic on the field to which it is |
| // aligned. This means that adding 1 to a civil_day increments the day field |
| // (normalizing as necessary), and subtracting 7 from a civil_month operates |
| // on the month field (normalizing as necessary). All arithmetic produces a |
| // valid civil time. Difference requires two similarly aligned civil-time |
| // objects and returns the scalar answer in units of the objects' alignment. |
| // For example, the difference between two civil_hour objects will give an |
| // answer in units of civil hours. |
| // |
| // In addition to the six civil-time types just described, there are |
| // a handful of helper functions and algorithms for performing common |
| // calculations. These are described below. |
| // |
| // Note: In C++14 and later, this library is usable in a constexpr context. |
| // |
| // CONSTRUCTION: |
| // |
| // Each of the civil-time types can be constructed in two ways: by directly |
| // passing to the constructor up to six (optional) integers representing the |
| // YMDHMS fields, or by copying the YMDHMS fields from a differently aligned |
| // civil-time type. |
| // |
| // civil_day default_value; // 1970-01-01 00:00:00 |
| // |
| // civil_day a(2015, 2, 3); // 2015-02-03 00:00:00 |
| // civil_day b(2015, 2, 3, 4, 5, 6); // 2015-02-03 00:00:00 |
| // civil_day c(2015); // 2015-01-01 00:00:00 |
| // |
| // civil_second ss(2015, 2, 3, 4, 5, 6); // 2015-02-03 04:05:06 |
| // civil_minute mm(ss); // 2015-02-03 04:05:00 |
| // civil_hour hh(mm); // 2015-02-03 04:00:00 |
| // civil_day d(hh); // 2015-02-03 00:00:00 |
| // civil_month m(d); // 2015-02-01 00:00:00 |
| // civil_year y(m); // 2015-01-01 00:00:00 |
| // |
| // m = civil_month(y); // 2015-01-01 00:00:00 |
| // d = civil_day(m); // 2015-01-01 00:00:00 |
| // hh = civil_hour(d); // 2015-01-01 00:00:00 |
| // mm = civil_minute(hh); // 2015-01-01 00:00:00 |
| // ss = civil_second(mm); // 2015-01-01 00:00:00 |
| // |
| // ALIGNMENT CONVERSION: |
| // |
| // The alignment of a civil-time object cannot change, but the object may be |
| // used to construct a new object with a different alignment. This is referred |
| // to as "realigning". When realigning to a type with the same or more |
| // precision (e.g., civil_day -> civil_second), the conversion may be |
| // performed implicitly since no information is lost. However, if information |
| // could be discarded (e.g., civil_second -> civil_day), the conversion must |
| // be explicit at the call site. |
| // |
| // void fun(const civil_day& day); |
| // |
| // civil_second cs; |
| // fun(cs); // Won't compile because data may be discarded |
| // fun(civil_day(cs)); // OK: explicit conversion |
| // |
| // civil_day cd; |
| // fun(cd); // OK: no conversion needed |
| // |
| // civil_month cm; |
| // fun(cm); // OK: implicit conversion to civil_day |
| // |
| // NORMALIZATION: |
| // |
| // Integer arguments passed to the constructor may be out-of-range, in which |
| // case they are normalized to produce a valid civil-time object. This enables |
| // natural arithmetic on constructor arguments without worrying about the |
| // field's range. Normalization guarantees that there are no invalid |
| // civil-time objects. |
| // |
| // civil_day d(2016, 10, 32); // Out-of-range day; normalized to 2016-11-01 |
| // |
| // Note: If normalization is undesired, you can signal an error by comparing |
| // the constructor arguments to the normalized values returned by the YMDHMS |
| // properties. |
| // |
| // PROPERTIES: |
| // |
| // All civil-time types have accessors for all six of the civil-time fields: |
| // year, month, day, hour, minute, and second. Recall that fields inferior to |
| // the type's alignment will be set to their minimum valid value. |
| // |
| // civil_day d(2015, 6, 28); |
| // // d.year() == 2015 |
| // // d.month() == 6 |
| // // d.day() == 28 |
| // // d.hour() == 0 |
| // // d.minute() == 0 |
| // // d.second() == 0 |
| // |
| // COMPARISON: |
| // |
| // Comparison always considers all six YMDHMS fields, regardless of the type's |
| // alignment. Comparison between differently aligned civil-time types is |
| // allowed. |
| // |
| // civil_day feb_3(2015, 2, 3); // 2015-02-03 00:00:00 |
| // civil_day mar_4(2015, 3, 4); // 2015-03-04 00:00:00 |
| // // feb_3 < mar_4 |
| // // civil_year(feb_3) == civil_year(mar_4) |
| // |
| // civil_second feb_3_noon(2015, 2, 3, 12, 0, 0); // 2015-02-03 12:00:00 |
| // // feb_3 < feb_3_noon |
| // // feb_3 == civil_day(feb_3_noon) |
| // |
| // // Iterates all the days of February 2015. |
| // for (civil_day d(2015, 2, 1); d < civil_month(2015, 3); ++d) { |
| // // ... |
| // } |
| // |
| // STREAMING: |
| // |
| // Each civil-time type may be sent to an output stream using operator<<(). |
| // The output format follows the pattern "YYYY-MM-DDThh:mm:ss" where fields |
| // inferior to the type's alignment are omitted. |
| // |
| // civil_second cs(2015, 2, 3, 4, 5, 6); |
| // std::cout << cs << "\n"; // Outputs: 2015-02-03T04:05:06 |
| // |
| // civil_day cd(cs); |
| // std::cout << cd << "\n"; // Outputs: 2015-02-03 |
| // |
| // civil_year cy(cs); |
| // std::cout << cy << "\n"; // Outputs: 2015 |
| // |
| // ARITHMETIC: |
| // |
| // Civil-time types support natural arithmetic operators such as addition, |
| // subtraction, and difference. Arithmetic operates on the civil-time field |
| // indicated in the type's name. Difference requires arguments with the same |
| // alignment and returns the answer in units of the alignment. |
| // |
| // civil_day a(2015, 2, 3); |
| // ++a; // 2015-02-04 00:00:00 |
| // --a; // 2015-02-03 00:00:00 |
| // civil_day b = a + 1; // 2015-02-04 00:00:00 |
| // civil_day c = 1 + b; // 2015-02-05 00:00:00 |
| // int n = c - a; // n = 2 (civil days) |
| // int m = c - civil_month(c); // Won't compile: different types. |
| // |
| // EXAMPLE: Adding a month to January 31. |
| // |
| // One of the classic questions that arises when considering a civil-time |
| // library (or a date library or a date/time library) is this: "What happens |
| // when you add a month to January 31?" This is an interesting question |
| // because there could be a number of possible answers: |
| // |
| // 1. March 3 (or 2 if a leap year). This may make sense if the operation |
| // wants the equivalent of February 31. |
| // 2. February 28 (or 29 if a leap year). This may make sense if the operation |
| // wants the last day of January to go to the last day of February. |
| // 3. Error. The caller may get some error, an exception, an invalid date |
| // object, or maybe false is returned. This may make sense because there is |
| // no single unambiguously correct answer to the question. |
| // |
| // Practically speaking, any answer that is not what the programmer intended |
| // is the wrong answer. |
| // |
| // This civil-time library avoids the problem by making it impossible to ask |
| // ambiguous questions. All civil-time objects are aligned to a particular |
| // civil-field boundary (such as aligned to a year, month, day, hour, minute, |
| // or second), and arithmetic operates on the field to which the object is |
| // aligned. This means that in order to "add a month" the object must first be |
| // aligned to a month boundary, which is equivalent to the first day of that |
| // month. |
| // |
| // Of course, there are ways to compute an answer the question at hand using |
| // this civil-time library, but they require the programmer to be explicit |
| // about the answer they expect. To illustrate, let's see how to compute all |
| // three of the above possible answers to the question of "Jan 31 plus 1 |
| // month": |
| // |
| // const civil_day d(2015, 1, 31); |
| // |
| // // Answer 1: |
| // // Add 1 to the month field in the constructor, and rely on normalization. |
| // const auto ans_normalized = civil_day(d.year(), d.month() + 1, d.day()); |
| // // ans_normalized == 2015-03-03 (aka Feb 31) |
| // |
| // // Answer 2: |
| // // Add 1 to month field, capping to the end of next month. |
| // const auto next_month = civil_month(d) + 1; |
| // const auto last_day_of_next_month = civil_day(next_month + 1) - 1; |
| // const auto ans_capped = std::min(ans_normalized, last_day_of_next_month); |
| // // ans_capped == 2015-02-28 |
| // |
| // // Answer 3: |
| // // Signal an error if the normalized answer is not in next month. |
| // if (civil_month(ans_normalized) != next_month) { |
| // // error, month overflow |
| // } |
| // |
| using civil_year = detail::civil_year; |
| using civil_month = detail::civil_month; |
| using civil_day = detail::civil_day; |
| using civil_hour = detail::civil_hour; |
| using civil_minute = detail::civil_minute; |
| using civil_second = detail::civil_second; |
| |
| // An enum class with members monday, tuesday, wednesday, thursday, friday, |
| // saturday, and sunday. These enum values may be sent to an output stream |
| // using operator<<(). The result is the full weekday name in English with a |
| // leading capital letter. |
| // |
| // weekday wd = weekday::thursday; |
| // std::cout << wd << "\n"; // Outputs: Thursday |
| // |
| using detail::weekday; |
| |
| // Returns the weekday for the given civil-time value. |
| // |
| // civil_day a(2015, 8, 13); |
| // weekday wd = get_weekday(a); // wd == weekday::thursday |
| // |
| using detail::get_weekday; |
| |
| // Returns the civil_day that strictly follows or precedes the given |
| // civil_day, and that falls on the given weekday. |
| // |
| // For example, given: |
| // |
| // August 2015 |
| // Su Mo Tu We Th Fr Sa |
| // 1 |
| // 2 3 4 5 6 7 8 |
| // 9 10 11 12 13 14 15 |
| // 16 17 18 19 20 21 22 |
| // 23 24 25 26 27 28 29 |
| // 30 31 |
| // |
| // civil_day a(2015, 8, 13); // get_weekday(a) == weekday::thursday |
| // civil_day b = next_weekday(a, weekday::thursday); // b = 2015-08-20 |
| // civil_day c = prev_weekday(a, weekday::thursday); // c = 2015-08-06 |
| // |
| // civil_day d = ... |
| // // Gets the following Thursday if d is not already Thursday |
| // civil_day thurs1 = next_weekday(d - 1, weekday::thursday); |
| // // Gets the previous Thursday if d is not already Thursday |
| // civil_day thurs2 = prev_weekday(d + 1, weekday::thursday); |
| // |
| using detail::next_weekday; |
| using detail::prev_weekday; |
| |
| // Returns the day-of-year for the given civil-time value. |
| // |
| // civil_day a(2015, 1, 1); |
| // int yd_jan_1 = get_yearday(a); // yd_jan_1 = 1 |
| // civil_day b(2015, 12, 31); |
| // int yd_dec_31 = get_yearday(b); // yd_dec_31 = 365 |
| // |
| using detail::get_yearday; |
| |
| } // namespace cctz |
| } // namespace time_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_ |
| *Þ× |
| soong/.intermediates/external/abseil-cpp/absl_strings_str_format_internal_hdrs/gen/my_include_dir/absl/strings/internal/str_format/arg.hÏÖ// Copyright 2020 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ |
| #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ |
| |
| #include <string.h> |
| #include <wchar.h> |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstdio> |
| #include <limits> |
| #include <memory> |
| #include <sstream> |
| #include <string> |
| #include <string_view> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/optimization.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/numeric/int128.h" |
| #include "absl/strings/has_absl_stringify.h" |
| #include "absl/strings/internal/str_format/extension.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| class Cord; |
| class FormatCountCapture; |
| class FormatSink; |
| |
| template <absl::FormatConversionCharSet C> |
| struct FormatConvertResult; |
| class FormatConversionSpec; |
| |
| namespace str_format_internal { |
| |
| template <FormatConversionCharSet C> |
| struct ArgConvertResult { |
| bool value; |
| }; |
| |
| using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion( |
| FormatConversionCharSetInternal::c, |
| FormatConversionCharSetInternal::kNumeric, |
| FormatConversionCharSetInternal::kStar, |
| FormatConversionCharSetInternal::v)>; |
| using FloatingConvertResult = ArgConvertResult<FormatConversionCharSetUnion( |
| FormatConversionCharSetInternal::kFloating, |
| FormatConversionCharSetInternal::v)>; |
| using CharConvertResult = ArgConvertResult<FormatConversionCharSetUnion( |
| FormatConversionCharSetInternal::c, |
| FormatConversionCharSetInternal::kNumeric, |
| FormatConversionCharSetInternal::kStar)>; |
| |
| template <typename T, typename = void> |
| struct HasUserDefinedConvert : std::false_type {}; |
| |
| template <typename T> |
| struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert( |
| std::declval<const T&>(), |
| std::declval<const FormatConversionSpec&>(), |
| std::declval<FormatSink*>()))>> |
| : std::true_type {}; |
| |
| // These declarations prevent ADL lookup from continuing in absl namespaces, |
| // we are deliberately using these as ADL hooks and want them to consider |
| // non-absl namespaces only. |
| void AbslFormatConvert(); |
| void AbslStringify(); |
| |
| template <typename T> |
| bool ConvertIntArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); |
| |
| // Forward declarations of internal `ConvertIntArg` function template |
| // instantiations are here to avoid including the template body in the headers |
| // and instantiating it in large numbers of translation units. Explicit |
| // instantiations can be found in "absl/strings/internal/str_format/arg.cc" |
| extern template bool ConvertIntArg<char>(char v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| extern template bool ConvertIntArg<signed char>(signed char v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| extern template bool ConvertIntArg<unsigned char>(unsigned char v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| extern template bool ConvertIntArg<wchar_t>(wchar_t v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| extern template bool ConvertIntArg<short>(short v, // NOLINT |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| extern template bool ConvertIntArg<unsigned short>( // NOLINT |
| unsigned short v, FormatConversionSpecImpl conv, // NOLINT |
| FormatSinkImpl* sink); |
| extern template bool ConvertIntArg<int>(int v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| extern template bool ConvertIntArg<unsigned int>(unsigned int v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| extern template bool ConvertIntArg<long>( // NOLINT |
| long v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); // NOLINT |
| extern template bool ConvertIntArg<unsigned long>(unsigned long v, // NOLINT |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| extern template bool ConvertIntArg<long long>(long long v, // NOLINT |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| extern template bool ConvertIntArg<unsigned long long>( // NOLINT |
| unsigned long long v, FormatConversionSpecImpl conv, // NOLINT |
| FormatSinkImpl* sink); |
| |
| template <typename T> |
| auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink) |
| -> decltype(AbslFormatConvert(v, |
| std::declval<const FormatConversionSpec&>(), |
| std::declval<FormatSink*>())) { |
| using FormatConversionSpecT = |
| absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>; |
| using FormatSinkT = |
| absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>; |
| auto fcs = conv.Wrap<FormatConversionSpecT>(); |
| auto fs = sink->Wrap<FormatSinkT>(); |
| return AbslFormatConvert(v, fcs, &fs); |
| } |
| |
| template <typename T> |
| auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink) |
| -> std::enable_if_t<std::is_enum<T>::value && |
| std::is_void<decltype(AbslStringify( |
| std::declval<FormatSink&>(), v))>::value, |
| IntegralConvertResult> { |
| if (conv.conversion_char() == FormatConversionCharInternal::v) { |
| using FormatSinkT = |
| absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>; |
| auto fs = sink->Wrap<FormatSinkT>(); |
| AbslStringify(fs, v); |
| return {true}; |
| } else { |
| return {ConvertIntArg( |
| static_cast<typename std::underlying_type<T>::type>(v), conv, sink)}; |
| } |
| } |
| |
| template <typename T> |
| auto FormatConvertImpl(const T& v, FormatConversionSpecImpl, |
| FormatSinkImpl* sink) |
| -> std::enable_if_t<!std::is_enum<T>::value && |
| !std::is_same<T, absl::Cord>::value && |
| std::is_void<decltype(AbslStringify( |
| std::declval<FormatSink&>(), v))>::value, |
| ArgConvertResult<FormatConversionCharSetInternal::v>> { |
| using FormatSinkT = |
| absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>; |
| auto fs = sink->Wrap<FormatSinkT>(); |
| AbslStringify(fs, v); |
| return {true}; |
| } |
| |
| template <typename T> |
| class StreamedWrapper; |
| |
| // If 'v' can be converted (in the printf sense) according to 'conv', |
| // then convert it, appending to `sink` and return `true`. |
| // Otherwise fail and return `false`. |
| |
| // AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v' |
| // as an extension mechanism. These FormatConvertImpl functions are the default |
| // implementations. |
| // The ADL search is augmented via the 'Sink*' parameter, which also |
| // serves as a disambiguator to reject possible unintended 'AbslFormatConvert' |
| // functions in the namespaces associated with 'v'. |
| |
| // Raw pointers. |
| struct VoidPtr { |
| VoidPtr() = default; |
| template <typename T, |
| decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0> |
| VoidPtr(T* ptr) // NOLINT |
| : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {} |
| uintptr_t value; |
| }; |
| |
| template <FormatConversionCharSet C> |
| constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) { |
| return C; |
| } |
| |
| template <FormatConversionCharSet C> |
| constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) { |
| return C; |
| } |
| |
| ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl( |
| VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); |
| |
| // Strings. |
| using StringConvertResult = ArgConvertResult<FormatConversionCharSetUnion( |
| FormatConversionCharSetInternal::s, |
| FormatConversionCharSetInternal::v)>; |
| StringConvertResult FormatConvertImpl(const std::string& v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| StringConvertResult FormatConvertImpl(const std::wstring& v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| StringConvertResult FormatConvertImpl(string_view v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| StringConvertResult FormatConvertImpl(std::wstring_view v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| #if !defined(ABSL_USES_STD_STRING_VIEW) |
| inline StringConvertResult FormatConvertImpl(std::string_view v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink) { |
| return FormatConvertImpl(absl::string_view(v.data(), v.size()), conv, sink); |
| } |
| #endif // !ABSL_USES_STD_STRING_VIEW |
| |
| using StringPtrConvertResult = ArgConvertResult<FormatConversionCharSetUnion( |
| FormatConversionCharSetInternal::s, |
| FormatConversionCharSetInternal::p)>; |
| StringPtrConvertResult FormatConvertImpl(const char* v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| StringPtrConvertResult FormatConvertImpl(const wchar_t* v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| // This overload is needed to disambiguate, since `nullptr` could match either |
| // of the other overloads equally well. |
| StringPtrConvertResult FormatConvertImpl(std::nullptr_t, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| |
| template <class AbslCord, typename std::enable_if<std::is_same< |
| AbslCord, absl::Cord>::value>::type* = nullptr> |
| StringConvertResult FormatConvertImpl(const AbslCord& value, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink) { |
| bool is_left = conv.has_left_flag(); |
| size_t space_remaining = 0; |
| |
| int width = conv.width(); |
| if (width >= 0) space_remaining = static_cast<size_t>(width); |
| |
| size_t to_write = value.size(); |
| |
| int precision = conv.precision(); |
| if (precision >= 0) |
| to_write = (std::min)(to_write, static_cast<size_t>(precision)); |
| |
| space_remaining = Excess(to_write, space_remaining); |
| |
| if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' '); |
| |
| for (string_view piece : value.Chunks()) { |
| if (piece.size() > to_write) { |
| piece.remove_suffix(piece.size() - to_write); |
| to_write = 0; |
| } else { |
| to_write -= piece.size(); |
| } |
| sink->Append(piece); |
| if (to_write == 0) { |
| break; |
| } |
| } |
| |
| if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' '); |
| return {true}; |
| } |
| |
| bool ConvertBoolArg(bool v, FormatSinkImpl* sink); |
| |
| // Floats. |
| FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| FloatingConvertResult FormatConvertImpl(long double v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| |
| // Chars. |
| CharConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| CharConvertResult FormatConvertImpl(wchar_t v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| |
| // Ints. |
| IntegralConvertResult FormatConvertImpl(signed char v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| IntegralConvertResult FormatConvertImpl(unsigned char v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| IntegralConvertResult FormatConvertImpl(short v, // NOLINT |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| IntegralConvertResult FormatConvertImpl(unsigned v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| IntegralConvertResult FormatConvertImpl(long v, // NOLINT |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| IntegralConvertResult FormatConvertImpl(long long v, // NOLINT |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| IntegralConvertResult FormatConvertImpl(uint128 v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink); |
| |
| // This function needs to be a template due to ambiguity regarding type |
| // conversions. |
| template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0> |
| IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink) { |
| if (conv.conversion_char() == FormatConversionCharInternal::v) { |
| return {ConvertBoolArg(v, sink)}; |
| } |
| |
| return FormatConvertImpl(static_cast<int>(v), conv, sink); |
| } |
| |
| // We provide this function to help the checker, but it is never defined. |
| // FormatArgImpl will use the underlying Convert functions instead. |
| template <typename T> |
| typename std::enable_if<std::is_enum<T>::value && |
| !HasUserDefinedConvert<T>::value && |
| !HasAbslStringify<T>::value, |
| IntegralConvertResult>::type |
| FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); |
| |
| template <typename T> |
| StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v, |
| FormatConversionSpecImpl conv, |
| FormatSinkImpl* out) { |
| std::ostringstream oss; |
| oss << v.v_; |
| if (!oss) return {false}; |
| return str_format_internal::FormatConvertImpl(oss.str(), conv, out); |
| } |
| |
| // Use templates and dependent types to delay evaluation of the function |
| // until after FormatCountCapture is fully defined. |
| struct FormatCountCaptureHelper { |
| template <class T = int> |
| static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper( |
| const FormatCountCapture& v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink) { |
| const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v; |
| |
| if (conv.conversion_char() != |
| str_format_internal::FormatConversionCharInternal::n) { |
| return {false}; |
| } |
| *v2.p_ = static_cast<int>(sink->size()); |
| return {true}; |
| } |
| }; |
| |
| template <class T = int> |
| ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl( |
| const FormatCountCapture& v, FormatConversionSpecImpl conv, |
| FormatSinkImpl* sink) { |
| return FormatCountCaptureHelper::ConvertHelper(v, conv, sink); |
| } |
| |
| // Helper friend struct to hide implementation details from the public API of |
| // FormatArgImpl. |
| struct FormatArgImplFriend { |
| template <typename Arg> |
| static bool ToInt(Arg arg, int* out) { |
| // A value initialized FormatConversionSpecImpl has a `none` conv, which |
| // tells the dispatcher to run the `int` conversion. |
| return arg.dispatcher_(arg.data_, {}, out); |
| } |
| |
| template <typename Arg> |
| static bool Convert(Arg arg, FormatConversionSpecImpl conv, |
| FormatSinkImpl* out) { |
| return arg.dispatcher_(arg.data_, conv, out); |
| } |
| |
| template <typename Arg> |
| static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) { |
| return arg.dispatcher_; |
| } |
| }; |
| |
| template <typename Arg> |
| constexpr FormatConversionCharSet ArgumentToConv() { |
| using ConvResult = decltype(str_format_internal::FormatConvertImpl( |
| std::declval<const Arg&>(), |
| std::declval<const FormatConversionSpecImpl&>(), |
| std::declval<FormatSinkImpl*>())); |
| return absl::str_format_internal::ExtractCharSet(ConvResult{}); |
| } |
| |
| // A type-erased handle to a format argument. |
| class FormatArgImpl { |
| private: |
| enum { kInlinedSpace = 8 }; |
| |
| using VoidPtr = str_format_internal::VoidPtr; |
| |
| union Data { |
| const void* ptr; |
| const volatile void* volatile_ptr; |
| char buf[kInlinedSpace]; |
| }; |
| |
| using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out); |
| |
| template <typename T> |
| struct store_by_value |
| : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) && |
| (std::is_integral<T>::value || |
| std::is_floating_point<T>::value || |
| std::is_pointer<T>::value || |
| std::is_same<VoidPtr, T>::value)> {}; |
| |
| enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue }; |
| template <typename T> |
| struct storage_policy |
| : std::integral_constant<StoragePolicy, |
| (std::is_volatile<T>::value |
| ? ByVolatilePointer |
| : (store_by_value<T>::value ? ByValue |
| : ByPointer))> { |
| }; |
| |
| // To reduce the number of vtables we will decay values before hand. |
| // Anything with a user-defined Convert will get its own vtable. |
| // For everything else: |
| // - Decay char* and char arrays into `const char*` |
| // - Decay wchar_t* and wchar_t arrays into `const wchar_t*` |
| // - Decay any other pointer to `const void*` |
| // - Decay all enums to the integral promotion of their underlying type. |
| // - Decay function pointers to void*. |
| template <typename T, typename = void> |
| struct DecayType { |
| static constexpr bool kHasUserDefined = |
| str_format_internal::HasUserDefinedConvert<T>::value || |
| HasAbslStringify<T>::value; |
| using type = typename std::conditional< |
| !kHasUserDefined && std::is_convertible<T, const char*>::value, |
| const char*, |
| typename std::conditional< |
| !kHasUserDefined && std::is_convertible<T, const wchar_t*>::value, |
| const wchar_t*, |
| typename std::conditional< |
| !kHasUserDefined && std::is_convertible<T, VoidPtr>::value, |
| VoidPtr, |
| const T&>::type>::type>::type; |
| }; |
| template <typename T> |
| struct DecayType< |
| T, typename std::enable_if< |
| !str_format_internal::HasUserDefinedConvert<T>::value && |
| !HasAbslStringify<T>::value && std::is_enum<T>::value>::type> { |
| using type = decltype(+typename std::underlying_type<T>::type()); |
| }; |
| |
| public: |
| template <typename T> |
| explicit FormatArgImpl(const T& value) { |
| using D = typename DecayType<T>::type; |
| static_assert( |
| std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue, |
| "Decayed types must be stored by value"); |
| Init(static_cast<D>(value)); |
| } |
| |
| private: |
| friend struct str_format_internal::FormatArgImplFriend; |
| template <typename T, StoragePolicy = storage_policy<T>::value> |
| struct Manager; |
| |
| template <typename T> |
| struct Manager<T, ByPointer> { |
| static Data SetValue(const T& value) { |
| Data data; |
| data.ptr = std::addressof(value); |
| return data; |
| } |
| |
| static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); } |
| }; |
| |
| template <typename T> |
| struct Manager<T, ByVolatilePointer> { |
| static Data SetValue(const T& value) { |
| Data data; |
| data.volatile_ptr = &value; |
| return data; |
| } |
| |
| static const T& Value(Data arg) { |
| return *static_cast<const T*>(arg.volatile_ptr); |
| } |
| }; |
| |
| template <typename T> |
| struct Manager<T, ByValue> { |
| static Data SetValue(const T& value) { |
| Data data; |
| memcpy(data.buf, &value, sizeof(value)); |
| return data; |
| } |
| |
| static T Value(Data arg) { |
| T value; |
| memcpy(&value, arg.buf, sizeof(T)); |
| return value; |
| } |
| }; |
| |
| template <typename T> |
| void Init(const T& value) { |
| data_ = Manager<T>::SetValue(value); |
| dispatcher_ = &Dispatch<T>; |
| } |
| |
| template <typename T> |
| static int ToIntVal(const T& val) { |
| using CommonType = typename std::conditional<std::is_signed<T>::value, |
| int64_t, uint64_t>::type; |
| if (static_cast<CommonType>(val) > |
| static_cast<CommonType>((std::numeric_limits<int>::max)())) { |
| return (std::numeric_limits<int>::max)(); |
| } else if (std::is_signed<T>::value && |
| static_cast<CommonType>(val) < |
| static_cast<CommonType>((std::numeric_limits<int>::min)())) { |
| return (std::numeric_limits<int>::min)(); |
| } |
| return static_cast<int>(val); |
| } |
| |
| template <typename T> |
| static bool ToInt(Data arg, int* out, std::true_type /* is_integral */, |
| std::false_type) { |
| *out = ToIntVal(Manager<T>::Value(arg)); |
| return true; |
| } |
| |
| template <typename T> |
| static bool ToInt(Data arg, int* out, std::false_type, |
| std::true_type /* is_enum */) { |
| *out = ToIntVal(static_cast<typename std::underlying_type<T>::type>( |
| Manager<T>::Value(arg))); |
| return true; |
| } |
| |
| template <typename T> |
| static bool ToInt(Data, int*, std::false_type, std::false_type) { |
| return false; |
| } |
| |
| template <typename T> |
| static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) { |
| // A `none` conv indicates that we want the `int` conversion. |
| if (ABSL_PREDICT_FALSE(spec.conversion_char() == |
| FormatConversionCharInternal::kNone)) { |
| return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(), |
| std::is_enum<T>()); |
| } |
| if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(), |
| spec.conversion_char()))) { |
| return false; |
| } |
| return str_format_internal::FormatConvertImpl( |
| Manager<T>::Value(arg), spec, |
| static_cast<FormatSinkImpl*>(out)) |
| .value; |
| } |
| |
| Data data_; |
| Dispatcher dispatcher_; |
| }; |
| |
| #define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \ |
| E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \ |
| void*) |
| |
| #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_NO_WSTRING_VIEW_(...) \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \ |
| __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(bool, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(char, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(signed char, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned char, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(short, __VA_ARGS__); /* NOLINT */ \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned short, /* NOLINT */ \ |
| __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned int, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long, __VA_ARGS__); /* NOLINT */ \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long, /* NOLINT */ \ |
| __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */ \ |
| __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */ \ |
| __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int128, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const wchar_t*, __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::wstring, __VA_ARGS__) |
| |
| #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_NO_WSTRING_VIEW_( \ |
| __VA_ARGS__); \ |
| ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::wstring_view, __VA_ARGS__) |
| |
| ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern); |
| |
| |
| } // namespace str_format_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ |
| *ÏP |
| soong/.intermediates/external/abseil-cpp/absl_strings_cord_internal_hdrs/gen/my_include_dir/absl/strings/internal/cord_rep_btree_navigator.h½O// 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_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_ |
| #define ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_ |
| |
| #include <cassert> |
| #include <iostream> |
| |
| #include "absl/strings/internal/cord_internal.h" |
| #include "absl/strings/internal/cord_rep_btree.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // CordRepBtreeNavigator is a bi-directional navigator allowing callers to |
| // navigate all the (leaf) data edges in a CordRepBtree instance. |
| // |
| // A CordRepBtreeNavigator instance is by default empty. Callers initialize a |
| // navigator instance by calling one of `InitFirst()`, `InitLast()` or |
| // `InitOffset()`, which establishes a current position. Callers can then |
| // navigate using the `Next`, `Previous`, `Skip` and `Seek` methods. |
| // |
| // The navigator instance does not take or adopt a reference on the provided |
| // `tree` on any of the initialization calls. Callers are responsible for |
| // guaranteeing the lifecycle of the provided tree. A navigator instance can |
| // be reset to the empty state by calling `Reset`. |
| // |
| // A navigator only keeps positional state on the 'current data edge', it does |
| // explicitly not keep any 'offset' state. The class does accept and return |
| // offsets in the `Read()`, `Skip()` and 'Seek()` methods as these would |
| // otherwise put a big burden on callers. Callers are expected to maintain |
| // (returned) offset info if they require such granular state. |
| class CordRepBtreeNavigator { |
| public: |
| // The logical position as returned by the Seek() and Skip() functions. |
| // Returns the current leaf edge for the desired seek or skip position and |
| // the offset of that position inside that edge. |
| struct Position { |
| CordRep* edge; |
| size_t offset; |
| }; |
| |
| // The read result as returned by the Read() function. |
| // `tree` contains the resulting tree which is identical to the result |
| // of calling CordRepBtree::SubTree(...) on the tree being navigated. |
| // `n` contains the number of bytes used from the last navigated to |
| // edge of the tree. |
| struct ReadResult { |
| CordRep* tree; |
| size_t n; |
| }; |
| |
| // Returns true if this instance is not empty. |
| explicit operator bool() const; |
| |
| // Returns the tree for this instance or nullptr if empty. |
| CordRepBtree* btree() const; |
| |
| // Returns the data edge of the current position. |
| // Requires this instance to not be empty. |
| CordRep* Current() const; |
| |
| // Resets this navigator to `tree`, returning the first data edge in the tree. |
| CordRep* InitFirst(CordRepBtree* tree); |
| |
| // Resets this navigator to `tree`, returning the last data edge in the tree. |
| CordRep* InitLast(CordRepBtree* tree); |
| |
| // Resets this navigator to `tree` returning the data edge at position |
| // `offset` and the relative offset of `offset` into that data edge. |
| // Returns `Position.edge = nullptr` if the provided offset is greater |
| // than or equal to the length of the tree, in which case the state of |
| // the navigator instance remains unchanged. |
| Position InitOffset(CordRepBtree* tree, size_t offset); |
| |
| // Navigates to the next data edge. |
| // Returns the next data edge or nullptr if there is no next data edge, in |
| // which case the current position remains unchanged. |
| CordRep* Next(); |
| |
| // Navigates to the previous data edge. |
| // Returns the previous data edge or nullptr if there is no previous data |
| // edge, in which case the current position remains unchanged. |
| CordRep* Previous(); |
| |
| // Navigates to the data edge at position `offset`. Returns the navigated to |
| // data edge in `Position.edge` and the relative offset of `offset` into that |
| // data edge in `Position.offset`. Returns `Position.edge = nullptr` if the |
| // provide offset is greater than or equal to the tree's length. |
| Position Seek(size_t offset); |
| |
| // Reads `n` bytes of data starting at offset `edge_offset` of the current |
| // data edge, and returns the result in `ReadResult.tree`. `ReadResult.n` |
| // contains the 'bytes used` from the last / current data edge in the tree. |
| // This allows users that mix regular navigation (using string views) and |
| // 'read into cord' navigation to keep track of the current state, and which |
| // bytes have been consumed from a navigator. |
| // This function returns `ReadResult.tree = nullptr` if the requested length |
| // exceeds the length of the tree starting at the current data edge. |
| ReadResult Read(size_t edge_offset, size_t n); |
| |
| // Skips `n` bytes forward from the current data edge, returning the navigated |
| // to data edge in `Position.edge` and `Position.offset` containing the offset |
| // inside that data edge. Note that the state of the navigator is left |
| // unchanged if `n` is smaller than the length of the current data edge. |
| Position Skip(size_t n); |
| |
| // Resets this instance to the default / empty state. |
| void Reset(); |
| |
| private: |
| // Slow path for Next() if Next() reached the end of a leaf node. Backtracks |
| // up the stack until it finds a node that has a 'next' position available, |
| // and then does a 'front dive' towards the next leaf node. |
| CordRep* NextUp(); |
| |
| // Slow path for Previous() if Previous() reached the beginning of a leaf |
| // node. Backtracks up the stack until it finds a node that has a 'previous' |
| // position available, and then does a 'back dive' towards the previous leaf |
| // node. |
| CordRep* PreviousUp(); |
| |
| // Generic implementation of InitFirst() and InitLast(). |
| template <CordRepBtree::EdgeType edge_type> |
| CordRep* Init(CordRepBtree* tree); |
| |
| // `height_` contains the height of the current tree, or -1 if empty. |
| int height_ = -1; |
| |
| // `index_` and `node_` contain the navigation state as the 'path' to the |
| // current data edge which is at `node_[0]->Edge(index_[0])`. The contents |
| // of these are undefined until the instance is initialized (`height_ >= 0`). |
| uint8_t index_[CordRepBtree::kMaxDepth]; |
| CordRepBtree* node_[CordRepBtree::kMaxDepth]; |
| }; |
| |
| // Returns true if this instance is not empty. |
| inline CordRepBtreeNavigator::operator bool() const { return height_ >= 0; } |
| |
| inline CordRepBtree* CordRepBtreeNavigator::btree() const { |
| return height_ >= 0 ? node_[height_] : nullptr; |
| } |
| |
| inline CordRep* CordRepBtreeNavigator::Current() const { |
| assert(height_ >= 0); |
| return node_[0]->Edge(index_[0]); |
| } |
| |
| inline void CordRepBtreeNavigator::Reset() { height_ = -1; } |
| |
| inline CordRep* CordRepBtreeNavigator::InitFirst(CordRepBtree* tree) { |
| return Init<CordRepBtree::kFront>(tree); |
| } |
| |
| inline CordRep* CordRepBtreeNavigator::InitLast(CordRepBtree* tree) { |
| return Init<CordRepBtree::kBack>(tree); |
| } |
| |
| template <CordRepBtree::EdgeType edge_type> |
| inline CordRep* CordRepBtreeNavigator::Init(CordRepBtree* tree) { |
| assert(tree != nullptr); |
| assert(tree->size() > 0); |
| assert(tree->height() <= CordRepBtree::kMaxHeight); |
| int height = height_ = tree->height(); |
| size_t index = tree->index(edge_type); |
| node_[height] = tree; |
| index_[height] = static_cast<uint8_t>(index); |
| while (--height >= 0) { |
| tree = tree->Edge(index)->btree(); |
| node_[height] = tree; |
| index = tree->index(edge_type); |
| index_[height] = static_cast<uint8_t>(index); |
| } |
| return node_[0]->Edge(index); |
| } |
| |
| inline CordRepBtreeNavigator::Position CordRepBtreeNavigator::Seek( |
| size_t offset) { |
| assert(btree() != nullptr); |
| int height = height_; |
| CordRepBtree* edge = node_[height]; |
| if (ABSL_PREDICT_FALSE(offset >= edge->length)) return {nullptr, 0}; |
| CordRepBtree::Position index = edge->IndexOf(offset); |
| index_[height] = static_cast<uint8_t>(index.index); |
| while (--height >= 0) { |
| edge = edge->Edge(index.index)->btree(); |
| node_[height] = edge; |
| index = edge->IndexOf(index.n); |
| index_[height] = static_cast<uint8_t>(index.index); |
| } |
| return {edge->Edge(index.index), index.n}; |
| } |
| |
| inline CordRepBtreeNavigator::Position CordRepBtreeNavigator::InitOffset( |
| CordRepBtree* tree, size_t offset) { |
| assert(tree != nullptr); |
| assert(tree->height() <= CordRepBtree::kMaxHeight); |
| if (ABSL_PREDICT_FALSE(offset >= tree->length)) return {nullptr, 0}; |
| height_ = tree->height(); |
| node_[height_] = tree; |
| return Seek(offset); |
| } |
| |
| inline CordRep* CordRepBtreeNavigator::Next() { |
| CordRepBtree* edge = node_[0]; |
| return index_[0] == edge->back() ? NextUp() : edge->Edge(++index_[0]); |
| } |
| |
| inline CordRep* CordRepBtreeNavigator::Previous() { |
| CordRepBtree* edge = node_[0]; |
| return index_[0] == edge->begin() ? PreviousUp() : edge->Edge(--index_[0]); |
| } |
| |
| inline CordRep* CordRepBtreeNavigator::NextUp() { |
| assert(index_[0] == node_[0]->back()); |
| CordRepBtree* edge; |
| size_t index; |
| int height = 0; |
| do { |
| if (++height > height_) return nullptr; |
| edge = node_[height]; |
| index = index_[height] + 1; |
| } while (index == edge->end()); |
| index_[height] = static_cast<uint8_t>(index); |
| do { |
| node_[--height] = edge = edge->Edge(index)->btree(); |
| index_[height] = static_cast<uint8_t>(index = edge->begin()); |
| } while (height > 0); |
| return edge->Edge(index); |
| } |
| |
| inline CordRep* CordRepBtreeNavigator::PreviousUp() { |
| assert(index_[0] == node_[0]->begin()); |
| CordRepBtree* edge; |
| size_t index; |
| int height = 0; |
| do { |
| if (++height > height_) return nullptr; |
| edge = node_[height]; |
| index = index_[height]; |
| } while (index == edge->begin()); |
| index_[height] = static_cast<uint8_t>(--index); |
| do { |
| node_[--height] = edge = edge->Edge(index)->btree(); |
| index_[height] = static_cast<uint8_t>(index = edge->back()); |
| } while (height > 0); |
| return edge->Edge(index); |
| } |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_ |
| *¥ |
| wsoong/.intermediates/external/abseil-cpp/absl_base_errno_saver_hdrs/gen/my_include_dir/absl/base/internal/errno_saver.h© |
| // Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_BASE_INTERNAL_ERRNO_SAVER_H_ |
| #define ABSL_BASE_INTERNAL_ERRNO_SAVER_H_ |
| |
| #include <cerrno> |
| |
| #include "absl/base/config.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace base_internal { |
| |
| // `ErrnoSaver` captures the value of `errno` upon construction and restores it |
| // upon deletion. It is used in low-level code and must be super fast. Do not |
| // add instrumentation, even in debug modes. |
| class ErrnoSaver { |
| public: |
| ErrnoSaver() : saved_errno_(errno) {} |
| ~ErrnoSaver() { errno = saved_errno_; } |
| int operator()() const { return saved_errno_; } |
| |
| private: |
| const int saved_errno_; |
| }; |
| |
| } // namespace base_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_BASE_INTERNAL_ERRNO_SAVER_H_ |
| *¸A |
| |soong/.intermediates/external/abseil-cpp/absl_log_internal_check_impl_hdrs/gen/my_include_dir/absl/log/internal/check_impl.h·@// Copyright 2022 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_LOG_INTERNAL_CHECK_IMPL_H_ |
| #define ABSL_LOG_INTERNAL_CHECK_IMPL_H_ |
| |
| #include "absl/base/optimization.h" |
| #include "absl/log/internal/check_op.h" |
| #include "absl/log/internal/conditions.h" |
| #include "absl/log/internal/log_message.h" |
| #include "absl/log/internal/strip.h" |
| |
| // CHECK |
| #define ABSL_LOG_INTERNAL_CHECK_IMPL(condition, condition_text) \ |
| ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, \ |
| ABSL_PREDICT_FALSE(!(condition))) \ |
| ABSL_LOG_INTERNAL_CHECK(condition_text).InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_QCHECK_IMPL(condition, condition_text) \ |
| ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, \ |
| ABSL_PREDICT_FALSE(!(condition))) \ |
| ABSL_LOG_INTERNAL_QCHECK(condition_text).InternalStream() |
| |
| #define ABSL_LOG_INTERNAL_PCHECK_IMPL(condition, condition_text) \ |
| ABSL_LOG_INTERNAL_CHECK_IMPL(condition, condition_text).WithPerror() |
| |
| #ifndef NDEBUG |
| #define ABSL_LOG_INTERNAL_DCHECK_IMPL(condition, condition_text) \ |
| ABSL_LOG_INTERNAL_CHECK_IMPL(condition, condition_text) |
| #else |
| #define ABSL_LOG_INTERNAL_DCHECK_IMPL(condition, condition_text) \ |
| ABSL_LOG_INTERNAL_CHECK_IMPL(true || (condition), "true") |
| #endif |
| |
| // CHECK_EQ |
| #define ABSL_LOG_INTERNAL_CHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_OP(Check_EQ, ==, val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_CHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_OP(Check_NE, !=, val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_CHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_OP(Check_LE, <=, val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_CHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_OP(Check_LT, <, val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_CHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_OP(Check_GE, >=, val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_CHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_OP(Check_GT, >, val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_QCHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_QCHECK_OP(Check_EQ, ==, val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_QCHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_QCHECK_OP(Check_NE, !=, val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_QCHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_QCHECK_OP(Check_LE, <=, val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_QCHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_QCHECK_OP(Check_LT, <, val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_QCHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_QCHECK_OP(Check_GE, >=, val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_QCHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_QCHECK_OP(Check_GT, >, val1, val1_text, val2, val2_text) |
| #ifndef NDEBUG |
| #define ABSL_LOG_INTERNAL_DCHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_EQ_IMPL(val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_DCHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_NE_IMPL(val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_DCHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_LE_IMPL(val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_DCHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_LT_IMPL(val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_DCHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_GE_IMPL(val1, val1_text, val2, val2_text) |
| #define ABSL_LOG_INTERNAL_DCHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_GT_IMPL(val1, val1_text, val2, val2_text) |
| #else // ndef NDEBUG |
| #define ABSL_LOG_INTERNAL_DCHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) |
| #define ABSL_LOG_INTERNAL_DCHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) |
| #define ABSL_LOG_INTERNAL_DCHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) |
| #define ABSL_LOG_INTERNAL_DCHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) |
| #define ABSL_LOG_INTERNAL_DCHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) |
| #define ABSL_LOG_INTERNAL_DCHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ |
| ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) |
| #endif // def NDEBUG |
| |
| // CHECK_OK |
| #define ABSL_LOG_INTERNAL_CHECK_OK_IMPL(status, status_text) \ |
| ABSL_LOG_INTERNAL_CHECK_OK(status, status_text) |
| #define ABSL_LOG_INTERNAL_QCHECK_OK_IMPL(status, status_text) \ |
| ABSL_LOG_INTERNAL_QCHECK_OK(status, status_text) |
| #ifndef NDEBUG |
| #define ABSL_LOG_INTERNAL_DCHECK_OK_IMPL(status, status_text) \ |
| ABSL_LOG_INTERNAL_CHECK_OK(status, status_text) |
| #else |
| #define ABSL_LOG_INTERNAL_DCHECK_OK_IMPL(status, status_text) \ |
| ABSL_LOG_INTERNAL_DCHECK_NOP(status, nullptr) |
| #endif |
| |
| // CHECK_STREQ |
| #define ABSL_LOG_INTERNAL_CHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_STROP(strcmp, ==, true, s1, s1_text, s2, s2_text) |
| #define ABSL_LOG_INTERNAL_CHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_STROP(strcmp, !=, false, s1, s1_text, s2, s2_text) |
| #define ABSL_LOG_INTERNAL_CHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_STROP(strcasecmp, ==, true, s1, s1_text, s2, s2_text) |
| #define ABSL_LOG_INTERNAL_CHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_STROP(strcasecmp, !=, false, s1, s1_text, s2, s2_text) |
| #define ABSL_LOG_INTERNAL_QCHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_QCHECK_STROP(strcmp, ==, true, s1, s1_text, s2, s2_text) |
| #define ABSL_LOG_INTERNAL_QCHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_QCHECK_STROP(strcmp, !=, false, s1, s1_text, s2, s2_text) |
| #define ABSL_LOG_INTERNAL_QCHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_QCHECK_STROP(strcasecmp, ==, true, s1, s1_text, s2, s2_text) |
| #define ABSL_LOG_INTERNAL_QCHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_QCHECK_STROP(strcasecmp, !=, false, s1, s1_text, s2, \ |
| s2_text) |
| #ifndef NDEBUG |
| #define ABSL_LOG_INTERNAL_DCHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) |
| #define ABSL_LOG_INTERNAL_DCHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) |
| #define ABSL_LOG_INTERNAL_DCHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) |
| #define ABSL_LOG_INTERNAL_DCHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_CHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) |
| #else // ndef NDEBUG |
| #define ABSL_LOG_INTERNAL_DCHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2) |
| #define ABSL_LOG_INTERNAL_DCHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2) |
| #define ABSL_LOG_INTERNAL_DCHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2) |
| #define ABSL_LOG_INTERNAL_DCHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ |
| ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2) |
| #endif // def NDEBUG |
| |
| #endif // ABSL_LOG_INTERNAL_CHECK_IMPL_H_ |
| *³9 |
| wsoong/.intermediates/external/abseil-cpp/absl_container_common_hdrs/gen/my_include_dir/absl/container/internal/common.h·8// Copyright 2018 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_CONTAINER_INTERNAL_COMMON_H_ |
| #define ABSL_CONTAINER_INTERNAL_COMMON_H_ |
| |
| #include <cassert> |
| #include <type_traits> |
| |
| #include "absl/meta/type_traits.h" |
| #include "absl/types/optional.h" |
| |
| // TODO(b/402804213): Clean up these macros when no longer needed. |
| #define ABSL_INTERNAL_SINGLE_ARG(...) __VA_ARGS__ |
| |
| #define ABSL_INTERNAL_IF_true(if_satisfied, ...) if_satisfied |
| #define ABSL_INTERNAL_IF_false(if_satisfied, ...) __VA_ARGS__ |
| |
| #define ABSL_INTERNAL_IF_true_AND_true ABSL_INTERNAL_IF_true |
| #define ABSL_INTERNAL_IF_false_AND_false ABSL_INTERNAL_IF_false |
| #define ABSL_INTERNAL_IF_true_AND_false ABSL_INTERNAL_IF_false_AND_false |
| #define ABSL_INTERNAL_IF_false_AND_true ABSL_INTERNAL_IF_false_AND_false |
| |
| #define ABSL_INTERNAL_IF_true_OR_true ABSL_INTERNAL_IF_true |
| #define ABSL_INTERNAL_IF_false_OR_false ABSL_INTERNAL_IF_false |
| #define ABSL_INTERNAL_IF_true_OR_false ABSL_INTERNAL_IF_true_OR_true |
| #define ABSL_INTERNAL_IF_false_OR_true ABSL_INTERNAL_IF_true_OR_true |
| |
| #define ABSL_INTERNAL_IF_true_NOR_true ABSL_INTERNAL_IF_false_AND_false |
| #define ABSL_INTERNAL_IF_false_NOR_false ABSL_INTERNAL_IF_true_AND_true |
| #define ABSL_INTERNAL_IF_true_NOR_false ABSL_INTERNAL_IF_false_AND_true |
| #define ABSL_INTERNAL_IF_false_NOR_true ABSL_INTERNAL_IF_true_AND_false |
| |
| #define ABSL_INTERNAL_COMMA , |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace container_internal { |
| |
| // TODO(b/402804213): Clean up these traits when no longer needed or |
| // deduplicate them with absl::functional_internal::EnableIf. |
| template <class Cond> |
| using EnableIf = std::enable_if_t<Cond::value, int>; |
| |
| template <bool Value, class T> |
| using HasValue = std::conditional_t<Value, T, absl::negation<T>>; |
| |
| template <class T> |
| struct IfRRef { |
| template <class Other> |
| using AddPtr = Other; |
| }; |
| |
| template <class T> |
| struct IfRRef<T&&> { |
| template <class Other> |
| using AddPtr = Other*; |
| }; |
| |
| template <class, class = void> |
| struct IsTransparent : std::false_type {}; |
| template <class T> |
| struct IsTransparent<T, absl::void_t<typename T::is_transparent>> |
| : std::true_type {}; |
| |
| template <bool is_transparent> |
| struct KeyArg { |
| // Transparent. Forward `K`. |
| template <typename K, typename key_type> |
| using type = K; |
| }; |
| |
| template <> |
| struct KeyArg<false> { |
| // Not transparent. Always use `key_type`. |
| template <typename K, typename key_type> |
| using type = key_type; |
| }; |
| |
| // The node_handle concept from C++17. |
| // We specialize node_handle for sets and maps. node_handle_base holds the |
| // common API of both. |
| template <typename PolicyTraits, typename Alloc> |
| class node_handle_base { |
| protected: |
| using slot_type = typename PolicyTraits::slot_type; |
| |
| public: |
| using allocator_type = Alloc; |
| |
| constexpr node_handle_base() = default; |
| node_handle_base(node_handle_base&& other) noexcept { |
| *this = std::move(other); |
| } |
| ~node_handle_base() { destroy(); } |
| node_handle_base& operator=(node_handle_base&& other) noexcept { |
| destroy(); |
| if (!other.empty()) { |
| alloc_ = other.alloc_; |
| PolicyTraits::transfer(alloc(), slot(), other.slot()); |
| other.reset(); |
| } |
| return *this; |
| } |
| |
| bool empty() const noexcept { return !alloc_; } |
| explicit operator bool() const noexcept { return !empty(); } |
| allocator_type get_allocator() const { return *alloc_; } |
| |
| protected: |
| friend struct CommonAccess; |
| |
| struct transfer_tag_t {}; |
| node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s) |
| : alloc_(a) { |
| PolicyTraits::transfer(alloc(), slot(), s); |
| } |
| |
| struct construct_tag_t {}; |
| template <typename... Args> |
| node_handle_base(construct_tag_t, const allocator_type& a, Args&&... args) |
| : alloc_(a) { |
| PolicyTraits::construct(alloc(), slot(), std::forward<Args>(args)...); |
| } |
| |
| void destroy() { |
| if (!empty()) { |
| PolicyTraits::destroy(alloc(), slot()); |
| reset(); |
| } |
| } |
| |
| void reset() { |
| assert(alloc_.has_value()); |
| alloc_ = absl::nullopt; |
| } |
| |
| slot_type* slot() const { |
| assert(!empty()); |
| return reinterpret_cast<slot_type*>(std::addressof(slot_space_)); |
| } |
| allocator_type* alloc() { return std::addressof(*alloc_); } |
| |
| private: |
| absl::optional<allocator_type> alloc_ = {}; |
| alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {}; |
| }; |
| |
| // For sets. |
| template <typename Policy, typename PolicyTraits, typename Alloc, |
| typename = void> |
| class node_handle : public node_handle_base<PolicyTraits, Alloc> { |
| using Base = node_handle_base<PolicyTraits, Alloc>; |
| |
| public: |
| using value_type = typename PolicyTraits::value_type; |
| |
| constexpr node_handle() {} |
| |
| value_type& value() const { return PolicyTraits::element(this->slot()); } |
| |
| private: |
| friend struct CommonAccess; |
| |
| using Base::Base; |
| }; |
| |
| // For maps. |
| template <typename Policy, typename PolicyTraits, typename Alloc> |
| class node_handle<Policy, PolicyTraits, Alloc, |
| absl::void_t<typename Policy::mapped_type>> |
| : public node_handle_base<PolicyTraits, Alloc> { |
| using Base = node_handle_base<PolicyTraits, Alloc>; |
| using slot_type = typename PolicyTraits::slot_type; |
| |
| public: |
| using key_type = typename Policy::key_type; |
| using mapped_type = typename Policy::mapped_type; |
| |
| constexpr node_handle() {} |
| |
| // When C++17 is available, we can use std::launder to provide mutable |
| // access to the key. Otherwise, we provide const access. |
| auto key() const |
| -> decltype(PolicyTraits::mutable_key(std::declval<slot_type*>())) { |
| return PolicyTraits::mutable_key(this->slot()); |
| } |
| |
| mapped_type& mapped() const { |
| return PolicyTraits::value(&PolicyTraits::element(this->slot())); |
| } |
| |
| private: |
| friend struct CommonAccess; |
| |
| using Base::Base; |
| }; |
| |
| // Provide access to non-public node-handle functions. |
| struct CommonAccess { |
| template <typename Node> |
| static auto GetSlot(const Node& node) -> decltype(node.slot()) { |
| return node.slot(); |
| } |
| |
| template <typename Node> |
| static void Destroy(Node* node) { |
| node->destroy(); |
| } |
| |
| template <typename Node> |
| static void Reset(Node* node) { |
| node->reset(); |
| } |
| |
| template <typename T, typename... Args> |
| static T Transfer(Args&&... args) { |
| return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...); |
| } |
| |
| template <typename T, typename... Args> |
| static T Construct(Args&&... args) { |
| return T(typename T::construct_tag_t{}, std::forward<Args>(args)...); |
| } |
| }; |
| |
| // Implement the insert_return_type<> concept of C++17. |
| template <class Iterator, class NodeType> |
| struct InsertReturnType { |
| Iterator position; |
| bool inserted; |
| NodeType node; |
| }; |
| |
| } // namespace container_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CONTAINER_INTERNAL_COMMON_H_ |
| * |
| soong/.intermediates/external/abseil-cpp/absl_strings_cordz_statistics_hdrs/gen/my_include_dir/absl/strings/internal/cordz_statistics.hû// Copyright 2019 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_CORDZ_STATISTICS_H_ |
| #define ABSL_STRINGS_INTERNAL_CORDZ_STATISTICS_H_ |
| |
| #include <cstdint> |
| |
| #include "absl/base/config.h" |
| #include "absl/strings/internal/cordz_update_tracker.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // CordzStatistics captures some meta information about a Cord's shape. |
| struct CordzStatistics { |
| using MethodIdentifier = CordzUpdateTracker::MethodIdentifier; |
| |
| // Node counts information |
| struct NodeCounts { |
| size_t flat = 0; // #flats |
| size_t flat_64 = 0; // #flats up to 64 bytes |
| size_t flat_128 = 0; // #flats up to 128 bytes |
| size_t flat_256 = 0; // #flats up to 256 bytes |
| size_t flat_512 = 0; // #flats up to 512 bytes |
| size_t flat_1k = 0; // #flats up to 1K bytes |
| size_t external = 0; // #external reps |
| size_t substring = 0; // #substring reps |
| size_t concat = 0; // #concat reps |
| size_t ring = 0; // #ring buffer reps |
| size_t btree = 0; // #btree reps |
| size_t crc = 0; // #crc reps |
| }; |
| |
| // The size of the cord in bytes. This matches the result of Cord::size(). |
| size_t size = 0; |
| |
| // The estimated memory used by the sampled cord. This value matches the |
| // value as reported by Cord::EstimatedMemoryUsage(). |
| // A value of 0 implies the property has not been recorded. |
| size_t estimated_memory_usage = 0; |
| |
| // The effective memory used by the sampled cord, inversely weighted by the |
| // effective indegree of each allocated node. This is a representation of the |
| // fair share of memory usage that should be attributed to the sampled cord. |
| // This value is more useful for cases where one or more nodes are referenced |
| // by multiple Cord instances, and for cases where a Cord includes the same |
| // node multiple times (either directly or indirectly). |
| // A value of 0 implies the property has not been recorded. |
| size_t estimated_fair_share_memory_usage = 0; |
| |
| // The total number of nodes referenced by this cord. |
| // For ring buffer Cords, this includes the 'ring buffer' node. |
| // For btree Cords, this includes all 'CordRepBtree' tree nodes as well as all |
| // the substring, flat and external nodes referenced by the tree. |
| // A value of 0 implies the property has not been recorded. |
| size_t node_count = 0; |
| |
| // Detailed node counts per type |
| NodeCounts node_counts; |
| |
| // The cord method responsible for sampling the cord. |
| MethodIdentifier method = MethodIdentifier::kUnknown; |
| |
| // The cord method responsible for sampling the parent cord if applicable. |
| MethodIdentifier parent_method = MethodIdentifier::kUnknown; |
| |
| // Update tracker tracking invocation count per cord method. |
| CordzUpdateTracker update_tracker; |
| }; |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORDZ_STATISTICS_H_ |
| *õ¦ |
| usoong/.intermediates/external/abseil-cpp/absl_container_btree_hdrs/gen/my_include_dir/absl/container/internal/btree.hú¥// 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. |
| |
| // A btree implementation of the STL set and map interfaces. A btree is smaller |
| // and generally also faster than STL set/map (refer to the benchmarks below). |
| // The red-black tree implementation of STL set/map has an overhead of 3 |
| // pointers (left, right and parent) plus the node color information for each |
| // stored value. So a set<int32_t> consumes 40 bytes for each value stored in |
| // 64-bit mode. This btree implementation stores multiple values on fixed |
| // size nodes (usually 256 bytes) and doesn't store child pointers for leaf |
| // nodes. The result is that a btree_set<int32_t> may use much less memory per |
| // stored value. For the random insertion benchmark in btree_bench.cc, a |
| // btree_set<int32_t> with node-size of 256 uses 5.1 bytes per stored value. |
| // |
| // The packing of multiple values on to each node of a btree has another effect |
| // besides better space utilization: better cache locality due to fewer cache |
| // lines being accessed. Better cache locality translates into faster |
| // operations. |
| // |
| // CAVEATS |
| // |
| // Insertions and deletions on a btree can cause splitting, merging or |
| // rebalancing of btree nodes. And even without these operations, insertions |
| // and deletions on a btree will move values around within a node. In both |
| // cases, the result is that insertions and deletions can invalidate iterators |
| // pointing to values other than the one being inserted/deleted. Therefore, this |
| // container does not provide pointer stability. This is notably different from |
| // STL set/map which takes care to not invalidate iterators on insert/erase |
| // except, of course, for iterators pointing to the value being erased. A |
| // partial workaround when erasing is available: erase() returns an iterator |
| // pointing to the item just after the one that was erased (or end() if none |
| // exists). |
| |
| #ifndef ABSL_CONTAINER_INTERNAL_BTREE_H_ |
| #define ABSL_CONTAINER_INTERNAL_BTREE_H_ |
| |
| #include <algorithm> |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <functional> |
| #include <iterator> |
| #include <limits> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/internal/raw_logging.h" |
| #include "absl/base/macros.h" |
| #include "absl/base/optimization.h" |
| #include "absl/container/internal/common.h" |
| #include "absl/container/internal/common_policy_traits.h" |
| #include "absl/container/internal/compressed_tuple.h" |
| #include "absl/container/internal/container_memory.h" |
| #include "absl/container/internal/layout.h" |
| #include "absl/memory/memory.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/strings/cord.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/types/compare.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace container_internal { |
| |
| #ifdef ABSL_BTREE_ENABLE_GENERATIONS |
| #error ABSL_BTREE_ENABLE_GENERATIONS cannot be directly set |
| #elif (defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ |
| defined(ABSL_HAVE_HWADDRESS_SANITIZER) || \ |
| defined(ABSL_HAVE_MEMORY_SANITIZER)) && \ |
| !defined(NDEBUG_SANITIZER) // If defined, performance is important. |
| // When compiled in sanitizer mode, we add generation integers to the nodes and |
| // iterators. When iterators are used, we validate that the container has not |
| // been mutated since the iterator was constructed. |
| #define ABSL_BTREE_ENABLE_GENERATIONS |
| #endif |
| |
| #ifdef ABSL_BTREE_ENABLE_GENERATIONS |
| constexpr bool BtreeGenerationsEnabled() { return true; } |
| #else |
| constexpr bool BtreeGenerationsEnabled() { return false; } |
| #endif |
| |
| template <typename Compare, typename T, typename U> |
| using compare_result_t = absl::result_of_t<const Compare(const T &, const U &)>; |
| |
| // A helper class that indicates if the Compare parameter is a key-compare-to |
| // comparator. |
| template <typename Compare, typename T> |
| using btree_is_key_compare_to = |
| std::is_convertible<compare_result_t<Compare, T, T>, absl::weak_ordering>; |
| |
| struct StringBtreeDefaultLess { |
| using is_transparent = void; |
| |
| StringBtreeDefaultLess() = default; |
| |
| // Compatibility constructor. |
| StringBtreeDefaultLess(std::less<std::string>) {} // NOLINT |
| StringBtreeDefaultLess(std::less<absl::string_view>) {} // NOLINT |
| |
| // Allow converting to std::less for use in key_comp()/value_comp(). |
| explicit operator std::less<std::string>() const { return {}; } |
| explicit operator std::less<absl::string_view>() const { return {}; } |
| explicit operator std::less<absl::Cord>() const { return {}; } |
| |
| absl::weak_ordering operator()(absl::string_view lhs, |
| absl::string_view rhs) const { |
| return compare_internal::compare_result_as_ordering(lhs.compare(rhs)); |
| } |
| StringBtreeDefaultLess(std::less<absl::Cord>) {} // NOLINT |
| absl::weak_ordering operator()(const absl::Cord &lhs, |
| const absl::Cord &rhs) const { |
| return compare_internal::compare_result_as_ordering(lhs.Compare(rhs)); |
| } |
| absl::weak_ordering operator()(const absl::Cord &lhs, |
| absl::string_view rhs) const { |
| return compare_internal::compare_result_as_ordering(lhs.Compare(rhs)); |
| } |
| absl::weak_ordering operator()(absl::string_view lhs, |
| const absl::Cord &rhs) const { |
| return compare_internal::compare_result_as_ordering(-rhs.Compare(lhs)); |
| } |
| }; |
| |
| struct StringBtreeDefaultGreater { |
| using is_transparent = void; |
| |
| StringBtreeDefaultGreater() = default; |
| |
| StringBtreeDefaultGreater(std::greater<std::string>) {} // NOLINT |
| StringBtreeDefaultGreater(std::greater<absl::string_view>) {} // NOLINT |
| |
| // Allow converting to std::greater for use in key_comp()/value_comp(). |
| explicit operator std::greater<std::string>() const { return {}; } |
| explicit operator std::greater<absl::string_view>() const { return {}; } |
| explicit operator std::greater<absl::Cord>() const { return {}; } |
| |
| absl::weak_ordering operator()(absl::string_view lhs, |
| absl::string_view rhs) const { |
| return compare_internal::compare_result_as_ordering(rhs.compare(lhs)); |
| } |
| StringBtreeDefaultGreater(std::greater<absl::Cord>) {} // NOLINT |
| absl::weak_ordering operator()(const absl::Cord &lhs, |
| const absl::Cord &rhs) const { |
| return compare_internal::compare_result_as_ordering(rhs.Compare(lhs)); |
| } |
| absl::weak_ordering operator()(const absl::Cord &lhs, |
| absl::string_view rhs) const { |
| return compare_internal::compare_result_as_ordering(-lhs.Compare(rhs)); |
| } |
| absl::weak_ordering operator()(absl::string_view lhs, |
| const absl::Cord &rhs) const { |
| return compare_internal::compare_result_as_ordering(rhs.Compare(lhs)); |
| } |
| }; |
| |
| // See below comments for checked_compare. |
| template <typename Compare, bool is_class = std::is_class<Compare>::value> |
| struct checked_compare_base : Compare { |
| using Compare::Compare; |
| explicit checked_compare_base(Compare c) : Compare(std::move(c)) {} |
| const Compare &comp() const { return *this; } |
| }; |
| template <typename Compare> |
| struct checked_compare_base<Compare, false> { |
| explicit checked_compare_base(Compare c) : compare(std::move(c)) {} |
| const Compare &comp() const { return compare; } |
| Compare compare; |
| }; |
| |
| // A mechanism for opting out of checked_compare for use only in btree_test.cc. |
| struct BtreeTestOnlyCheckedCompareOptOutBase {}; |
| |
| // A helper class to adapt the specified comparator for two use cases: |
| // (1) When using common Abseil string types with common comparison functors, |
| // convert a boolean comparison into a three-way comparison that returns an |
| // `absl::weak_ordering`. This helper class is specialized for |
| // less<std::string>, greater<std::string>, less<string_view>, |
| // greater<string_view>, less<absl::Cord>, and greater<absl::Cord>. |
| // (2) Adapt the comparator to diagnose cases of non-strict-weak-ordering (see |
| // https://en.cppreference.com/w/cpp/named_req/Compare) in debug mode. Whenever |
| // a comparison is made, we will make assertions to verify that the comparator |
| // is valid. |
| template <typename Compare, typename Key> |
| struct key_compare_adapter { |
| // Inherit from checked_compare_base to support function pointers and also |
| // keep empty-base-optimization (EBO) support for classes. |
| // Note: we can't use CompressedTuple here because that would interfere |
| // with the EBO for `btree::rightmost_`. `btree::rightmost_` is itself a |
| // CompressedTuple and nested `CompressedTuple`s don't support EBO. |
| // TODO(b/214288561): use CompressedTuple instead once it supports EBO for |
| // nested `CompressedTuple`s. |
| struct checked_compare : checked_compare_base<Compare> { |
| private: |
| using Base = typename checked_compare::checked_compare_base; |
| using Base::comp; |
| |
| // If possible, returns whether `t` is equivalent to itself. We can only do |
| // this for `Key`s because we can't be sure that it's safe to call |
| // `comp()(k, k)` otherwise. Even if SFINAE allows it, there could be a |
| // compilation failure inside the implementation of the comparison operator. |
| bool is_self_equivalent(const Key &k) const { |
| // Note: this works for both boolean and three-way comparators. |
| return comp()(k, k) == 0; |
| } |
| // If we can't compare `t` with itself, returns true unconditionally. |
| template <typename T> |
| bool is_self_equivalent(const T &) const { |
| return true; |
| } |
| |
| public: |
| using Base::Base; |
| checked_compare(Compare cmp) : Base(std::move(cmp)) {} // NOLINT |
| |
| // Allow converting to Compare for use in key_comp()/value_comp(). |
| explicit operator Compare() const { return comp(); } |
| |
| template <typename T, typename U, |
| absl::enable_if_t< |
| std::is_same<bool, compare_result_t<Compare, T, U>>::value, |
| int> = 0> |
| bool operator()(const T &lhs, const U &rhs) const { |
| // NOTE: if any of these assertions fail, then the comparator does not |
| // establish a strict-weak-ordering (see |
| // https://en.cppreference.com/w/cpp/named_req/Compare). |
| assert(is_self_equivalent(lhs)); |
| assert(is_self_equivalent(rhs)); |
| const bool lhs_comp_rhs = comp()(lhs, rhs); |
| assert(!lhs_comp_rhs || !comp()(rhs, lhs)); |
| return lhs_comp_rhs; |
| } |
| |
| template < |
| typename T, typename U, |
| absl::enable_if_t<std::is_convertible<compare_result_t<Compare, T, U>, |
| absl::weak_ordering>::value, |
| int> = 0> |
| absl::weak_ordering operator()(const T &lhs, const U &rhs) const { |
| // NOTE: if any of these assertions fail, then the comparator does not |
| // establish a strict-weak-ordering (see |
| // https://en.cppreference.com/w/cpp/named_req/Compare). |
| assert(is_self_equivalent(lhs)); |
| assert(is_self_equivalent(rhs)); |
| const absl::weak_ordering lhs_comp_rhs = comp()(lhs, rhs); |
| #ifndef NDEBUG |
| const absl::weak_ordering rhs_comp_lhs = comp()(rhs, lhs); |
| if (lhs_comp_rhs > 0) { |
| assert(rhs_comp_lhs < 0 && "lhs_comp_rhs > 0 -> rhs_comp_lhs < 0"); |
| } else if (lhs_comp_rhs == 0) { |
| assert(rhs_comp_lhs == 0 && "lhs_comp_rhs == 0 -> rhs_comp_lhs == 0"); |
| } else { |
| assert(rhs_comp_lhs > 0 && "lhs_comp_rhs < 0 -> rhs_comp_lhs > 0"); |
| } |
| #endif |
| return lhs_comp_rhs; |
| } |
| }; |
| using type = absl::conditional_t< |
| std::is_base_of<BtreeTestOnlyCheckedCompareOptOutBase, Compare>::value, |
| Compare, checked_compare>; |
| }; |
| |
| template <> |
| struct key_compare_adapter<std::less<std::string>, std::string> { |
| using type = StringBtreeDefaultLess; |
| }; |
| |
| template <> |
| struct key_compare_adapter<std::greater<std::string>, std::string> { |
| using type = StringBtreeDefaultGreater; |
| }; |
| |
| template <> |
| struct key_compare_adapter<std::less<absl::string_view>, absl::string_view> { |
| using type = StringBtreeDefaultLess; |
| }; |
| |
| template <> |
| struct key_compare_adapter<std::greater<absl::string_view>, absl::string_view> { |
| using type = StringBtreeDefaultGreater; |
| }; |
| |
| template <> |
| struct key_compare_adapter<std::less<absl::Cord>, absl::Cord> { |
| using type = StringBtreeDefaultLess; |
| }; |
| |
| template <> |
| struct key_compare_adapter<std::greater<absl::Cord>, absl::Cord> { |
| using type = StringBtreeDefaultGreater; |
| }; |
| |
| // Detects an 'absl_btree_prefer_linear_node_search' member. This is |
| // a protocol used as an opt-in or opt-out of linear search. |
| // |
| // For example, this would be useful for key types that wrap an integer |
| // and define their own cheap operator<(). For example: |
| // |
| // class K { |
| // public: |
| // using absl_btree_prefer_linear_node_search = std::true_type; |
| // ... |
| // private: |
| // friend bool operator<(K a, K b) { return a.k_ < b.k_; } |
| // int k_; |
| // }; |
| // |
| // btree_map<K, V> m; // Uses linear search |
| // |
| // If T has the preference tag, then it has a preference. |
| // Btree will use the tag's truth value. |
| template <typename T, typename = void> |
| struct has_linear_node_search_preference : std::false_type {}; |
| template <typename T, typename = void> |
| struct prefers_linear_node_search : std::false_type {}; |
| template <typename T> |
| struct has_linear_node_search_preference< |
| T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>> |
| : std::true_type {}; |
| template <typename T> |
| struct prefers_linear_node_search< |
| T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>> |
| : T::absl_btree_prefer_linear_node_search {}; |
| |
| template <typename Compare, typename Key> |
| constexpr bool compare_has_valid_result_type() { |
| using compare_result_type = compare_result_t<Compare, Key, Key>; |
| return std::is_same<compare_result_type, bool>::value || |
| std::is_convertible<compare_result_type, absl::weak_ordering>::value; |
| } |
| |
| template <typename original_key_compare, typename value_type> |
| class map_value_compare { |
| template <typename Params> |
| friend class btree; |
| |
| // Note: this `protected` is part of the API of std::map::value_compare. See |
| // https://en.cppreference.com/w/cpp/container/map/value_compare. |
| protected: |
| explicit map_value_compare(original_key_compare c) : comp(std::move(c)) {} |
| |
| original_key_compare comp; // NOLINT |
| |
| public: |
| auto operator()(const value_type &lhs, const value_type &rhs) const |
| -> decltype(comp(lhs.first, rhs.first)) { |
| return comp(lhs.first, rhs.first); |
| } |
| }; |
| |
| template <typename Key, typename Compare, typename Alloc, int TargetNodeSize, |
| bool IsMulti, bool IsMap, typename SlotPolicy> |
| struct common_params : common_policy_traits<SlotPolicy> { |
| using original_key_compare = Compare; |
| |
| // If Compare is a common comparator for a string-like type, then we adapt it |
| // to use heterogeneous lookup and to be a key-compare-to comparator. |
| // We also adapt the comparator to diagnose invalid comparators in debug mode. |
| // We disable this when `Compare` is invalid in a way that will cause |
| // adaptation to fail (having invalid return type) so that we can give a |
| // better compilation failure in static_assert_validation. If we don't do |
| // this, then there will be cascading compilation failures that are confusing |
| // for users. |
| using key_compare = |
| absl::conditional_t<!compare_has_valid_result_type<Compare, Key>(), |
| Compare, |
| typename key_compare_adapter<Compare, Key>::type>; |
| |
| static constexpr bool kIsKeyCompareStringAdapted = |
| std::is_same<key_compare, StringBtreeDefaultLess>::value || |
| std::is_same<key_compare, StringBtreeDefaultGreater>::value; |
| static constexpr bool kIsKeyCompareTransparent = |
| IsTransparent<original_key_compare>::value || kIsKeyCompareStringAdapted; |
| |
| // A type which indicates if we have a key-compare-to functor or a plain old |
| // key-compare functor. |
| using is_key_compare_to = btree_is_key_compare_to<key_compare, Key>; |
| |
| using allocator_type = Alloc; |
| using key_type = Key; |
| using size_type = size_t; |
| using difference_type = ptrdiff_t; |
| |
| using slot_policy = SlotPolicy; |
| using slot_type = typename slot_policy::slot_type; |
| using value_type = typename slot_policy::value_type; |
| using init_type = typename slot_policy::mutable_value_type; |
| using pointer = value_type *; |
| using const_pointer = const value_type *; |
| using reference = value_type &; |
| using const_reference = const value_type &; |
| |
| using value_compare = |
| absl::conditional_t<IsMap, |
| map_value_compare<original_key_compare, value_type>, |
| original_key_compare>; |
| using is_map_container = std::integral_constant<bool, IsMap>; |
| |
| // For the given lookup key type, returns whether we can have multiple |
| // equivalent keys in the btree. If this is a multi-container, then we can. |
| // Otherwise, we can have multiple equivalent keys only if all of the |
| // following conditions are met: |
| // - The comparator is transparent. |
| // - The lookup key type is not the same as key_type. |
| // - The comparator is not a StringBtreeDefault{Less,Greater} comparator |
| // that we know has the same equivalence classes for all lookup types. |
| template <typename LookupKey> |
| constexpr static bool can_have_multiple_equivalent_keys() { |
| return IsMulti || (IsTransparent<key_compare>::value && |
| !std::is_same<LookupKey, Key>::value && |
| !kIsKeyCompareStringAdapted); |
| } |
| |
| enum { |
| kTargetNodeSize = TargetNodeSize, |
| |
| // Upper bound for the available space for slots. This is largest for leaf |
| // nodes, which have overhead of at least a pointer + 4 bytes (for storing |
| // 3 field_types and an enum). |
| kNodeSlotSpace = TargetNodeSize - /*minimum overhead=*/(sizeof(void *) + 4), |
| }; |
| |
| // This is an integral type large enough to hold as many slots as will fit a |
| // node of TargetNodeSize bytes. |
| using node_count_type = |
| absl::conditional_t<(kNodeSlotSpace / sizeof(slot_type) > |
| (std::numeric_limits<uint8_t>::max)()), |
| uint16_t, uint8_t>; // NOLINT |
| }; |
| |
| // An adapter class that converts a lower-bound compare into an upper-bound |
| // compare. Note: there is no need to make a version of this adapter specialized |
| // for key-compare-to functors because the upper-bound (the first value greater |
| // than the input) is never an exact match. |
| template <typename Compare> |
| struct upper_bound_adapter { |
| explicit upper_bound_adapter(const Compare &c) : comp(c) {} |
| template <typename K1, typename K2> |
| bool operator()(const K1 &a, const K2 &b) const { |
| // Returns true when a is not greater than b. |
| return !compare_internal::compare_result_as_less_than(comp(b, a)); |
| } |
| |
| private: |
| Compare comp; |
| }; |
| |
| enum class MatchKind : uint8_t { kEq, kNe }; |
| |
| template <typename V, bool IsCompareTo> |
| struct SearchResult { |
| V value; |
| MatchKind match; |
| |
| static constexpr bool HasMatch() { return true; } |
| bool IsEq() const { return match == MatchKind::kEq; } |
| }; |
| |
| // When we don't use CompareTo, `match` is not present. |
| // This ensures that callers can't use it accidentally when it provides no |
| // useful information. |
| template <typename V> |
| struct SearchResult<V, false> { |
| SearchResult() = default; |
| explicit SearchResult(V v) : value(v) {} |
| SearchResult(V v, MatchKind /*match*/) : value(v) {} |
| |
| V value; |
| |
| static constexpr bool HasMatch() { return false; } |
| static constexpr bool IsEq() { return false; } |
| }; |
| |
| // A node in the btree holding. The same node type is used for both internal |
| // and leaf nodes in the btree, though the nodes are allocated in such a way |
| // that the children array is only valid in internal nodes. |
| template <typename Params> |
| class btree_node { |
| using is_key_compare_to = typename Params::is_key_compare_to; |
| using field_type = typename Params::node_count_type; |
| using allocator_type = typename Params::allocator_type; |
| using slot_type = typename Params::slot_type; |
| using original_key_compare = typename Params::original_key_compare; |
| |
| public: |
| using params_type = Params; |
| using key_type = typename Params::key_type; |
| using value_type = typename Params::value_type; |
| using pointer = typename Params::pointer; |
| using const_pointer = typename Params::const_pointer; |
| using reference = typename Params::reference; |
| using const_reference = typename Params::const_reference; |
| using key_compare = typename Params::key_compare; |
| using size_type = typename Params::size_type; |
| using difference_type = typename Params::difference_type; |
| |
| // Btree decides whether to use linear node search as follows: |
| // - If the comparator expresses a preference, use that. |
| // - If the key expresses a preference, use that. |
| // - If the key is arithmetic and the comparator is std::less or |
| // std::greater, choose linear. |
| // - Otherwise, choose binary. |
| // TODO(ezb): Might make sense to add condition(s) based on node-size. |
| using use_linear_search = std::integral_constant< |
| bool, has_linear_node_search_preference<original_key_compare>::value |
| ? prefers_linear_node_search<original_key_compare>::value |
| : has_linear_node_search_preference<key_type>::value |
| ? prefers_linear_node_search<key_type>::value |
| : std::is_arithmetic<key_type>::value && |
| (std::is_same<std::less<key_type>, |
| original_key_compare>::value || |
| std::is_same<std::greater<key_type>, |
| original_key_compare>::value)>; |
| |
| // This class is organized by absl::container_internal::Layout as if it had |
| // the following structure: |
| // // A pointer to the node's parent. |
| // btree_node *parent; |
| // |
| // // When ABSL_BTREE_ENABLE_GENERATIONS is defined, we also have a |
| // // generation integer in order to check that when iterators are |
| // // used, they haven't been invalidated already. Only the generation on |
| // // the root is used, but we have one on each node because whether a node |
| // // is root or not can change. |
| // uint32_t generation; |
| // |
| // // The position of the node in the node's parent. |
| // field_type position; |
| // // The index of the first populated value in `values`. |
| // // TODO(ezb): right now, `start` is always 0. Update insertion/merge |
| // // logic to allow for floating storage within nodes. |
| // field_type start; |
| // // The index after the last populated value in `values`. Currently, this |
| // // is the same as the count of values. |
| // field_type finish; |
| // // The maximum number of values the node can hold. This is an integer in |
| // // [1, kNodeSlots] for root leaf nodes, kNodeSlots for non-root leaf |
| // // nodes, and kInternalNodeMaxCount (as a sentinel value) for internal |
| // // nodes (even though there are still kNodeSlots values in the node). |
| // // TODO(ezb): make max_count use only 4 bits and record log2(capacity) |
| // // to free extra bits for is_root, etc. |
| // field_type max_count; |
| // |
| // // The array of values. The capacity is `max_count` for leaf nodes and |
| // // kNodeSlots for internal nodes. Only the values in |
| // // [start, finish) have been initialized and are valid. |
| // slot_type values[max_count]; |
| // |
| // // The array of child pointers. The keys in children[i] are all less |
| // // than key(i). The keys in children[i + 1] are all greater than key(i). |
| // // There are 0 children for leaf nodes and kNodeSlots + 1 children for |
| // // internal nodes. |
| // btree_node *children[kNodeSlots + 1]; |
| // |
| // This class is only constructed by EmptyNodeType. Normally, pointers to the |
| // layout above are allocated, cast to btree_node*, and de-allocated within |
| // the btree implementation. |
| ~btree_node() = default; |
| btree_node(btree_node const &) = delete; |
| btree_node &operator=(btree_node const &) = delete; |
| |
| protected: |
| btree_node() = default; |
| |
| private: |
| using layout_type = |
| absl::container_internal::Layout<btree_node *, uint32_t, field_type, |
| slot_type, btree_node *>; |
| using leaf_layout_type = typename layout_type::template WithStaticSizes< |
| /*parent*/ 1, |
| /*generation*/ BtreeGenerationsEnabled() ? 1 : 0, |
| /*position, start, finish, max_count*/ 4>; |
| constexpr static size_type SizeWithNSlots(size_type n) { |
| return leaf_layout_type(/*slots*/ n, /*children*/ 0).AllocSize(); |
| } |
| // A lower bound for the overhead of fields other than slots in a leaf node. |
| constexpr static size_type MinimumOverhead() { |
| return SizeWithNSlots(1) - sizeof(slot_type); |
| } |
| |
| // Compute how many values we can fit onto a leaf node taking into account |
| // padding. |
| constexpr static size_type NodeTargetSlots(const size_type begin, |
| const size_type end) { |
| return begin == end ? begin |
| : SizeWithNSlots((begin + end) / 2 + 1) > |
| params_type::kTargetNodeSize |
| ? NodeTargetSlots(begin, (begin + end) / 2) |
| : NodeTargetSlots((begin + end) / 2 + 1, end); |
| } |
| |
| constexpr static size_type kTargetNodeSize = params_type::kTargetNodeSize; |
| constexpr static size_type kNodeTargetSlots = |
| NodeTargetSlots(0, kTargetNodeSize); |
| |
| // We need a minimum of 3 slots per internal node in order to perform |
| // splitting (1 value for the two nodes involved in the split and 1 value |
| // propagated to the parent as the delimiter for the split). For performance |
| // reasons, we don't allow 3 slots-per-node due to bad worst case occupancy of |
| // 1/3 (for a node, not a b-tree). |
| constexpr static size_type kMinNodeSlots = 4; |
| |
| constexpr static size_type kNodeSlots = |
| kNodeTargetSlots >= kMinNodeSlots ? kNodeTargetSlots : kMinNodeSlots; |
| |
| using internal_layout_type = typename layout_type::template WithStaticSizes< |
| /*parent*/ 1, |
| /*generation*/ BtreeGenerationsEnabled() ? 1 : 0, |
| /*position, start, finish, max_count*/ 4, /*slots*/ kNodeSlots, |
| /*children*/ kNodeSlots + 1>; |
| |
| // The node is internal (i.e. is not a leaf node) if and only if `max_count` |
| // has this value. |
| constexpr static field_type kInternalNodeMaxCount = 0; |
| |
| // Leaves can have less than kNodeSlots values. |
| constexpr static leaf_layout_type LeafLayout( |
| const size_type slot_count = kNodeSlots) { |
| return leaf_layout_type(slot_count, 0); |
| } |
| constexpr static auto InternalLayout() { return internal_layout_type(); } |
| constexpr static size_type LeafSize(const size_type slot_count = kNodeSlots) { |
| return LeafLayout(slot_count).AllocSize(); |
| } |
| constexpr static size_type InternalSize() { |
| return InternalLayout().AllocSize(); |
| } |
| |
| constexpr static size_type Alignment() { |
| static_assert(LeafLayout(1).Alignment() == InternalLayout().Alignment(), |
| "Alignment of all nodes must be equal."); |
| return InternalLayout().Alignment(); |
| } |
| |
| // N is the index of the type in the Layout definition. |
| // ElementType<N> is the Nth type in the Layout definition. |
| template <size_type N> |
| inline typename layout_type::template ElementType<N> *GetField() { |
| // We assert that we don't read from values that aren't there. |
| assert(N < 4 || is_internal()); |
| return InternalLayout().template Pointer<N>(reinterpret_cast<char *>(this)); |
| } |
| template <size_type N> |
| inline const typename layout_type::template ElementType<N> *GetField() const { |
| assert(N < 4 || is_internal()); |
| return InternalLayout().template Pointer<N>( |
| reinterpret_cast<const char *>(this)); |
| } |
| void set_parent(btree_node *p) { *GetField<0>() = p; } |
| field_type &mutable_finish() { return GetField<2>()[2]; } |
| slot_type *slot(size_type i) { return &GetField<3>()[i]; } |
| slot_type *start_slot() { return slot(start()); } |
| slot_type *finish_slot() { return slot(finish()); } |
| const slot_type *slot(size_type i) const { return &GetField<3>()[i]; } |
| void set_position(field_type v) { GetField<2>()[0] = v; } |
| void set_start(field_type v) { GetField<2>()[1] = v; } |
| void set_finish(field_type v) { GetField<2>()[2] = v; } |
| // This method is only called by the node init methods. |
| void set_max_count(field_type v) { GetField<2>()[3] = v; } |
| |
| public: |
| // Whether this is a leaf node or not. This value doesn't change after the |
| // node is created. |
| bool is_leaf() const { return GetField<2>()[3] != kInternalNodeMaxCount; } |
| // Whether this is an internal node or not. This value doesn't change after |
| // the node is created. |
| bool is_internal() const { return !is_leaf(); } |
| |
| // Getter for the position of this node in its parent. |
| field_type position() const { return GetField<2>()[0]; } |
| |
| // Getter for the offset of the first value in the `values` array. |
| field_type start() const { |
| // TODO(ezb): when floating storage is implemented, return GetField<2>()[1]; |
| assert(GetField<2>()[1] == 0); |
| return 0; |
| } |
| |
| // Getter for the offset after the last value in the `values` array. |
| field_type finish() const { return GetField<2>()[2]; } |
| |
| // Getters for the number of values stored in this node. |
| field_type count() const { |
| assert(finish() >= start()); |
| return finish() - start(); |
| } |
| field_type max_count() const { |
| // Internal nodes have max_count==kInternalNodeMaxCount. |
| // Leaf nodes have max_count in [1, kNodeSlots]. |
| const field_type max_count = GetField<2>()[3]; |
| return max_count == field_type{kInternalNodeMaxCount} |
| ? field_type{kNodeSlots} |
| : max_count; |
| } |
| |
| // Getter for the parent of this node. |
| // TODO(ezb): assert that the child of the returned node at position |
| // `node_->position()` maps to the current node. |
| btree_node *parent() const { return *GetField<0>(); } |
| // Getter for whether the node is the root of the tree. The parent of the |
| // root of the tree is the leftmost node in the tree which is guaranteed to |
| // be a leaf. |
| bool is_root() const { return parent()->is_leaf(); } |
| void make_root() { |
| assert(parent()->is_root()); |
| set_generation(parent()->generation()); |
| set_parent(parent()->parent()); |
| } |
| |
| // Gets the root node's generation integer, which is the one used by the tree. |
| uint32_t *get_root_generation() const { |
| assert(BtreeGenerationsEnabled()); |
| const btree_node *curr = this; |
| for (; !curr->is_root(); curr = curr->parent()) continue; |
| return const_cast<uint32_t *>(&curr->GetField<1>()[0]); |
| } |
| |
| // Returns the generation for iterator validation. |
| uint32_t generation() const { |
| return BtreeGenerationsEnabled() ? *get_root_generation() : 0; |
| } |
| // Updates generation. Should only be called on a root node or during node |
| // initialization. |
| void set_generation(uint32_t generation) { |
| if (BtreeGenerationsEnabled()) GetField<1>()[0] = generation; |
| } |
| // Updates the generation. We do this whenever the node is mutated. |
| void next_generation() { |
| if (BtreeGenerationsEnabled()) ++*get_root_generation(); |
| } |
| |
| // Getters for the key/value at position i in the node. |
| const key_type &key(size_type i) const { return params_type::key(slot(i)); } |
| reference value(size_type i) { return params_type::element(slot(i)); } |
| const_reference value(size_type i) const { |
| return params_type::element(slot(i)); |
| } |
| |
| // Getters/setter for the child at position i in the node. |
| btree_node *child(field_type i) const { return GetField<4>()[i]; } |
| btree_node *start_child() const { return child(start()); } |
| btree_node *&mutable_child(field_type i) { return GetField<4>()[i]; } |
| void clear_child(field_type i) { |
| absl::container_internal::SanitizerPoisonObject(&mutable_child(i)); |
| } |
| void set_child_noupdate_position(field_type i, btree_node *c) { |
| absl::container_internal::SanitizerUnpoisonObject(&mutable_child(i)); |
| mutable_child(i) = c; |
| } |
| void set_child(field_type i, btree_node *c) { |
| set_child_noupdate_position(i, c); |
| c->set_position(i); |
| } |
| void init_child(field_type i, btree_node *c) { |
| set_child(i, c); |
| c->set_parent(this); |
| } |
| |
| // Returns the position of the first value whose key is not less than k. |
| template <typename K> |
| SearchResult<size_type, is_key_compare_to::value> lower_bound( |
| const K &k, const key_compare &comp) const { |
| return use_linear_search::value ? linear_search(k, comp) |
| : binary_search(k, comp); |
| } |
| // Returns the position of the first value whose key is greater than k. |
| template <typename K> |
| size_type upper_bound(const K &k, const key_compare &comp) const { |
| auto upper_compare = upper_bound_adapter<key_compare>(comp); |
| return use_linear_search::value ? linear_search(k, upper_compare).value |
| : binary_search(k, upper_compare).value; |
| } |
| |
| template <typename K, typename Compare> |
| SearchResult<size_type, btree_is_key_compare_to<Compare, key_type>::value> |
| linear_search(const K &k, const Compare &comp) const { |
| return linear_search_impl(k, start(), finish(), comp, |
| btree_is_key_compare_to<Compare, key_type>()); |
| } |
| |
| template <typename K, typename Compare> |
| SearchResult<size_type, btree_is_key_compare_to<Compare, key_type>::value> |
| binary_search(const K &k, const Compare &comp) const { |
| return binary_search_impl(k, start(), finish(), comp, |
| btree_is_key_compare_to<Compare, key_type>()); |
| } |
| |
| // Returns the position of the first value whose key is not less than k using |
| // linear search performed using plain compare. |
| template <typename K, typename Compare> |
| SearchResult<size_type, false> linear_search_impl( |
| const K &k, size_type s, const size_type e, const Compare &comp, |
| std::false_type /* IsCompareTo */) const { |
| while (s < e) { |
| if (!comp(key(s), k)) { |
| break; |
| } |
| ++s; |
| } |
| return SearchResult<size_type, false>{s}; |
| } |
| |
| // Returns the position of the first value whose key is not less than k using |
| // linear search performed using compare-to. |
| template <typename K, typename Compare> |
| SearchResult<size_type, true> linear_search_impl( |
| const K &k, size_type s, const size_type e, const Compare &comp, |
| std::true_type /* IsCompareTo */) const { |
| while (s < e) { |
| const absl::weak_ordering c = comp(key(s), k); |
| if (c == 0) { |
| return {s, MatchKind::kEq}; |
| } else if (c > 0) { |
| break; |
| } |
| ++s; |
| } |
| return {s, MatchKind::kNe}; |
| } |
| |
| // Returns the position of the first value whose key is not less than k using |
| // binary search performed using plain compare. |
| template <typename K, typename Compare> |
| SearchResult<size_type, false> binary_search_impl( |
| const K &k, size_type s, size_type e, const Compare &comp, |
| std::false_type /* IsCompareTo */) const { |
| while (s != e) { |
| const size_type mid = (s + e) >> 1; |
| if (comp(key(mid), k)) { |
| s = mid + 1; |
| } else { |
| e = mid; |
| } |
| } |
| return SearchResult<size_type, false>{s}; |
| } |
| |
| // Returns the position of the first value whose key is not less than k using |
| // binary search performed using compare-to. |
| template <typename K, typename CompareTo> |
| SearchResult<size_type, true> binary_search_impl( |
| const K &k, size_type s, size_type e, const CompareTo &comp, |
| std::true_type /* IsCompareTo */) const { |
| if (params_type::template can_have_multiple_equivalent_keys<K>()) { |
| MatchKind exact_match = MatchKind::kNe; |
| while (s != e) { |
| const size_type mid = (s + e) >> 1; |
| const absl::weak_ordering c = comp(key(mid), k); |
| if (c < 0) { |
| s = mid + 1; |
| } else { |
| e = mid; |
| if (c == 0) { |
| // Need to return the first value whose key is not less than k, |
| // which requires continuing the binary search if there could be |
| // multiple equivalent keys. |
| exact_match = MatchKind::kEq; |
| } |
| } |
| } |
| return {s, exact_match}; |
| } else { // Can't have multiple equivalent keys. |
| while (s != e) { |
| const size_type mid = (s + e) >> 1; |
| const absl::weak_ordering c = comp(key(mid), k); |
| if (c < 0) { |
| s = mid + 1; |
| } else if (c > 0) { |
| e = mid; |
| } else { |
| return {mid, MatchKind::kEq}; |
| } |
| } |
| return {s, MatchKind::kNe}; |
| } |
| } |
| |
| // Returns whether key i is ordered correctly with respect to the other keys |
| // in the node. The motivation here is to detect comparators that violate |
| // transitivity. Note: we only do comparisons of keys on this node rather than |
| // the whole tree so that this is constant time. |
| template <typename Compare> |
| bool is_ordered_correctly(field_type i, const Compare &comp) const { |
| if (std::is_base_of<BtreeTestOnlyCheckedCompareOptOutBase, |
| Compare>::value || |
| params_type::kIsKeyCompareStringAdapted) { |
| return true; |
| } |
| |
| const auto compare = [&](field_type a, field_type b) { |
| const absl::weak_ordering cmp = |
| compare_internal::do_three_way_comparison(comp, key(a), key(b)); |
| return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; |
| }; |
| int cmp = -1; |
| constexpr bool kCanHaveEquivKeys = |
| params_type::template can_have_multiple_equivalent_keys<key_type>(); |
| for (field_type j = start(); j < finish(); ++j) { |
| if (j == i) { |
| if (cmp > 0) return false; |
| continue; |
| } |
| int new_cmp = compare(j, i); |
| if (new_cmp < cmp || (!kCanHaveEquivKeys && new_cmp == 0)) return false; |
| cmp = new_cmp; |
| } |
| return true; |
| } |
| |
| // Emplaces a value at position i, shifting all existing values and |
| // children at positions >= i to the right by 1. |
| template <typename... Args> |
| void emplace_value(field_type i, allocator_type *alloc, Args &&...args); |
| |
| // Removes the values at positions [i, i + to_erase), shifting all existing |
| // values and children after that range to the left by to_erase. Clears all |
| // children between [i, i + to_erase). |
| void remove_values(field_type i, field_type to_erase, allocator_type *alloc); |
| |
| // Rebalances a node with its right sibling. |
| void rebalance_right_to_left(field_type to_move, btree_node *right, |
| allocator_type *alloc); |
| void rebalance_left_to_right(field_type to_move, btree_node *right, |
| allocator_type *alloc); |
| |
| // Splits a node, moving a portion of the node's values to its right sibling. |
| void split(int insert_position, btree_node *dest, allocator_type *alloc); |
| |
| // Merges a node with its right sibling, moving all of the values and the |
| // delimiting key in the parent node onto itself, and deleting the src node. |
| void merge(btree_node *src, allocator_type *alloc); |
| |
| // Node allocation/deletion routines. |
| void init_leaf(field_type position, field_type max_count, |
| btree_node *parent) { |
| set_generation(0); |
| set_parent(parent); |
| set_position(position); |
| set_start(0); |
| set_finish(0); |
| set_max_count(max_count); |
| absl::container_internal::SanitizerPoisonMemoryRegion( |
| start_slot(), max_count * sizeof(slot_type)); |
| } |
| void init_internal(field_type position, btree_node *parent) { |
| init_leaf(position, kNodeSlots, parent); |
| // Set `max_count` to a sentinel value to indicate that this node is |
| // internal. |
| set_max_count(kInternalNodeMaxCount); |
| absl::container_internal::SanitizerPoisonMemoryRegion( |
| &mutable_child(start()), (kNodeSlots + 1) * sizeof(btree_node *)); |
| } |
| |
| static void deallocate(const size_type size, btree_node *node, |
| allocator_type *alloc) { |
| absl::container_internal::SanitizerUnpoisonMemoryRegion(node, size); |
| absl::container_internal::Deallocate<Alignment()>(alloc, node, size); |
| } |
| |
| // Deletes a node and all of its children. |
| static void clear_and_delete(btree_node *node, allocator_type *alloc); |
| |
| private: |
| template <typename... Args> |
| void value_init(const field_type i, allocator_type *alloc, Args &&...args) { |
| next_generation(); |
| absl::container_internal::SanitizerUnpoisonObject(slot(i)); |
| params_type::construct(alloc, slot(i), std::forward<Args>(args)...); |
| } |
| void value_destroy(const field_type i, allocator_type *alloc) { |
| next_generation(); |
| params_type::destroy(alloc, slot(i)); |
| absl::container_internal::SanitizerPoisonObject(slot(i)); |
| } |
| void value_destroy_n(const field_type i, const field_type n, |
| allocator_type *alloc) { |
| next_generation(); |
| for (slot_type *s = slot(i), *end = slot(i + n); s != end; ++s) { |
| params_type::destroy(alloc, s); |
| absl::container_internal::SanitizerPoisonObject(s); |
| } |
| } |
| |
| static void transfer(slot_type *dest, slot_type *src, allocator_type *alloc) { |
| absl::container_internal::SanitizerUnpoisonObject(dest); |
| params_type::transfer(alloc, dest, src); |
| absl::container_internal::SanitizerPoisonObject(src); |
| } |
| |
| // Transfers value from slot `src_i` in `src_node` to slot `dest_i` in `this`. |
| void transfer(const size_type dest_i, const size_type src_i, |
| btree_node *src_node, allocator_type *alloc) { |
| next_generation(); |
| transfer(slot(dest_i), src_node->slot(src_i), alloc); |
| } |
| |
| // Transfers `n` values starting at value `src_i` in `src_node` into the |
| // values starting at value `dest_i` in `this`. |
| void transfer_n(const size_type n, const size_type dest_i, |
| const size_type src_i, btree_node *src_node, |
| allocator_type *alloc) { |
| next_generation(); |
| for (slot_type *src = src_node->slot(src_i), *end = src + n, |
| *dest = slot(dest_i); |
| src != end; ++src, ++dest) { |
| transfer(dest, src, alloc); |
| } |
| } |
| |
| // Same as above, except that we start at the end and work our way to the |
| // beginning. |
| void transfer_n_backward(const size_type n, const size_type dest_i, |
| const size_type src_i, btree_node *src_node, |
| allocator_type *alloc) { |
| next_generation(); |
| for (slot_type *src = src_node->slot(src_i + n), *end = src - n, |
| *dest = slot(dest_i + n); |
| src != end; --src, --dest) { |
| // If we modified the loop index calculations above to avoid the -1s here, |
| // it would result in UB in the computation of `end` (and possibly `src` |
| // as well, if n == 0), since slot() is effectively an array index and it |
| // is UB to compute the address of any out-of-bounds array element except |
| // for one-past-the-end. |
| transfer(dest - 1, src - 1, alloc); |
| } |
| } |
| |
| template <typename P> |
| friend class btree; |
| template <typename N, typename R, typename P> |
| friend class btree_iterator; |
| friend class BtreeNodePeer; |
| friend struct btree_access; |
| }; |
| |
| template <typename Node> |
| bool AreNodesFromSameContainer(const Node *node_a, const Node *node_b) { |
| // If either node is null, then give up on checking whether they're from the |
| // same container. (If exactly one is null, then we'll trigger the |
| // default-constructed assert in Equals.) |
| if (node_a == nullptr || node_b == nullptr) return true; |
| while (!node_a->is_root()) node_a = node_a->parent(); |
| while (!node_b->is_root()) node_b = node_b->parent(); |
| return node_a == node_b; |
| } |
| |
| class btree_iterator_generation_info_enabled { |
| public: |
| explicit btree_iterator_generation_info_enabled(uint32_t g) |
| : generation_(g) {} |
| |
| // Updates the generation. For use internally right before we return an |
| // iterator to the user. |
| template <typename Node> |
| void update_generation(const Node *node) { |
| if (node != nullptr) generation_ = node->generation(); |
| } |
| uint32_t generation() const { return generation_; } |
| |
| template <typename Node> |
| void assert_valid_generation(const Node *node) const { |
| if (node != nullptr && node->generation() != generation_) { |
| ABSL_INTERNAL_LOG( |
| FATAL, |
| "Attempting to use an invalidated iterator. The corresponding b-tree " |
| "container has been mutated since this iterator was constructed."); |
| } |
| } |
| |
| private: |
| // Used to check that the iterator hasn't been invalidated. |
| uint32_t generation_; |
| }; |
| |
| class btree_iterator_generation_info_disabled { |
| public: |
| explicit btree_iterator_generation_info_disabled(uint32_t) {} |
| static void update_generation(const void *) {} |
| static uint32_t generation() { return 0; } |
| static void assert_valid_generation(const void *) {} |
| }; |
| |
| #ifdef ABSL_BTREE_ENABLE_GENERATIONS |
| using btree_iterator_generation_info = btree_iterator_generation_info_enabled; |
| #else |
| using btree_iterator_generation_info = btree_iterator_generation_info_disabled; |
| #endif |
| |
| template <typename Node, typename Reference, typename Pointer> |
| class btree_iterator : private btree_iterator_generation_info { |
| using field_type = typename Node::field_type; |
| using key_type = typename Node::key_type; |
| using size_type = typename Node::size_type; |
| using params_type = typename Node::params_type; |
| using is_map_container = typename params_type::is_map_container; |
| |
| using node_type = Node; |
| using normal_node = typename std::remove_const<Node>::type; |
| using const_node = const Node; |
| using normal_pointer = typename params_type::pointer; |
| using normal_reference = typename params_type::reference; |
| using const_pointer = typename params_type::const_pointer; |
| using const_reference = typename params_type::const_reference; |
| using slot_type = typename params_type::slot_type; |
| |
| // In sets, all iterators are const. |
| using iterator = absl::conditional_t< |
| is_map_container::value, |
| btree_iterator<normal_node, normal_reference, normal_pointer>, |
| btree_iterator<normal_node, const_reference, const_pointer>>; |
| using const_iterator = |
| btree_iterator<const_node, const_reference, const_pointer>; |
| |
| public: |
| // These aliases are public for std::iterator_traits. |
| using difference_type = typename Node::difference_type; |
| using value_type = typename params_type::value_type; |
| using pointer = Pointer; |
| using reference = Reference; |
| using iterator_category = std::bidirectional_iterator_tag; |
| |
| btree_iterator() : btree_iterator(nullptr, -1) {} |
| explicit btree_iterator(Node *n) : btree_iterator(n, n->start()) {} |
| btree_iterator(Node *n, int p) |
| : btree_iterator_generation_info(n != nullptr ? n->generation() |
| : ~uint32_t{}), |
| node_(n), |
| position_(p) {} |
| |
| // NOTE: this SFINAE allows for implicit conversions from iterator to |
| // const_iterator, but it specifically avoids hiding the copy constructor so |
| // that the trivial one will be used when possible. |
| template <typename N, typename R, typename P, |
| absl::enable_if_t< |
| std::is_same<btree_iterator<N, R, P>, iterator>::value && |
| std::is_same<btree_iterator, const_iterator>::value, |
| int> = 0> |
| btree_iterator(const btree_iterator<N, R, P> other) // NOLINT |
| : btree_iterator_generation_info(other), |
| node_(other.node_), |
| position_(other.position_) {} |
| |
| bool operator==(const iterator &other) const { |
| return Equals(other); |
| } |
| bool operator==(const const_iterator &other) const { |
| return Equals(other); |
| } |
| bool operator!=(const iterator &other) const { |
| return !Equals(other); |
| } |
| bool operator!=(const const_iterator &other) const { |
| return !Equals(other); |
| } |
| |
| // Returns n such that n calls to ++other yields *this. |
| // Precondition: n exists. |
| difference_type operator-(const_iterator other) const { |
| if (node_ == other.node_) { |
| if (node_->is_leaf()) return position_ - other.position_; |
| if (position_ == other.position_) return 0; |
| } |
| return distance_slow(other); |
| } |
| |
| // Advances the iterator by `n`. Values of `n` must not result in going past |
| // the `end` iterator (for a positive `n`) or before the `begin` iterator (for |
| // a negative `n`). |
| btree_iterator &operator+=(difference_type n) { |
| assert_valid_generation(node_); |
| if (n == 0) return *this; |
| if (n < 0) return decrement_n_slow(-n); |
| return increment_n_slow(n); |
| } |
| |
| // Moves the iterator by `n` positions backwards. Values of `n` must not |
| // result in going before the `begin` iterator (for a positive `n`) or past |
| // the `end` iterator (for a negative `n`). |
| btree_iterator &operator-=(difference_type n) { |
| assert_valid_generation(node_); |
| if (n == 0) return *this; |
| if (n < 0) return increment_n_slow(-n); |
| return decrement_n_slow(n); |
| } |
| |
| // Accessors for the key/value the iterator is pointing at. |
| reference operator*() const { |
| ABSL_HARDENING_ASSERT(node_ != nullptr); |
| assert_valid_generation(node_); |
| ABSL_HARDENING_ASSERT(position_ >= node_->start()); |
| if (position_ >= node_->finish()) { |
| ABSL_HARDENING_ASSERT(!IsEndIterator() && "Dereferencing end() iterator"); |
| ABSL_HARDENING_ASSERT(position_ < node_->finish()); |
| } |
| return node_->value(static_cast<field_type>(position_)); |
| } |
| pointer operator->() const { return &operator*(); } |
| |
| btree_iterator &operator++() { |
| increment(); |
| return *this; |
| } |
| btree_iterator &operator--() { |
| decrement(); |
| return *this; |
| } |
| btree_iterator operator++(int) { |
| btree_iterator tmp = *this; |
| ++*this; |
| return tmp; |
| } |
| btree_iterator operator--(int) { |
| btree_iterator tmp = *this; |
| --*this; |
| return tmp; |
| } |
| |
| private: |
| friend iterator; |
| friend const_iterator; |
| template <typename Params> |
| friend class btree; |
| template <typename Tree> |
| friend class btree_container; |
| template <typename Tree> |
| friend class btree_set_container; |
| template <typename Tree> |
| friend class btree_map_container; |
| template <typename Tree> |
| friend class btree_multiset_container; |
| template <typename TreeType, typename CheckerType> |
| friend class base_checker; |
| friend struct btree_access; |
| |
| // This SFINAE allows explicit conversions from const_iterator to |
| // iterator, but also avoids hiding the copy constructor. |
| // NOTE: the const_cast is safe because this constructor is only called by |
| // non-const methods and the container owns the nodes. |
| template <typename N, typename R, typename P, |
| absl::enable_if_t< |
| std::is_same<btree_iterator<N, R, P>, const_iterator>::value && |
| std::is_same<btree_iterator, iterator>::value, |
| int> = 0> |
| explicit btree_iterator(const btree_iterator<N, R, P> other) |
| : btree_iterator_generation_info(other.generation()), |
| node_(const_cast<node_type *>(other.node_)), |
| position_(other.position_) {} |
| |
| bool Equals(const const_iterator other) const { |
| ABSL_HARDENING_ASSERT(((node_ == nullptr && other.node_ == nullptr) || |
| (node_ != nullptr && other.node_ != nullptr)) && |
| "Comparing default-constructed iterator with " |
| "non-default-constructed iterator."); |
| // Note: we use assert instead of ABSL_HARDENING_ASSERT here because this |
| // changes the complexity of Equals from O(1) to O(log(N) + log(M)) where |
| // N/M are sizes of the containers containing node_/other.node_. |
| assert(AreNodesFromSameContainer(node_, other.node_) && |
| "Comparing iterators from different containers."); |
| assert_valid_generation(node_); |
| other.assert_valid_generation(other.node_); |
| return node_ == other.node_ && position_ == other.position_; |
| } |
| |
| bool IsEndIterator() const { |
| if (position_ != node_->finish()) return false; |
| node_type *node = node_; |
| while (!node->is_root()) { |
| if (node->position() != node->parent()->finish()) return false; |
| node = node->parent(); |
| } |
| return true; |
| } |
| |
| // Returns n such that n calls to ++other yields *this. |
| // Precondition: n exists && (this->node_ != other.node_ || |
| // !this->node_->is_leaf() || this->position_ != other.position_). |
| difference_type distance_slow(const_iterator other) const; |
| |
| // Increment/decrement the iterator. |
| void increment() { |
| assert_valid_generation(node_); |
| if (node_->is_leaf() && ++position_ < node_->finish()) { |
| return; |
| } |
| increment_slow(); |
| } |
| void increment_slow(); |
| btree_iterator &increment_n_slow(difference_type n); |
| |
| void decrement() { |
| assert_valid_generation(node_); |
| if (node_->is_leaf() && --position_ >= node_->start()) { |
| return; |
| } |
| decrement_slow(); |
| } |
| void decrement_slow(); |
| btree_iterator &decrement_n_slow(difference_type n); |
| |
| const key_type &key() const { |
| return node_->key(static_cast<size_type>(position_)); |
| } |
| decltype(std::declval<Node *>()->slot(0)) slot() { |
| return node_->slot(static_cast<size_type>(position_)); |
| } |
| |
| void update_generation() { |
| btree_iterator_generation_info::update_generation(node_); |
| } |
| |
| // The node in the tree the iterator is pointing at. |
| Node *node_; |
| // The position within the node of the tree the iterator is pointing at. |
| // NOTE: this is an int rather than a field_type because iterators can point |
| // to invalid positions (such as -1) in certain circumstances. |
| int position_; |
| }; |
| |
| template <typename Params> |
| class btree { |
| using node_type = btree_node<Params>; |
| using is_key_compare_to = typename Params::is_key_compare_to; |
| using field_type = typename node_type::field_type; |
| |
| // We use a static empty node for the root/leftmost/rightmost of empty btrees |
| // in order to avoid branching in begin()/end(). |
| struct EmptyNodeType : node_type { |
| using field_type = typename node_type::field_type; |
| node_type *parent; |
| #ifdef ABSL_BTREE_ENABLE_GENERATIONS |
| uint32_t generation = 0; |
| #endif |
| field_type position = 0; |
| field_type start = 0; |
| field_type finish = 0; |
| // max_count must be != kInternalNodeMaxCount (so that this node is regarded |
| // as a leaf node). max_count() is never called when the tree is empty. |
| field_type max_count = node_type::kInternalNodeMaxCount + 1; |
| |
| constexpr EmptyNodeType() : parent(this) {} |
| }; |
| |
| static node_type *EmptyNode() { |
| alignas(node_type::Alignment()) static constexpr EmptyNodeType empty_node; |
| return const_cast<EmptyNodeType *>(&empty_node); |
| } |
| |
| enum : uint32_t { |
| kNodeSlots = node_type::kNodeSlots, |
| kMinNodeValues = kNodeSlots / 2, |
| }; |
| |
| struct node_stats { |
| using size_type = typename Params::size_type; |
| |
| node_stats(size_type l, size_type i) : leaf_nodes(l), internal_nodes(i) {} |
| |
| node_stats &operator+=(const node_stats &other) { |
| leaf_nodes += other.leaf_nodes; |
| internal_nodes += other.internal_nodes; |
| return *this; |
| } |
| |
| size_type leaf_nodes; |
| size_type internal_nodes; |
| }; |
| |
| public: |
| using key_type = typename Params::key_type; |
| using value_type = typename Params::value_type; |
| using size_type = typename Params::size_type; |
| using difference_type = typename Params::difference_type; |
| using key_compare = typename Params::key_compare; |
| using original_key_compare = typename Params::original_key_compare; |
| using value_compare = typename Params::value_compare; |
| using allocator_type = typename Params::allocator_type; |
| using reference = typename Params::reference; |
| using const_reference = typename Params::const_reference; |
| using pointer = typename Params::pointer; |
| using const_pointer = typename Params::const_pointer; |
| using iterator = |
| typename btree_iterator<node_type, reference, pointer>::iterator; |
| using const_iterator = typename iterator::const_iterator; |
| using reverse_iterator = std::reverse_iterator<iterator>; |
| using const_reverse_iterator = std::reverse_iterator<const_iterator>; |
| using node_handle_type = node_handle<Params, Params, allocator_type>; |
| |
| // Internal types made public for use by btree_container types. |
| using params_type = Params; |
| using slot_type = typename Params::slot_type; |
| |
| private: |
| // Copies or moves (depending on the template parameter) the values in |
| // other into this btree in their order in other. This btree must be empty |
| // before this method is called. This method is used in copy construction, |
| // copy assignment, and move assignment. |
| template <typename Btree> |
| void copy_or_move_values_in_order(Btree &other); |
| |
| // Validates that various assumptions/requirements are true at compile time. |
| constexpr static bool static_assert_validation(); |
| |
| public: |
| btree(const key_compare &comp, const allocator_type &alloc) |
| : root_(EmptyNode()), rightmost_(comp, alloc, EmptyNode()), size_(0) {} |
| |
| btree(const btree &other) : btree(other, other.allocator()) {} |
| btree(const btree &other, const allocator_type &alloc) |
| : btree(other.key_comp(), alloc) { |
| copy_or_move_values_in_order(other); |
| } |
| btree(btree &&other) noexcept |
| : root_(std::exchange(other.root_, EmptyNode())), |
| rightmost_(std::move(other.rightmost_)), |
| size_(std::exchange(other.size_, 0u)) { |
| other.mutable_rightmost() = EmptyNode(); |
| } |
| btree(btree &&other, const allocator_type &alloc) |
| : btree(other.key_comp(), alloc) { |
| if (alloc == other.allocator()) { |
| swap(other); |
| } else { |
| // Move values from `other` one at a time when allocators are different. |
| copy_or_move_values_in_order(other); |
| } |
| } |
| |
| ~btree() { |
| // Put static_asserts in destructor to avoid triggering them before the type |
| // is complete. |
| static_assert(static_assert_validation(), "This call must be elided."); |
| clear(); |
| } |
| |
| // Assign the contents of other to *this. |
| btree &operator=(const btree &other); |
| btree &operator=(btree &&other) noexcept; |
| |
| iterator begin() { return iterator(leftmost()); } |
| const_iterator begin() const { return const_iterator(leftmost()); } |
| iterator end() { return iterator(rightmost(), rightmost()->finish()); } |
| const_iterator end() const { |
| return const_iterator(rightmost(), rightmost()->finish()); |
| } |
| reverse_iterator rbegin() { return reverse_iterator(end()); } |
| const_reverse_iterator rbegin() const { |
| return const_reverse_iterator(end()); |
| } |
| reverse_iterator rend() { return reverse_iterator(begin()); } |
| const_reverse_iterator rend() const { |
| return const_reverse_iterator(begin()); |
| } |
| |
| // Finds the first element whose key is not less than `key`. |
| template <typename K> |
| iterator lower_bound(const K &key) { |
| return internal_end(internal_lower_bound(key).value); |
| } |
| template <typename K> |
| const_iterator lower_bound(const K &key) const { |
| return internal_end(internal_lower_bound(key).value); |
| } |
| |
| // Finds the first element whose key is not less than `key` and also returns |
| // whether that element is equal to `key`. |
| template <typename K> |
| std::pair<iterator, bool> lower_bound_equal(const K &key) const; |
| |
| // Finds the first element whose key is greater than `key`. |
| template <typename K> |
| iterator upper_bound(const K &key) { |
| return internal_end(internal_upper_bound(key)); |
| } |
| template <typename K> |
| const_iterator upper_bound(const K &key) const { |
| return internal_end(internal_upper_bound(key)); |
| } |
| |
| // Finds the range of values which compare equal to key. The first member of |
| // the returned pair is equal to lower_bound(key). The second member of the |
| // pair is equal to upper_bound(key). |
| template <typename K> |
| std::pair<iterator, iterator> equal_range(const K &key); |
| template <typename K> |
| std::pair<const_iterator, const_iterator> equal_range(const K &key) const { |
| return const_cast<btree *>(this)->equal_range(key); |
| } |
| |
| // Inserts a value into the btree only if it does not already exist. The |
| // boolean return value indicates whether insertion succeeded or failed. |
| // Requirement: if `key` already exists in the btree, does not consume `args`. |
| // Requirement: `key` is never referenced after consuming `args`. |
| template <typename K, typename... Args> |
| std::pair<iterator, bool> insert_unique(const K &key, Args &&...args); |
| |
| // Inserts with hint. Checks to see if the value should be placed immediately |
| // before `position` in the tree. If so, then the insertion will take |
| // amortized constant time. If not, the insertion will take amortized |
| // logarithmic time as if a call to insert_unique() were made. |
| // Requirement: if `key` already exists in the btree, does not consume `args`. |
| // Requirement: `key` is never referenced after consuming `args`. |
| template <typename K, typename... Args> |
| std::pair<iterator, bool> insert_hint_unique(iterator position, const K &key, |
| Args &&...args); |
| |
| // Insert a range of values into the btree. |
| // Note: the first overload avoids constructing a value_type if the key |
| // already exists in the btree. |
| template <typename InputIterator, |
| typename = decltype(std::declval<const key_compare &>()( |
| params_type::key(*std::declval<InputIterator>()), |
| std::declval<const key_type &>()))> |
| void insert_iterator_unique(InputIterator b, InputIterator e, int); |
| // We need the second overload for cases in which we need to construct a |
| // value_type in order to compare it with the keys already in the btree. |
| template <typename InputIterator> |
| void insert_iterator_unique(InputIterator b, InputIterator e, char); |
| |
| // Inserts a value into the btree. |
| template <typename ValueType> |
| iterator insert_multi(const key_type &key, ValueType &&v); |
| |
| // Inserts a value into the btree. |
| template <typename ValueType> |
| iterator insert_multi(ValueType &&v) { |
| return insert_multi(params_type::key(v), std::forward<ValueType>(v)); |
| } |
| |
| // Insert with hint. Check to see if the value should be placed immediately |
| // before position in the tree. If it does, then the insertion will take |
| // amortized constant time. If not, the insertion will take amortized |
| // logarithmic time as if a call to insert_multi(v) were made. |
| template <typename ValueType> |
| iterator insert_hint_multi(iterator position, ValueType &&v); |
| |
| // Insert a range of values into the btree. |
| template <typename InputIterator> |
| void insert_iterator_multi(InputIterator b, |
| InputIterator e); |
| |
| // Erase the specified iterator from the btree. The iterator must be valid |
| // (i.e. not equal to end()). Return an iterator pointing to the node after |
| // the one that was erased (or end() if none exists). |
| // Requirement: does not read the value at `*iter`. |
| iterator erase(iterator iter); |
| |
| // Erases range. Returns the number of keys erased and an iterator pointing |
| // to the element after the last erased element. |
| std::pair<size_type, iterator> erase_range(iterator begin, iterator end); |
| |
| // Finds an element with key equivalent to `key` or returns `end()` if `key` |
| // is not present. |
| template <typename K> |
| iterator find(const K &key) { |
| return internal_end(internal_find(key)); |
| } |
| template <typename K> |
| const_iterator find(const K &key) const { |
| return internal_end(internal_find(key)); |
| } |
| |
| // Clear the btree, deleting all of the values it contains. |
| void clear(); |
| |
| // Swaps the contents of `this` and `other`. |
| void swap(btree &other); |
| |
| const key_compare &key_comp() const noexcept { |
| return rightmost_.template get<0>(); |
| } |
| template <typename K1, typename K2> |
| bool compare_keys(const K1 &a, const K2 &b) const { |
| return compare_internal::compare_result_as_less_than(key_comp()(a, b)); |
| } |
| |
| value_compare value_comp() const { |
| return value_compare(original_key_compare(key_comp())); |
| } |
| |
| // Verifies the structure of the btree. |
| void verify() const; |
| |
| // Size routines. |
| size_type size() const { return size_; } |
| size_type max_size() const { return (std::numeric_limits<size_type>::max)(); } |
| bool empty() const { return size_ == 0; } |
| |
| // The height of the btree. An empty tree will have height 0. |
| size_type height() const { |
| size_type h = 0; |
| if (!empty()) { |
| // Count the length of the chain from the leftmost node up to the |
| // root. We actually count from the root back around to the level below |
| // the root, but the calculation is the same because of the circularity |
| // of that traversal. |
| const node_type *n = root(); |
| do { |
| ++h; |
| n = n->parent(); |
| } while (n != root()); |
| } |
| return h; |
| } |
| |
| // The number of internal, leaf and total nodes used by the btree. |
| size_type leaf_nodes() const { return internal_stats(root()).leaf_nodes; } |
| size_type internal_nodes() const { |
| return internal_stats(root()).internal_nodes; |
| } |
| size_type nodes() const { |
| node_stats stats = internal_stats(root()); |
| return stats.leaf_nodes + stats.internal_nodes; |
| } |
| |
| // The total number of bytes used by the btree. |
| // TODO(b/169338300): update to support node_btree_*. |
| size_type bytes_used() const { |
| node_stats stats = internal_stats(root()); |
| if (stats.leaf_nodes == 1 && stats.internal_nodes == 0) { |
| return sizeof(*this) + node_type::LeafSize(root()->max_count()); |
| } else { |
| return sizeof(*this) + stats.leaf_nodes * node_type::LeafSize() + |
| stats.internal_nodes * node_type::InternalSize(); |
| } |
| } |
| |
| // The average number of bytes used per value stored in the btree assuming |
| // random insertion order. |
| static double average_bytes_per_value() { |
| // The expected number of values per node with random insertion order is the |
| // average of the maximum and minimum numbers of values per node. |
| const double expected_values_per_node = (kNodeSlots + kMinNodeValues) / 2.0; |
| return node_type::LeafSize() / expected_values_per_node; |
| } |
| |
| // The fullness of the btree. Computed as the number of elements in the btree |
| // divided by the maximum number of elements a tree with the current number |
| // of nodes could hold. A value of 1 indicates perfect space |
| // utilization. Smaller values indicate space wastage. |
| // Returns 0 for empty trees. |
| double fullness() const { |
| if (empty()) return 0.0; |
| return static_cast<double>(size()) / (nodes() * kNodeSlots); |
| } |
| // The overhead of the btree structure in bytes per node. Computed as the |
| // total number of bytes used by the btree minus the number of bytes used for |
| // storing elements divided by the number of elements. |
| // Returns 0 for empty trees. |
| double overhead() const { |
| if (empty()) return 0.0; |
| return (bytes_used() - size() * sizeof(value_type)) / |
| static_cast<double>(size()); |
| } |
| |
| // The allocator used by the btree. |
| allocator_type get_allocator() const { return allocator(); } |
| |
| private: |
| friend struct btree_access; |
| |
| // Internal accessor routines. |
| node_type *root() { return root_; } |
| const node_type *root() const { return root_; } |
| node_type *&mutable_root() noexcept { return root_; } |
| node_type *rightmost() { return rightmost_.template get<2>(); } |
| const node_type *rightmost() const { return rightmost_.template get<2>(); } |
| node_type *&mutable_rightmost() noexcept { |
| return rightmost_.template get<2>(); |
| } |
| key_compare *mutable_key_comp() noexcept { |
| return &rightmost_.template get<0>(); |
| } |
| |
| // The leftmost node is stored as the parent of the root node. |
| node_type *leftmost() { return root()->parent(); } |
| const node_type *leftmost() const { return root()->parent(); } |
| |
| // Allocator routines. |
| allocator_type *mutable_allocator() noexcept { |
| return &rightmost_.template get<1>(); |
| } |
| const allocator_type &allocator() const noexcept { |
| return rightmost_.template get<1>(); |
| } |
| |
| // Allocates a correctly aligned node of at least size bytes using the |
| // allocator. |
| node_type *allocate(size_type size) { |
| return reinterpret_cast<node_type *>( |
| absl::container_internal::Allocate<node_type::Alignment()>( |
| mutable_allocator(), size)); |
| } |
| |
| // Node creation/deletion routines. |
| node_type *new_internal_node(field_type position, node_type *parent) { |
| node_type *n = allocate(node_type::InternalSize()); |
| n->init_internal(position, parent); |
| return n; |
| } |
| node_type *new_leaf_node(field_type position, node_type *parent) { |
| node_type *n = allocate(node_type::LeafSize()); |
| n->init_leaf(position, kNodeSlots, parent); |
| return n; |
| } |
| node_type *new_leaf_root_node(field_type max_count) { |
| node_type *n = allocate(node_type::LeafSize(max_count)); |
| n->init_leaf(/*position=*/0, max_count, /*parent=*/n); |
| return n; |
| } |
| |
| // Deletion helper routines. |
| iterator rebalance_after_delete(iterator iter); |
| |
| // Rebalances or splits the node iter points to. |
| void rebalance_or_split(iterator *iter); |
| |
| // Merges the values of left, right and the delimiting key on their parent |
| // onto left, removing the delimiting key and deleting right. |
| void merge_nodes(node_type *left, node_type *right); |
| |
| // Tries to merge node with its left or right sibling, and failing that, |
| // rebalance with its left or right sibling. Returns true if a merge |
| // occurred, at which point it is no longer valid to access node. Returns |
| // false if no merging took place. |
| bool try_merge_or_rebalance(iterator *iter); |
| |
| // Tries to shrink the height of the tree by 1. |
| void try_shrink(); |
| |
| iterator internal_end(iterator iter) { |
| return iter.node_ != nullptr ? iter : end(); |
| } |
| const_iterator internal_end(const_iterator iter) const { |
| return iter.node_ != nullptr ? iter : end(); |
| } |
| |
| // Emplaces a value into the btree immediately before iter. Requires that |
| // key(v) <= iter.key() and (--iter).key() <= key(v). |
| template <typename... Args> |
| iterator internal_emplace(iterator iter, Args &&...args); |
| |
| // Returns an iterator pointing to the first value >= the value "iter" is |
| // pointing at. Note that "iter" might be pointing to an invalid location such |
| // as iter.position_ == iter.node_->finish(). This routine simply moves iter |
| // up in the tree to a valid location. Requires: iter.node_ is non-null. |
| template <typename IterType> |
| static IterType internal_last(IterType iter); |
| |
| // Returns an iterator pointing to the leaf position at which key would |
| // reside in the tree, unless there is an exact match - in which case, the |
| // result may not be on a leaf. When there's a three-way comparator, we can |
| // return whether there was an exact match. This allows the caller to avoid a |
| // subsequent comparison to determine if an exact match was made, which is |
| // important for keys with expensive comparison, such as strings. |
| template <typename K> |
| SearchResult<iterator, is_key_compare_to::value> internal_locate( |
| const K &key) const; |
| |
| // Internal routine which implements lower_bound(). |
| template <typename K> |
| SearchResult<iterator, is_key_compare_to::value> internal_lower_bound( |
| const K &key) const; |
| |
| // Internal routine which implements upper_bound(). |
| template <typename K> |
| iterator internal_upper_bound(const K &key) const; |
| |
| // Internal routine which implements find(). |
| template <typename K> |
| iterator internal_find(const K &key) const; |
| |
| // Verifies the tree structure of node. |
| size_type internal_verify(const node_type *node, const key_type *lo, |
| const key_type *hi) const; |
| |
| node_stats internal_stats(const node_type *node) const { |
| // The root can be a static empty node. |
| if (node == nullptr || (node == root() && empty())) { |
| return node_stats(0, 0); |
| } |
| if (node->is_leaf()) { |
| return node_stats(1, 0); |
| } |
| node_stats res(0, 1); |
| for (int i = node->start(); i <= node->finish(); ++i) { |
| res += internal_stats(node->child(i)); |
| } |
| return res; |
| } |
| |
| node_type *root_; |
| |
| // A pointer to the rightmost node. Note that the leftmost node is stored as |
| // the root's parent. We use compressed tuple in order to save space because |
| // key_compare and allocator_type are usually empty. |
| absl::container_internal::CompressedTuple<key_compare, allocator_type, |
| node_type *> |
| rightmost_; |
| |
| // Number of values. |
| size_type size_; |
| }; |
| |
| //// |
| // btree_node methods |
| template <typename P> |
| template <typename... Args> |
| inline void btree_node<P>::emplace_value(const field_type i, |
| allocator_type *alloc, |
| Args &&...args) { |
| assert(i >= start()); |
| assert(i <= finish()); |
| // Shift old values to create space for new value and then construct it in |
| // place. |
| if (i < finish()) { |
| transfer_n_backward(finish() - i, /*dest_i=*/i + 1, /*src_i=*/i, this, |
| alloc); |
| } |
| value_init(static_cast<field_type>(i), alloc, std::forward<Args>(args)...); |
| set_finish(finish() + 1); |
| |
| if (is_internal() && finish() > i + 1) { |
| for (field_type j = finish(); j > i + 1; --j) { |
| set_child(j, child(j - 1)); |
| } |
| clear_child(i + 1); |
| } |
| } |
| |
| template <typename P> |
| inline void btree_node<P>::remove_values(const field_type i, |
| const field_type to_erase, |
| allocator_type *alloc) { |
| // Transfer values after the removed range into their new places. |
| value_destroy_n(i, to_erase, alloc); |
| const field_type orig_finish = finish(); |
| const field_type src_i = i + to_erase; |
| transfer_n(orig_finish - src_i, i, src_i, this, alloc); |
| |
| if (is_internal()) { |
| // Delete all children between begin and end. |
| for (field_type j = 0; j < to_erase; ++j) { |
| clear_and_delete(child(i + j + 1), alloc); |
| } |
| // Rotate children after end into new positions. |
| for (field_type j = i + to_erase + 1; j <= orig_finish; ++j) { |
| set_child(j - to_erase, child(j)); |
| clear_child(j); |
| } |
| } |
| set_finish(orig_finish - to_erase); |
| } |
| |
| template <typename P> |
| void btree_node<P>::rebalance_right_to_left(field_type to_move, |
| btree_node *right, |
| allocator_type *alloc) { |
| assert(parent() == right->parent()); |
| assert(position() + 1 == right->position()); |
| assert(right->count() >= count()); |
| assert(to_move >= 1); |
| assert(to_move <= right->count()); |
| |
| // 1) Move the delimiting value in the parent to the left node. |
| transfer(finish(), position(), parent(), alloc); |
| |
| // 2) Move the (to_move - 1) values from the right node to the left node. |
| transfer_n(to_move - 1, finish() + 1, right->start(), right, alloc); |
| |
| // 3) Move the new delimiting value to the parent from the right node. |
| parent()->transfer(position(), right->start() + to_move - 1, right, alloc); |
| |
| // 4) Shift the values in the right node to their correct positions. |
| right->transfer_n(right->count() - to_move, right->start(), |
| right->start() + to_move, right, alloc); |
| |
| if (is_internal()) { |
| // Move the child pointers from the right to the left node. |
| for (field_type i = 0; i < to_move; ++i) { |
| init_child(finish() + i + 1, right->child(i)); |
| } |
| for (field_type i = right->start(); i <= right->finish() - to_move; ++i) { |
| assert(i + to_move <= right->max_count()); |
| right->init_child(i, right->child(i + to_move)); |
| right->clear_child(i + to_move); |
| } |
| } |
| |
| // Fixup `finish` on the left and right nodes. |
| set_finish(finish() + to_move); |
| right->set_finish(right->finish() - to_move); |
| } |
| |
| template <typename P> |
| void btree_node<P>::rebalance_left_to_right(field_type to_move, |
| btree_node *right, |
| allocator_type *alloc) { |
| assert(parent() == right->parent()); |
| assert(position() + 1 == right->position()); |
| assert(count() >= right->count()); |
| assert(to_move >= 1); |
| assert(to_move <= count()); |
| |
| // Values in the right node are shifted to the right to make room for the |
| // new to_move values. Then, the delimiting value in the parent and the |
| // other (to_move - 1) values in the left node are moved into the right node. |
| // Lastly, a new delimiting value is moved from the left node into the |
| // parent, and the remaining empty left node entries are destroyed. |
| |
| // 1) Shift existing values in the right node to their correct positions. |
| right->transfer_n_backward(right->count(), right->start() + to_move, |
| right->start(), right, alloc); |
| |
| // 2) Move the delimiting value in the parent to the right node. |
| right->transfer(right->start() + to_move - 1, position(), parent(), alloc); |
| |
| // 3) Move the (to_move - 1) values from the left node to the right node. |
| right->transfer_n(to_move - 1, right->start(), finish() - (to_move - 1), this, |
| alloc); |
| |
| // 4) Move the new delimiting value to the parent from the left node. |
| parent()->transfer(position(), finish() - to_move, this, alloc); |
| |
| if (is_internal()) { |
| // Move the child pointers from the left to the right node. |
| for (field_type i = right->finish() + 1; i > right->start(); --i) { |
| right->init_child(i - 1 + to_move, right->child(i - 1)); |
| right->clear_child(i - 1); |
| } |
| for (field_type i = 1; i <= to_move; ++i) { |
| right->init_child(i - 1, child(finish() - to_move + i)); |
| clear_child(finish() - to_move + i); |
| } |
| } |
| |
| // Fixup the counts on the left and right nodes. |
| set_finish(finish() - to_move); |
| right->set_finish(right->finish() + to_move); |
| } |
| |
| template <typename P> |
| void btree_node<P>::split(const int insert_position, btree_node *dest, |
| allocator_type *alloc) { |
| assert(dest->count() == 0); |
| assert(max_count() == kNodeSlots); |
| assert(position() + 1 == dest->position()); |
| assert(parent() == dest->parent()); |
| |
| // We bias the split based on the position being inserted. If we're |
| // inserting at the beginning of the left node then bias the split to put |
| // more values on the right node. If we're inserting at the end of the |
| // right node then bias the split to put more values on the left node. |
| if (insert_position == start()) { |
| dest->set_finish(dest->start() + finish() - 1); |
| } else if (insert_position == kNodeSlots) { |
| dest->set_finish(dest->start()); |
| } else { |
| dest->set_finish(dest->start() + count() / 2); |
| } |
| set_finish(finish() - dest->count()); |
| assert(count() >= 1); |
| |
| // Move values from the left sibling to the right sibling. |
| dest->transfer_n(dest->count(), dest->start(), finish(), this, alloc); |
| |
| // The split key is the largest value in the left sibling. |
| --mutable_finish(); |
| parent()->emplace_value(position(), alloc, finish_slot()); |
| value_destroy(finish(), alloc); |
| parent()->set_child_noupdate_position(position() + 1, dest); |
| |
| if (is_internal()) { |
| for (field_type i = dest->start(), j = finish() + 1; i <= dest->finish(); |
| ++i, ++j) { |
| assert(child(j) != nullptr); |
| dest->init_child(i, child(j)); |
| clear_child(j); |
| } |
| } |
| } |
| |
| template <typename P> |
| void btree_node<P>::merge(btree_node *src, allocator_type *alloc) { |
| assert(parent() == src->parent()); |
| assert(position() + 1 == src->position()); |
| |
| // Move the delimiting value to the left node. |
| value_init(finish(), alloc, parent()->slot(position())); |
| |
| // Move the values from the right to the left node. |
| transfer_n(src->count(), finish() + 1, src->start(), src, alloc); |
| |
| if (is_internal()) { |
| // Move the child pointers from the right to the left node. |
| for (field_type i = src->start(), j = finish() + 1; i <= src->finish(); |
| ++i, ++j) { |
| init_child(j, src->child(i)); |
| src->clear_child(i); |
| } |
| } |
| |
| // Fixup `finish` on the src and dest nodes. |
| set_finish(start() + 1 + count() + src->count()); |
| src->set_finish(src->start()); |
| |
| // Remove the value on the parent node and delete the src node. |
| parent()->remove_values(position(), /*to_erase=*/1, alloc); |
| } |
| |
| template <typename P> |
| void btree_node<P>::clear_and_delete(btree_node *node, allocator_type *alloc) { |
| if (node->is_leaf()) { |
| node->value_destroy_n(node->start(), node->count(), alloc); |
| deallocate(LeafSize(node->max_count()), node, alloc); |
| return; |
| } |
| if (node->count() == 0) { |
| deallocate(InternalSize(), node, alloc); |
| return; |
| } |
| |
| // The parent of the root of the subtree we are deleting. |
| btree_node *delete_root_parent = node->parent(); |
| |
| // Navigate to the leftmost leaf under node, and then delete upwards. |
| while (node->is_internal()) node = node->start_child(); |
| #ifdef ABSL_BTREE_ENABLE_GENERATIONS |
| // When generations are enabled, we delete the leftmost leaf last in case it's |
| // the parent of the root and we need to check whether it's a leaf before we |
| // can update the root's generation. |
| // TODO(ezb): if we change btree_node::is_root to check a bool inside the node |
| // instead of checking whether the parent is a leaf, we can remove this logic. |
| btree_node *leftmost_leaf = node; |
| #endif |
| // Use `size_type` because `pos` needs to be able to hold `kNodeSlots+1`, |
| // which isn't guaranteed to be a valid `field_type`. |
| size_type pos = node->position(); |
| btree_node *parent = node->parent(); |
| for (;;) { |
| // In each iteration of the next loop, we delete one leaf node and go right. |
| assert(pos <= parent->finish()); |
| do { |
| node = parent->child(static_cast<field_type>(pos)); |
| if (node->is_internal()) { |
| // Navigate to the leftmost leaf under node. |
| while (node->is_internal()) node = node->start_child(); |
| pos = node->position(); |
| parent = node->parent(); |
| } |
| node->value_destroy_n(node->start(), node->count(), alloc); |
| #ifdef ABSL_BTREE_ENABLE_GENERATIONS |
| if (leftmost_leaf != node) |
| #endif |
| deallocate(LeafSize(node->max_count()), node, alloc); |
| ++pos; |
| } while (pos <= parent->finish()); |
| |
| // Once we've deleted all children of parent, delete parent and go up/right. |
| assert(pos > parent->finish()); |
| do { |
| node = parent; |
| pos = node->position(); |
| parent = node->parent(); |
| node->value_destroy_n(node->start(), node->count(), alloc); |
| deallocate(InternalSize(), node, alloc); |
| if (parent == delete_root_parent) { |
| #ifdef ABSL_BTREE_ENABLE_GENERATIONS |
| deallocate(LeafSize(leftmost_leaf->max_count()), leftmost_leaf, alloc); |
| #endif |
| return; |
| } |
| ++pos; |
| } while (pos > parent->finish()); |
| } |
| } |
| |
| //// |
| // btree_iterator methods |
| |
| // Note: the implementation here is based on btree_node::clear_and_delete. |
| template <typename N, typename R, typename P> |
| auto btree_iterator<N, R, P>::distance_slow(const_iterator other) const |
| -> difference_type { |
| const_iterator begin = other; |
| const_iterator end = *this; |
| assert(begin.node_ != end.node_ || !begin.node_->is_leaf() || |
| begin.position_ != end.position_); |
| |
| const node_type *node = begin.node_; |
| // We need to compensate for double counting if begin.node_ is a leaf node. |
| difference_type count = node->is_leaf() ? -begin.position_ : 0; |
| |
| // First navigate to the leftmost leaf node past begin. |
| if (node->is_internal()) { |
| ++count; |
| node = node->child(begin.position_ + 1); |
| } |
| while (node->is_internal()) node = node->start_child(); |
| |
| // Use `size_type` because `pos` needs to be able to hold `kNodeSlots+1`, |
| // which isn't guaranteed to be a valid `field_type`. |
| size_type pos = node->position(); |
| const node_type *parent = node->parent(); |
| for (;;) { |
| // In each iteration of the next loop, we count one leaf node and go right. |
| assert(pos <= parent->finish()); |
| do { |
| node = parent->child(static_cast<field_type>(pos)); |
| if (node->is_internal()) { |
| // Navigate to the leftmost leaf under node. |
| while (node->is_internal()) node = node->start_child(); |
| pos = node->position(); |
| parent = node->parent(); |
| } |
| if (node == end.node_) return count + end.position_; |
| if (parent == end.node_ && pos == static_cast<size_type>(end.position_)) |
| return count + node->count(); |
| // +1 is for the next internal node value. |
| count += node->count() + 1; |
| ++pos; |
| } while (pos <= parent->finish()); |
| |
| // Once we've counted all children of parent, go up/right. |
| assert(pos > parent->finish()); |
| do { |
| node = parent; |
| pos = node->position(); |
| parent = node->parent(); |
| // -1 because we counted the value at end and shouldn't. |
| if (parent == end.node_ && pos == static_cast<size_type>(end.position_)) |
| return count - 1; |
| ++pos; |
| } while (pos > parent->finish()); |
| } |
| } |
| |
| template <typename N, typename R, typename P> |
| void btree_iterator<N, R, P>::increment_slow() { |
| N* node = node_; |
| int position = position_; |
| if (node->is_leaf()) { |
| assert(position >= node->finish()); |
| while (position == node->finish() && !node->is_root()) { |
| assert(node->parent()->child(node->position()) == node); |
| position = node->position(); |
| node = node->parent(); |
| } |
| // TODO(ezb): assert we aren't incrementing end() instead of handling. |
| if (position == node->finish()) { |
| return; |
| } |
| } else { |
| assert(position < node->finish()); |
| node = node->child(static_cast<field_type>(position + 1)); |
| while (node->is_internal()) { |
| node = node->start_child(); |
| } |
| position = node->start(); |
| } |
| *this = {node, position}; |
| } |
| |
| template <typename N, typename R, typename P> |
| void btree_iterator<N, R, P>::decrement_slow() { |
| N* node = node_; |
| int position = position_; |
| if (node->is_leaf()) { |
| assert(position <= -1); |
| while (position < node->start() && !node->is_root()) { |
| assert(node->parent()->child(node->position()) == node); |
| position = node->position() - 1; |
| node = node->parent(); |
| } |
| // TODO(ezb): assert we aren't decrementing begin() instead of handling. |
| if (position < node->start()) { |
| return; |
| } |
| } else { |
| assert(position >= node->start()); |
| node = node->child(static_cast<field_type>(position)); |
| while (node->is_internal()) { |
| node = node->child(node->finish()); |
| } |
| position = node->finish() - 1; |
| } |
| *this = {node, position}; |
| } |
| |
| template <typename N, typename R, typename P> |
| btree_iterator<N, R, P> &btree_iterator<N, R, P>::increment_n_slow( |
| difference_type n) { |
| N *node = node_; |
| int position = position_; |
| ABSL_ASSUME(n > 0); |
| while (n > 0) { |
| if (node->is_leaf()) { |
| if (position + n < node->finish()) { |
| position += n; |
| break; |
| } else { |
| n -= node->finish() - position; |
| position = node->finish(); |
| btree_iterator save = {node, position}; |
| while (position == node->finish() && !node->is_root()) { |
| position = node->position(); |
| node = node->parent(); |
| } |
| if (position == node->finish()) { |
| ABSL_HARDENING_ASSERT(n == 0); |
| return *this = save; |
| } |
| } |
| } else { |
| --n; |
| assert(position < node->finish()); |
| node = node->child(static_cast<field_type>(position + 1)); |
| while (node->is_internal()) { |
| node = node->start_child(); |
| } |
| position = node->start(); |
| } |
| } |
| node_ = node; |
| position_ = position; |
| return *this; |
| } |
| |
| template <typename N, typename R, typename P> |
| btree_iterator<N, R, P> &btree_iterator<N, R, P>::decrement_n_slow( |
| difference_type n) { |
| N *node = node_; |
| int position = position_; |
| ABSL_ASSUME(n > 0); |
| while (n > 0) { |
| if (node->is_leaf()) { |
| if (position - n >= node->start()) { |
| position -= n; |
| break; |
| } else { |
| n -= 1 + position - node->start(); |
| position = node->start() - 1; |
| while (position < node->start() && !node->is_root()) { |
| position = node->position() - 1; |
| node = node->parent(); |
| } |
| ABSL_HARDENING_ASSERT(position >= node->start()); |
| } |
| } else { |
| --n; |
| assert(position >= node->start()); |
| node = node->child(static_cast<field_type>(position)); |
| while (node->is_internal()) { |
| node = node->child(node->finish()); |
| } |
| position = node->finish() - 1; |
| } |
| } |
| node_ = node; |
| position_ = position; |
| return *this; |
| } |
| |
| //// |
| // btree methods |
| template <typename P> |
| template <typename Btree> |
| void btree<P>::copy_or_move_values_in_order(Btree &other) { |
| static_assert(std::is_same<btree, Btree>::value || |
| std::is_same<const btree, Btree>::value, |
| "Btree type must be same or const."); |
| assert(empty()); |
| |
| // We can avoid key comparisons because we know the order of the |
| // values is the same order we'll store them in. |
| auto iter = other.begin(); |
| if (iter == other.end()) return; |
| insert_multi(iter.slot()); |
| ++iter; |
| for (; iter != other.end(); ++iter) { |
| // If the btree is not empty, we can just insert the new value at the end |
| // of the tree. |
| internal_emplace(end(), iter.slot()); |
| } |
| } |
| |
| template <typename P> |
| constexpr bool btree<P>::static_assert_validation() { |
| static_assert(std::is_nothrow_copy_constructible<key_compare>::value, |
| "Key comparison must be nothrow copy constructible"); |
| static_assert(std::is_nothrow_copy_constructible<allocator_type>::value, |
| "Allocator must be nothrow copy constructible"); |
| static_assert(std::is_trivially_copyable<iterator>::value, |
| "iterator not trivially copyable."); |
| |
| // Note: We assert that kTargetValues, which is computed from |
| // Params::kTargetNodeSize, must fit the node_type::field_type. |
| static_assert( |
| kNodeSlots < (1 << (8 * sizeof(typename node_type::field_type))), |
| "target node size too large"); |
| |
| // Verify that key_compare returns an absl::{weak,strong}_ordering or bool. |
| static_assert( |
| compare_has_valid_result_type<key_compare, key_type>(), |
| "key comparison function must return absl::{weak,strong}_ordering or " |
| "bool."); |
| |
| // Test the assumption made in setting kNodeSlotSpace. |
| static_assert(node_type::MinimumOverhead() >= sizeof(void *) + 4, |
| "node space assumption incorrect"); |
| |
| return true; |
| } |
| |
| template <typename P> |
| template <typename K> |
| auto btree<P>::lower_bound_equal(const K &key) const |
| -> std::pair<iterator, bool> { |
| const SearchResult<iterator, is_key_compare_to::value> res = |
| internal_lower_bound(key); |
| const iterator lower = iterator(internal_end(res.value)); |
| const bool equal = res.HasMatch() |
| ? res.IsEq() |
| : lower != end() && !compare_keys(key, lower.key()); |
| return {lower, equal}; |
| } |
| |
| template <typename P> |
| template <typename K> |
| auto btree<P>::equal_range(const K &key) -> std::pair<iterator, iterator> { |
| const std::pair<iterator, bool> lower_and_equal = lower_bound_equal(key); |
| const iterator lower = lower_and_equal.first; |
| if (!lower_and_equal.second) { |
| return {lower, lower}; |
| } |
| |
| const iterator next = std::next(lower); |
| if (!params_type::template can_have_multiple_equivalent_keys<K>()) { |
| // The next iterator after lower must point to a key greater than `key`. |
| // Note: if this assert fails, then it may indicate that the comparator does |
| // not meet the equivalence requirements for Compare |
| // (see https://en.cppreference.com/w/cpp/named_req/Compare). |
| assert(next == end() || compare_keys(key, next.key())); |
| return {lower, next}; |
| } |
| // Try once more to avoid the call to upper_bound() if there's only one |
| // equivalent key. This should prevent all calls to upper_bound() in cases of |
| // unique-containers with heterogeneous comparators in which all comparison |
| // operators have the same equivalence classes. |
| if (next == end() || compare_keys(key, next.key())) return {lower, next}; |
| |
| // In this case, we need to call upper_bound() to avoid worst case O(N) |
| // behavior if we were to iterate over equal keys. |
| return {lower, upper_bound(key)}; |
| } |
| |
| template <typename P> |
| template <typename K, typename... Args> |
| auto btree<P>::insert_unique(const K &key, Args &&...args) |
| -> std::pair<iterator, bool> { |
| if (empty()) { |
| mutable_root() = mutable_rightmost() = new_leaf_root_node(1); |
| } |
| |
| SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key); |
| iterator iter = res.value; |
| |
| if (res.HasMatch()) { |
| if (res.IsEq()) { |
| // The key already exists in the tree, do nothing. |
| return {iter, false}; |
| } |
| } else { |
| iterator last = internal_last(iter); |
| if (last.node_ && !compare_keys(key, last.key())) { |
| // The key already exists in the tree, do nothing. |
| return {last, false}; |
| } |
| } |
| return {internal_emplace(iter, std::forward<Args>(args)...), true}; |
| } |
| |
| template <typename P> |
| template <typename K, typename... Args> |
| inline auto btree<P>::insert_hint_unique(iterator position, const K &key, |
| Args &&...args) |
| -> std::pair<iterator, bool> { |
| if (!empty()) { |
| if (position == end() || compare_keys(key, position.key())) { |
| if (position == begin() || compare_keys(std::prev(position).key(), key)) { |
| // prev.key() < key < position.key() |
| return {internal_emplace(position, std::forward<Args>(args)...), true}; |
| } |
| } else if (compare_keys(position.key(), key)) { |
| ++position; |
| if (position == end() || compare_keys(key, position.key())) { |
| // {original `position`}.key() < key < {current `position`}.key() |
| return {internal_emplace(position, std::forward<Args>(args)...), true}; |
| } |
| } else { |
| // position.key() == key |
| return {position, false}; |
| } |
| } |
| return insert_unique(key, std::forward<Args>(args)...); |
| } |
| |
| template <typename P> |
| template <typename InputIterator, typename> |
| void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e, int) { |
| for (; b != e; ++b) { |
| insert_hint_unique(end(), params_type::key(*b), *b); |
| } |
| } |
| |
| template <typename P> |
| template <typename InputIterator> |
| void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e, char) { |
| for (; b != e; ++b) { |
| // Use a node handle to manage a temp slot. |
| auto node_handle = |
| CommonAccess::Construct<node_handle_type>(get_allocator(), *b); |
| slot_type *slot = CommonAccess::GetSlot(node_handle); |
| insert_hint_unique(end(), params_type::key(slot), slot); |
| } |
| } |
| |
| template <typename P> |
| template <typename ValueType> |
| auto btree<P>::insert_multi(const key_type &key, ValueType &&v) -> iterator { |
| if (empty()) { |
| mutable_root() = mutable_rightmost() = new_leaf_root_node(1); |
| } |
| |
| iterator iter = internal_upper_bound(key); |
| if (iter.node_ == nullptr) { |
| iter = end(); |
| } |
| return internal_emplace(iter, std::forward<ValueType>(v)); |
| } |
| |
| template <typename P> |
| template <typename ValueType> |
| auto btree<P>::insert_hint_multi(iterator position, ValueType &&v) -> iterator { |
| if (!empty()) { |
| const key_type &key = params_type::key(v); |
| if (position == end() || !compare_keys(position.key(), key)) { |
| if (position == begin() || |
| !compare_keys(key, std::prev(position).key())) { |
| // prev.key() <= key <= position.key() |
| return internal_emplace(position, std::forward<ValueType>(v)); |
| } |
| } else { |
| ++position; |
| if (position == end() || !compare_keys(position.key(), key)) { |
| // {original `position`}.key() < key < {current `position`}.key() |
| return internal_emplace(position, std::forward<ValueType>(v)); |
| } |
| } |
| } |
| return insert_multi(std::forward<ValueType>(v)); |
| } |
| |
| template <typename P> |
| template <typename InputIterator> |
| void btree<P>::insert_iterator_multi(InputIterator b, InputIterator e) { |
| for (; b != e; ++b) { |
| insert_hint_multi(end(), *b); |
| } |
| } |
| |
| template <typename P> |
| auto btree<P>::operator=(const btree &other) -> btree & { |
| if (this != &other) { |
| clear(); |
| |
| *mutable_key_comp() = other.key_comp(); |
| if (absl::allocator_traits< |
| allocator_type>::propagate_on_container_copy_assignment::value) { |
| *mutable_allocator() = other.allocator(); |
| } |
| |
| copy_or_move_values_in_order(other); |
| } |
| return *this; |
| } |
| |
| template <typename P> |
| auto btree<P>::operator=(btree &&other) noexcept -> btree & { |
| if (this != &other) { |
| clear(); |
| |
| using std::swap; |
| if (absl::allocator_traits< |
| allocator_type>::propagate_on_container_move_assignment::value) { |
| swap(root_, other.root_); |
| // Note: `rightmost_` also contains the allocator and the key comparator. |
| swap(rightmost_, other.rightmost_); |
| swap(size_, other.size_); |
| } else { |
| if (allocator() == other.allocator()) { |
| swap(mutable_root(), other.mutable_root()); |
| swap(*mutable_key_comp(), *other.mutable_key_comp()); |
| swap(mutable_rightmost(), other.mutable_rightmost()); |
| swap(size_, other.size_); |
| } else { |
| // We aren't allowed to propagate the allocator and the allocator is |
| // different so we can't take over its memory. We must move each element |
| // individually. We need both `other` and `this` to have `other`s key |
| // comparator while moving the values so we can't swap the key |
| // comparators. |
| *mutable_key_comp() = other.key_comp(); |
| copy_or_move_values_in_order(other); |
| } |
| } |
| } |
| return *this; |
| } |
| |
| template <typename P> |
| auto btree<P>::erase(iterator iter) -> iterator { |
| iter.node_->value_destroy(static_cast<field_type>(iter.position_), |
| mutable_allocator()); |
| iter.update_generation(); |
| |
| const bool internal_delete = iter.node_->is_internal(); |
| if (internal_delete) { |
| // Deletion of a value on an internal node. First, transfer the largest |
| // value from our left child here, then erase/rebalance from that position. |
| // We can get to the largest value from our left child by decrementing iter. |
| iterator internal_iter(iter); |
| --iter; |
| assert(iter.node_->is_leaf()); |
| internal_iter.node_->transfer( |
| static_cast<size_type>(internal_iter.position_), |
| static_cast<size_type>(iter.position_), iter.node_, |
| mutable_allocator()); |
| } else { |
| // Shift values after erased position in leaf. In the internal case, we |
| // don't need to do this because the leaf position is the end of the node. |
| const field_type transfer_from = |
| static_cast<field_type>(iter.position_ + 1); |
| const field_type num_to_transfer = iter.node_->finish() - transfer_from; |
| iter.node_->transfer_n(num_to_transfer, |
| static_cast<size_type>(iter.position_), |
| transfer_from, iter.node_, mutable_allocator()); |
| } |
| // Update node finish and container size. |
| iter.node_->set_finish(iter.node_->finish() - 1); |
| --size_; |
| |
| // We want to return the next value after the one we just erased. If we |
| // erased from an internal node (internal_delete == true), then the next |
| // value is ++(++iter). If we erased from a leaf node (internal_delete == |
| // false) then the next value is ++iter. Note that ++iter may point to an |
| // internal node and the value in the internal node may move to a leaf node |
| // (iter.node_) when rebalancing is performed at the leaf level. |
| |
| iterator res = rebalance_after_delete(iter); |
| |
| // If we erased from an internal node, advance the iterator. |
| if (internal_delete) { |
| ++res; |
| } |
| return res; |
| } |
| |
| template <typename P> |
| auto btree<P>::rebalance_after_delete(iterator iter) -> iterator { |
| // Merge/rebalance as we walk back up the tree. |
| iterator res(iter); |
| bool first_iteration = true; |
| for (;;) { |
| if (iter.node_ == root()) { |
| try_shrink(); |
| if (empty()) { |
| return end(); |
| } |
| break; |
| } |
| if (iter.node_->count() >= kMinNodeValues) { |
| break; |
| } |
| bool merged = try_merge_or_rebalance(&iter); |
| // On the first iteration, we should update `res` with `iter` because `res` |
| // may have been invalidated. |
| if (first_iteration) { |
| res = iter; |
| first_iteration = false; |
| } |
| if (!merged) { |
| break; |
| } |
| iter.position_ = iter.node_->position(); |
| iter.node_ = iter.node_->parent(); |
| } |
| res.update_generation(); |
| |
| // Adjust our return value. If we're pointing at the end of a node, advance |
| // the iterator. |
| if (res.position_ == res.node_->finish()) { |
| res.position_ = res.node_->finish() - 1; |
| ++res; |
| } |
| |
| return res; |
| } |
| |
| // Note: we tried implementing this more efficiently by erasing all of the |
| // elements in [begin, end) at once and then doing rebalancing once at the end |
| // (rather than interleaving deletion and rebalancing), but that adds a lot of |
| // complexity, which seems to outweigh the performance win. |
| template <typename P> |
| auto btree<P>::erase_range(iterator begin, iterator end) |
| -> std::pair<size_type, iterator> { |
| size_type count = static_cast<size_type>(end - begin); |
| assert(count >= 0); |
| |
| if (count == 0) { |
| return {0, begin}; |
| } |
| |
| if (static_cast<size_type>(count) == size_) { |
| clear(); |
| return {count, this->end()}; |
| } |
| |
| if (begin.node_ == end.node_) { |
| assert(end.position_ > begin.position_); |
| begin.node_->remove_values( |
| static_cast<field_type>(begin.position_), |
| static_cast<field_type>(end.position_ - begin.position_), |
| mutable_allocator()); |
| size_ -= count; |
| return {count, rebalance_after_delete(begin)}; |
| } |
| |
| const size_type target_size = size_ - count; |
| while (size_ > target_size) { |
| if (begin.node_->is_leaf()) { |
| const size_type remaining_to_erase = size_ - target_size; |
| const size_type remaining_in_node = |
| static_cast<size_type>(begin.node_->finish() - begin.position_); |
| const field_type to_erase = static_cast<field_type>( |
| (std::min)(remaining_to_erase, remaining_in_node)); |
| begin.node_->remove_values(static_cast<field_type>(begin.position_), |
| to_erase, mutable_allocator()); |
| size_ -= to_erase; |
| begin = rebalance_after_delete(begin); |
| } else { |
| begin = erase(begin); |
| } |
| } |
| begin.update_generation(); |
| return {count, begin}; |
| } |
| |
| template <typename P> |
| void btree<P>::clear() { |
| if (!empty()) { |
| node_type::clear_and_delete(root(), mutable_allocator()); |
| } |
| mutable_root() = mutable_rightmost() = EmptyNode(); |
| size_ = 0; |
| } |
| |
| template <typename P> |
| void btree<P>::swap(btree &other) { |
| using std::swap; |
| if (absl::allocator_traits< |
| allocator_type>::propagate_on_container_swap::value) { |
| // Note: `rightmost_` also contains the allocator and the key comparator. |
| swap(rightmost_, other.rightmost_); |
| } else { |
| // It's undefined behavior if the allocators are unequal here. |
| assert(allocator() == other.allocator()); |
| swap(mutable_rightmost(), other.mutable_rightmost()); |
| swap(*mutable_key_comp(), *other.mutable_key_comp()); |
| } |
| swap(mutable_root(), other.mutable_root()); |
| swap(size_, other.size_); |
| } |
| |
| template <typename P> |
| void btree<P>::verify() const { |
| assert(root() != nullptr); |
| assert(leftmost() != nullptr); |
| assert(rightmost() != nullptr); |
| assert(empty() || size() == internal_verify(root(), nullptr, nullptr)); |
| assert(leftmost() == (++const_iterator(root(), -1)).node_); |
| assert(rightmost() == (--const_iterator(root(), root()->finish())).node_); |
| assert(leftmost()->is_leaf()); |
| assert(rightmost()->is_leaf()); |
| } |
| |
| template <typename P> |
| void btree<P>::rebalance_or_split(iterator *iter) { |
| node_type *&node = iter->node_; |
| int &insert_position = iter->position_; |
| assert(node->count() == node->max_count()); |
| assert(kNodeSlots == node->max_count()); |
| |
| // First try to make room on the node by rebalancing. |
| node_type *parent = node->parent(); |
| if (node != root()) { |
| if (node->position() > parent->start()) { |
| // Try rebalancing with our left sibling. |
| node_type *left = parent->child(node->position() - 1); |
| assert(left->max_count() == kNodeSlots); |
| if (left->count() < kNodeSlots) { |
| // We bias rebalancing based on the position being inserted. If we're |
| // inserting at the end of the right node then we bias rebalancing to |
| // fill up the left node. |
| field_type to_move = |
| (kNodeSlots - left->count()) / |
| (1 + (static_cast<field_type>(insert_position) < kNodeSlots)); |
| to_move = (std::max)(field_type{1}, to_move); |
| |
| if (static_cast<field_type>(insert_position) - to_move >= |
| node->start() || |
| left->count() + to_move < kNodeSlots) { |
| left->rebalance_right_to_left(to_move, node, mutable_allocator()); |
| |
| assert(node->max_count() - node->count() == to_move); |
| insert_position = static_cast<int>( |
| static_cast<field_type>(insert_position) - to_move); |
| if (insert_position < node->start()) { |
| insert_position = insert_position + left->count() + 1; |
| node = left; |
| } |
| |
| assert(node->count() < node->max_count()); |
| return; |
| } |
| } |
| } |
| |
| if (node->position() < parent->finish()) { |
| // Try rebalancing with our right sibling. |
| node_type *right = parent->child(node->position() + 1); |
| assert(right->max_count() == kNodeSlots); |
| if (right->count() < kNodeSlots) { |
| // We bias rebalancing based on the position being inserted. If we're |
| // inserting at the beginning of the left node then we bias rebalancing |
| // to fill up the right node. |
| field_type to_move = (kNodeSlots - right->count()) / |
| (1 + (insert_position > node->start())); |
| to_move = (std::max)(field_type{1}, to_move); |
| |
| if (static_cast<field_type>(insert_position) <= |
| node->finish() - to_move || |
| right->count() + to_move < kNodeSlots) { |
| node->rebalance_left_to_right(to_move, right, mutable_allocator()); |
| |
| if (insert_position > node->finish()) { |
| insert_position = insert_position - node->count() - 1; |
| node = right; |
| } |
| |
| assert(node->count() < node->max_count()); |
| return; |
| } |
| } |
| } |
| |
| // Rebalancing failed, make sure there is room on the parent node for a new |
| // value. |
| assert(parent->max_count() == kNodeSlots); |
| if (parent->count() == kNodeSlots) { |
| iterator parent_iter(parent, node->position()); |
| rebalance_or_split(&parent_iter); |
| parent = node->parent(); |
| } |
| } else { |
| // Rebalancing not possible because this is the root node. |
| // Create a new root node and set the current root node as the child of the |
| // new root. |
| parent = new_internal_node(/*position=*/0, parent); |
| parent->set_generation(root()->generation()); |
| parent->init_child(parent->start(), node); |
| mutable_root() = parent; |
| // If the former root was a leaf node, then it's now the rightmost node. |
| assert(parent->start_child()->is_internal() || |
| parent->start_child() == rightmost()); |
| } |
| |
| // Split the node. |
| node_type *split_node; |
| if (node->is_leaf()) { |
| split_node = new_leaf_node(node->position() + 1, parent); |
| node->split(insert_position, split_node, mutable_allocator()); |
| if (rightmost() == node) mutable_rightmost() = split_node; |
| } else { |
| split_node = new_internal_node(node->position() + 1, parent); |
| node->split(insert_position, split_node, mutable_allocator()); |
| } |
| |
| if (insert_position > node->finish()) { |
| insert_position = insert_position - node->count() - 1; |
| node = split_node; |
| } |
| } |
| |
| template <typename P> |
| void btree<P>::merge_nodes(node_type *left, node_type *right) { |
| left->merge(right, mutable_allocator()); |
| if (rightmost() == right) mutable_rightmost() = left; |
| } |
| |
| template <typename P> |
| bool btree<P>::try_merge_or_rebalance(iterator *iter) { |
| node_type *parent = iter->node_->parent(); |
| if (iter->node_->position() > parent->start()) { |
| // Try merging with our left sibling. |
| node_type *left = parent->child(iter->node_->position() - 1); |
| assert(left->max_count() == kNodeSlots); |
| if (1U + left->count() + iter->node_->count() <= kNodeSlots) { |
| iter->position_ += 1 + left->count(); |
| merge_nodes(left, iter->node_); |
| iter->node_ = left; |
| return true; |
| } |
| } |
| if (iter->node_->position() < parent->finish()) { |
| // Try merging with our right sibling. |
| node_type *right = parent->child(iter->node_->position() + 1); |
| assert(right->max_count() == kNodeSlots); |
| if (1U + iter->node_->count() + right->count() <= kNodeSlots) { |
| merge_nodes(iter->node_, right); |
| return true; |
| } |
| // Try rebalancing with our right sibling. We don't perform rebalancing if |
| // we deleted the first element from iter->node_ and the node is not |
| // empty. This is a small optimization for the common pattern of deleting |
| // from the front of the tree. |
| if (right->count() > kMinNodeValues && |
| (iter->node_->count() == 0 || iter->position_ > iter->node_->start())) { |
| field_type to_move = (right->count() - iter->node_->count()) / 2; |
| to_move = |
| (std::min)(to_move, static_cast<field_type>(right->count() - 1)); |
| iter->node_->rebalance_right_to_left(to_move, right, mutable_allocator()); |
| return false; |
| } |
| } |
| if (iter->node_->position() > parent->start()) { |
| // Try rebalancing with our left sibling. We don't perform rebalancing if |
| // we deleted the last element from iter->node_ and the node is not |
| // empty. This is a small optimization for the common pattern of deleting |
| // from the back of the tree. |
| node_type *left = parent->child(iter->node_->position() - 1); |
| if (left->count() > kMinNodeValues && |
| (iter->node_->count() == 0 || |
| iter->position_ < iter->node_->finish())) { |
| field_type to_move = (left->count() - iter->node_->count()) / 2; |
| to_move = (std::min)(to_move, static_cast<field_type>(left->count() - 1)); |
| left->rebalance_left_to_right(to_move, iter->node_, mutable_allocator()); |
| iter->position_ += to_move; |
| return false; |
| } |
| } |
| return false; |
| } |
| |
| template <typename P> |
| void btree<P>::try_shrink() { |
| node_type *orig_root = root(); |
| if (orig_root->count() > 0) { |
| return; |
| } |
| // Deleted the last item on the root node, shrink the height of the tree. |
| if (orig_root->is_leaf()) { |
| assert(size() == 0); |
| mutable_root() = mutable_rightmost() = EmptyNode(); |
| } else { |
| node_type *child = orig_root->start_child(); |
| child->make_root(); |
| mutable_root() = child; |
| } |
| node_type::clear_and_delete(orig_root, mutable_allocator()); |
| } |
| |
| template <typename P> |
| template <typename IterType> |
| inline IterType btree<P>::internal_last(IterType iter) { |
| assert(iter.node_ != nullptr); |
| while (iter.position_ == iter.node_->finish()) { |
| iter.position_ = iter.node_->position(); |
| iter.node_ = iter.node_->parent(); |
| if (iter.node_->is_leaf()) { |
| iter.node_ = nullptr; |
| break; |
| } |
| } |
| iter.update_generation(); |
| return iter; |
| } |
| |
| template <typename P> |
| template <typename... Args> |
| inline auto btree<P>::internal_emplace(iterator iter, Args &&...args) |
| -> iterator { |
| if (iter.node_->is_internal()) { |
| // We can't insert on an internal node. Instead, we'll insert after the |
| // previous value which is guaranteed to be on a leaf node. |
| --iter; |
| ++iter.position_; |
| } |
| const field_type max_count = iter.node_->max_count(); |
| allocator_type *alloc = mutable_allocator(); |
| |
| const auto transfer_and_delete = [&](node_type *old_node, |
| node_type *new_node) { |
| new_node->transfer_n(old_node->count(), new_node->start(), |
| old_node->start(), old_node, alloc); |
| new_node->set_finish(old_node->finish()); |
| old_node->set_finish(old_node->start()); |
| new_node->set_generation(old_node->generation()); |
| node_type::clear_and_delete(old_node, alloc); |
| }; |
| const auto replace_leaf_root_node = [&](field_type new_node_size) { |
| assert(iter.node_ == root()); |
| node_type *old_root = iter.node_; |
| node_type *new_root = iter.node_ = new_leaf_root_node(new_node_size); |
| transfer_and_delete(old_root, new_root); |
| mutable_root() = mutable_rightmost() = new_root; |
| }; |
| |
| bool replaced_node = false; |
| if (iter.node_->count() == max_count) { |
| // Make room in the leaf for the new item. |
| if (max_count < kNodeSlots) { |
| // Insertion into the root where the root is smaller than the full node |
| // size. Simply grow the size of the root node. |
| replace_leaf_root_node(static_cast<field_type>( |
| (std::min)(static_cast<int>(kNodeSlots), 2 * max_count))); |
| replaced_node = true; |
| } else { |
| rebalance_or_split(&iter); |
| } |
| } |
| (void)replaced_node; |
| #if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ |
| defined(ABSL_HAVE_HWADDRESS_SANITIZER) |
| if (!replaced_node) { |
| assert(iter.node_->is_leaf()); |
| if (iter.node_->is_root()) { |
| replace_leaf_root_node(max_count); |
| } else { |
| node_type *old_node = iter.node_; |
| const bool was_rightmost = rightmost() == old_node; |
| const bool was_leftmost = leftmost() == old_node; |
| node_type *parent = old_node->parent(); |
| const field_type position = old_node->position(); |
| node_type *new_node = iter.node_ = new_leaf_node(position, parent); |
| parent->set_child_noupdate_position(position, new_node); |
| transfer_and_delete(old_node, new_node); |
| if (was_rightmost) mutable_rightmost() = new_node; |
| // The leftmost node is stored as the parent of the root node. |
| if (was_leftmost) root()->set_parent(new_node); |
| } |
| } |
| #endif |
| iter.node_->emplace_value(static_cast<field_type>(iter.position_), alloc, |
| std::forward<Args>(args)...); |
| assert( |
| iter.node_->is_ordered_correctly(static_cast<field_type>(iter.position_), |
| original_key_compare(key_comp())) && |
| "If this assert fails, then either (1) the comparator may violate " |
| "transitivity, i.e. comp(a,b) && comp(b,c) -> comp(a,c) (see " |
| "https://en.cppreference.com/w/cpp/named_req/Compare), or (2) a " |
| "key may have been mutated after it was inserted into the tree."); |
| ++size_; |
| iter.update_generation(); |
| return iter; |
| } |
| |
| template <typename P> |
| template <typename K> |
| inline auto btree<P>::internal_locate(const K &key) const |
| -> SearchResult<iterator, is_key_compare_to::value> { |
| iterator iter(const_cast<node_type *>(root())); |
| for (;;) { |
| SearchResult<size_type, is_key_compare_to::value> res = |
| iter.node_->lower_bound(key, key_comp()); |
| iter.position_ = static_cast<int>(res.value); |
| if (res.IsEq()) { |
| return {iter, MatchKind::kEq}; |
| } |
| // Note: in the non-key-compare-to case, we don't need to walk all the way |
| // down the tree if the keys are equal, but determining equality would |
| // require doing an extra comparison on each node on the way down, and we |
| // will need to go all the way to the leaf node in the expected case. |
| if (iter.node_->is_leaf()) { |
| break; |
| } |
| iter.node_ = iter.node_->child(static_cast<field_type>(iter.position_)); |
| } |
| // Note: in the non-key-compare-to case, the key may actually be equivalent |
| // here (and the MatchKind::kNe is ignored). |
| return {iter, MatchKind::kNe}; |
| } |
| |
| template <typename P> |
| template <typename K> |
| auto btree<P>::internal_lower_bound(const K &key) const |
| -> SearchResult<iterator, is_key_compare_to::value> { |
| if (!params_type::template can_have_multiple_equivalent_keys<K>()) { |
| SearchResult<iterator, is_key_compare_to::value> ret = internal_locate(key); |
| ret.value = internal_last(ret.value); |
| return ret; |
| } |
| iterator iter(const_cast<node_type *>(root())); |
| SearchResult<size_type, is_key_compare_to::value> res; |
| bool seen_eq = false; |
| for (;;) { |
| res = iter.node_->lower_bound(key, key_comp()); |
| iter.position_ = static_cast<int>(res.value); |
| if (iter.node_->is_leaf()) { |
| break; |
| } |
| seen_eq = seen_eq || res.IsEq(); |
| iter.node_ = iter.node_->child(static_cast<field_type>(iter.position_)); |
| } |
| if (res.IsEq()) return {iter, MatchKind::kEq}; |
| return {internal_last(iter), seen_eq ? MatchKind::kEq : MatchKind::kNe}; |
| } |
| |
| template <typename P> |
| template <typename K> |
| auto btree<P>::internal_upper_bound(const K &key) const -> iterator { |
| iterator iter(const_cast<node_type *>(root())); |
| for (;;) { |
| iter.position_ = static_cast<int>(iter.node_->upper_bound(key, key_comp())); |
| if (iter.node_->is_leaf()) { |
| break; |
| } |
| iter.node_ = iter.node_->child(static_cast<field_type>(iter.position_)); |
| } |
| return internal_last(iter); |
| } |
| |
| template <typename P> |
| template <typename K> |
| auto btree<P>::internal_find(const K &key) const -> iterator { |
| SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key); |
| if (res.HasMatch()) { |
| if (res.IsEq()) { |
| return res.value; |
| } |
| } else { |
| const iterator iter = internal_last(res.value); |
| if (iter.node_ != nullptr && !compare_keys(key, iter.key())) { |
| return iter; |
| } |
| } |
| return {nullptr, 0}; |
| } |
| |
| template <typename P> |
| typename btree<P>::size_type btree<P>::internal_verify( |
| const node_type *node, const key_type *lo, const key_type *hi) const { |
| assert(node->count() > 0); |
| assert(node->count() <= node->max_count()); |
| if (lo) { |
| assert(!compare_keys(node->key(node->start()), *lo)); |
| } |
| if (hi) { |
| assert(!compare_keys(*hi, node->key(node->finish() - 1))); |
| } |
| for (int i = node->start() + 1; i < node->finish(); ++i) { |
| assert(!compare_keys(node->key(i), node->key(i - 1))); |
| } |
| size_type count = node->count(); |
| if (node->is_internal()) { |
| for (field_type i = node->start(); i <= node->finish(); ++i) { |
| assert(node->child(i) != nullptr); |
| assert(node->child(i)->parent() == node); |
| assert(node->child(i)->position() == i); |
| count += internal_verify(node->child(i), |
| i == node->start() ? lo : &node->key(i - 1), |
| i == node->finish() ? hi : &node->key(i)); |
| } |
| } |
| return count; |
| } |
| |
| struct btree_access { |
| template <typename BtreeContainer, typename Pred> |
| static auto erase_if(BtreeContainer &container, Pred pred) -> |
| typename BtreeContainer::size_type { |
| const auto initial_size = container.size(); |
| auto &tree = container.tree_; |
| auto *alloc = tree.mutable_allocator(); |
| for (auto it = container.begin(); it != container.end();) { |
| if (!pred(*it)) { |
| ++it; |
| continue; |
| } |
| auto *node = it.node_; |
| if (node->is_internal()) { |
| // Handle internal nodes normally. |
| it = container.erase(it); |
| continue; |
| } |
| // If this is a leaf node, then we do all the erases from this node |
| // at once before doing rebalancing. |
| |
| // The current position to transfer slots to. |
| int to_pos = it.position_; |
| node->value_destroy(it.position_, alloc); |
| while (++it.position_ < node->finish()) { |
| it.update_generation(); |
| if (pred(*it)) { |
| node->value_destroy(it.position_, alloc); |
| } else { |
| node->transfer(node->slot(to_pos++), node->slot(it.position_), alloc); |
| } |
| } |
| const int num_deleted = node->finish() - to_pos; |
| tree.size_ -= num_deleted; |
| node->set_finish(to_pos); |
| it.position_ = to_pos; |
| it = tree.rebalance_after_delete(it); |
| } |
| return initial_size - container.size(); |
| } |
| }; |
| |
| #undef ABSL_BTREE_ENABLE_GENERATIONS |
| |
| } // namespace container_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CONTAINER_INTERNAL_BTREE_H_ |
| *°% |
| ksoong/.intermediates/external/abseil-cpp/absl_types_span_hdrs/gen/my_include_dir/absl/types/internal/span.hÀ$// |
| // Copyright 2019 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| #ifndef ABSL_TYPES_INTERNAL_SPAN_H_ |
| #define ABSL_TYPES_INTERNAL_SPAN_H_ |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <string> |
| #include <type_traits> |
| |
| #include "absl/algorithm/algorithm.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/throw_delegate.h" |
| #include "absl/meta/type_traits.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| template <typename T> |
| class Span; |
| |
| namespace span_internal { |
| // Wrappers for access to container data pointers. |
| template <typename C> |
| constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references) |
| -> decltype(c.data()) { |
| return c.data(); |
| } |
| |
| // Before C++17, std::string::data returns a const char* in all cases. |
| inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references) |
| int) noexcept { |
| return &s[0]; |
| } |
| |
| template <typename C> |
| constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references) |
| -> decltype(GetDataImpl(c, 0)) { |
| return GetDataImpl(c, 0); |
| } |
| |
| // Detection idioms for size() and data(). |
| template <typename C> |
| using HasSize = |
| std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>; |
| |
| // We want to enable conversion from vector<T*> to Span<const T* const> but |
| // disable conversion from vector<Derived> to Span<Base>. Here we use |
| // the fact that U** is convertible to Q* const* if and only if Q is the same |
| // type or a more cv-qualified version of U. We also decay the result type of |
| // data() to avoid problems with classes which have a member function data() |
| // which returns a reference. |
| template <typename T, typename C> |
| using HasData = |
| std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*, |
| T* const*>; |
| |
| // Extracts value type from a Container |
| template <typename C> |
| struct ElementType { |
| using type = typename absl::remove_reference_t<C>::value_type; |
| }; |
| |
| template <typename T, size_t N> |
| struct ElementType<T (&)[N]> { |
| using type = T; |
| }; |
| |
| template <typename C> |
| using ElementT = typename ElementType<C>::type; |
| |
| template <typename T> |
| using EnableIfMutable = |
| typename std::enable_if<!std::is_const<T>::value, int>::type; |
| |
| template <template <typename> class SpanT, typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool EqualImpl(SpanT<T> a, SpanT<T> b) { |
| static_assert(std::is_const<T>::value, ""); |
| return std::equal(a.begin(), a.end(), b.begin(), b.end()); |
| } |
| |
| template <template <typename> class SpanT, typename T> |
| ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool LessThanImpl(SpanT<T> a, SpanT<T> b) { |
| // We can't use value_type since that is remove_cv_t<T>, so we go the long way |
| // around. |
| static_assert(std::is_const<T>::value, ""); |
| return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); |
| } |
| |
| template <typename From, typename To> |
| using EnableIfConvertibleTo = |
| typename std::enable_if<std::is_convertible<From, To>::value>::type; |
| |
| // IsView is true for types where the return type of .data() is the same for |
| // mutable and const instances. This isn't foolproof, but it's only used to |
| // enable a compiler warning. |
| template <typename T, typename = void, typename = void> |
| struct IsView { |
| static constexpr bool value = false; |
| }; |
| |
| template <typename T> |
| struct IsView< |
| T, absl::void_t<decltype(span_internal::GetData(std::declval<const T&>()))>, |
| absl::void_t<decltype(span_internal::GetData(std::declval<T&>()))>> { |
| private: |
| using Container = std::remove_const_t<T>; |
| using ConstData = |
| decltype(span_internal::GetData(std::declval<const Container&>())); |
| using MutData = decltype(span_internal::GetData(std::declval<Container&>())); |
| public: |
| static constexpr bool value = std::is_same<ConstData, MutData>::value; |
| }; |
| |
| // These enablers result in 'int' so they can be used as typenames or defaults |
| // in template parameters lists. |
| template <typename T> |
| using EnableIfIsView = std::enable_if_t<IsView<T>::value, int>; |
| |
| template <typename T> |
| using EnableIfNotIsView = std::enable_if_t<!IsView<T>::value, int>; |
| |
| } // namespace span_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_TYPES_INTERNAL_SPAN_H_ |
| *Å
|
| dsoong/.intermediates/external/abseil-cpp/absl_utility_hdrs/gen/my_include_dir/absl/utility/utility.hÜ// Copyright 2017 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_UTILITY_UTILITY_H_ |
| #define ABSL_UTILITY_UTILITY_H_ |
| |
| #include <cstddef> |
| #include <cstdlib> |
| #include <tuple> |
| #include <utility> |
| |
| #include "absl/base/config.h" |
| |
| // TODO(b/290784225): Include what you use cleanup required. |
| #include "absl/meta/type_traits.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| |
| // Historical note: Abseil once provided implementations of these |
| // abstractions for platforms that had not yet provided them. Those |
| // platforms are no longer supported. New code should simply use the |
| // the ones from std directly. |
| using std::apply; |
| using std::exchange; |
| using std::forward; |
| using std::in_place; |
| using std::in_place_index; |
| using std::in_place_index_t; |
| using std::in_place_t; |
| using std::in_place_type; |
| using std::in_place_type_t; |
| using std::index_sequence; |
| using std::index_sequence_for; |
| using std::integer_sequence; |
| using std::make_from_tuple; |
| using std::make_index_sequence; |
| using std::make_integer_sequence; |
| using std::move; |
| |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_UTILITY_UTILITY_H_ |
| *ëø |
| wsoong/.intermediates/external/abseil-cpp/absl_container_layout_hdrs/gen/my_include_dir/absl/container/internal/layout.hî÷// 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. |
| // |
| // MOTIVATION AND TUTORIAL |
| // |
| // If you want to put in a single heap allocation N doubles followed by M ints, |
| // it's easy if N and M are known at compile time. |
| // |
| // struct S { |
| // double a[N]; |
| // int b[M]; |
| // }; |
| // |
| // S* p = new S; |
| // |
| // But what if N and M are known only in run time? Class template Layout to the |
| // rescue! It's a portable generalization of the technique known as struct hack. |
| // |
| // // This object will tell us everything we need to know about the memory |
| // // layout of double[N] followed by int[M]. It's structurally identical to |
| // // size_t[2] that stores N and M. It's very cheap to create. |
| // const Layout<double, int> layout(N, M); |
| // |
| // // Allocate enough memory for both arrays. `AllocSize()` tells us how much |
| // // memory is needed. We are free to use any allocation function we want as |
| // // long as it returns aligned memory. |
| // std::unique_ptr<unsigned char[]> p(new unsigned char[layout.AllocSize()]); |
| // |
| // // Obtain the pointer to the array of doubles. |
| // // Equivalent to `reinterpret_cast<double*>(p.get())`. |
| // // |
| // // We could have written layout.Pointer<0>(p) instead. If all the types are |
| // // unique you can use either form, but if some types are repeated you must |
| // // use the index form. |
| // double* a = layout.Pointer<double>(p.get()); |
| // |
| // // Obtain the pointer to the array of ints. |
| // // Equivalent to `reinterpret_cast<int*>(p.get() + N * 8)`. |
| // int* b = layout.Pointer<int>(p); |
| // |
| // If we are unable to specify sizes of all fields, we can pass as many sizes as |
| // we can to `Partial()`. In return, it'll allow us to access the fields whose |
| // locations and sizes can be computed from the provided information. |
| // `Partial()` comes in handy when the array sizes are embedded into the |
| // allocation. |
| // |
| // // size_t[0] containing N, size_t[1] containing M, double[N], int[M]. |
| // using L = Layout<size_t, size_t, double, int>; |
| // |
| // unsigned char* Allocate(size_t n, size_t m) { |
| // const L layout(1, 1, n, m); |
| // unsigned char* p = new unsigned char[layout.AllocSize()]; |
| // *layout.Pointer<0>(p) = n; |
| // *layout.Pointer<1>(p) = m; |
| // return p; |
| // } |
| // |
| // void Use(unsigned char* p) { |
| // // First, extract N and M. |
| // // Specify that the first array has only one element. Using `prefix` we |
| // // can access the first two arrays but not more. |
| // constexpr auto prefix = L::Partial(1); |
| // size_t n = *prefix.Pointer<0>(p); |
| // size_t m = *prefix.Pointer<1>(p); |
| // |
| // // Now we can get pointers to the payload. |
| // const L layout(1, 1, n, m); |
| // double* a = layout.Pointer<double>(p); |
| // int* b = layout.Pointer<int>(p); |
| // } |
| // |
| // The layout we used above combines fixed-size with dynamically-sized fields. |
| // This is quite common. Layout is optimized for this use case and attempts to |
| // generate optimal code. To help the compiler do that in more cases, you can |
| // specify the fixed sizes using `WithStaticSizes`. This ensures that all |
| // computations that can be performed at compile time are indeed performed at |
| // compile time. Note that sometimes the `template` keyword is needed. E.g.: |
| // |
| // using SL = L::template WithStaticSizes<1, 1>; |
| // |
| // void Use(unsigned char* p) { |
| // // First, extract N and M. |
| // // Using `prefix` we can access the first three arrays but not more. |
| // // |
| // // More details: The first element always has offset 0. `SL` |
| // // has offsets for the second and third array based on sizes of |
| // // the first and second array, specified via `WithStaticSizes`. |
| // constexpr auto prefix = SL::Partial(); |
| // size_t n = *prefix.Pointer<0>(p); |
| // size_t m = *prefix.Pointer<1>(p); |
| // |
| // // Now we can get a pointer to the final payload. |
| // const SL layout(n, m); |
| // double* a = layout.Pointer<double>(p); |
| // int* b = layout.Pointer<int>(p); |
| // } |
| // |
| // Efficiency tip: The order of fields matters. In `Layout<T1, ..., TN>` try to |
| // ensure that `alignof(T1) >= ... >= alignof(TN)`. This way you'll have no |
| // padding in between arrays. |
| // |
| // You can manually override the alignment of an array by wrapping the type in |
| // `Aligned<T, N>`. `Layout<..., Aligned<T, N>, ...>` has exactly the same API |
| // and behavior as `Layout<..., T, ...>` except that the first element of the |
| // array of `T` is aligned to `N` (the rest of the elements follow without |
| // padding). `N` cannot be less than `alignof(T)`. |
| // |
| // `AllocSize()` and `Pointer()` are the most basic methods for dealing with |
| // memory layouts. Check out the reference or code below to discover more. |
| // |
| // EXAMPLE |
| // |
| // // Immutable move-only string with sizeof equal to sizeof(void*). The |
| // // string size and the characters are kept in the same heap allocation. |
| // class CompactString { |
| // public: |
| // CompactString(const char* s = "") { |
| // const size_t size = strlen(s); |
| // // size_t[1] followed by char[size + 1]. |
| // const L layout(size + 1); |
| // p_.reset(new unsigned char[layout.AllocSize()]); |
| // // If running under ASAN, mark the padding bytes, if any, to catch |
| // // memory errors. |
| // layout.PoisonPadding(p_.get()); |
| // // Store the size in the allocation. |
| // *layout.Pointer<size_t>(p_.get()) = size; |
| // // Store the characters in the allocation. |
| // memcpy(layout.Pointer<char>(p_.get()), s, size + 1); |
| // } |
| // |
| // size_t size() const { |
| // // Equivalent to reinterpret_cast<size_t&>(*p). |
| // return *L::Partial().Pointer<size_t>(p_.get()); |
| // } |
| // |
| // const char* c_str() const { |
| // // Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)). |
| // return L::Partial().Pointer<char>(p_.get()); |
| // } |
| // |
| // private: |
| // // Our heap allocation contains a single size_t followed by an array of |
| // // chars. |
| // using L = Layout<size_t, char>::WithStaticSizes<1>; |
| // std::unique_ptr<unsigned char[]> p_; |
| // }; |
| // |
| // int main() { |
| // CompactString s = "hello"; |
| // assert(s.size() == 5); |
| // assert(strcmp(s.c_str(), "hello") == 0); |
| // } |
| // |
| // DOCUMENTATION |
| // |
| // The interface exported by this file consists of: |
| // - class `Layout<>` and its public members. |
| // - The public members of classes `internal_layout::LayoutWithStaticSizes<>` |
| // and `internal_layout::LayoutImpl<>`. Those classes aren't intended to be |
| // used directly, and their name and template parameter list are internal |
| // implementation details, but the classes themselves provide most of the |
| // functionality in this file. See comments on their members for detailed |
| // documentation. |
| // |
| // `Layout<T1,... Tn>::Partial(count1,..., countm)` (where `m` <= `n`) returns a |
| // `LayoutImpl<>` object. `Layout<T1,..., Tn> layout(count1,..., countn)` |
| // creates a `Layout` object, which exposes the same functionality by inheriting |
| // from `LayoutImpl<>`. |
| |
| #ifndef ABSL_CONTAINER_INTERNAL_LAYOUT_H_ |
| #define ABSL_CONTAINER_INTERNAL_LAYOUT_H_ |
| |
| #include <assert.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <array> |
| #include <string> |
| #include <tuple> |
| #include <type_traits> |
| #include <typeinfo> |
| #include <utility> |
| |
| #include "absl/base/config.h" |
| #include "absl/debugging/internal/demangle.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/types/span.h" |
| #include "absl/utility/utility.h" |
| |
| #ifdef ABSL_HAVE_ADDRESS_SANITIZER |
| #include <sanitizer/asan_interface.h> |
| #endif |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace container_internal { |
| |
| // A type wrapper that instructs `Layout` to use the specific alignment for the |
| // array. `Layout<..., Aligned<T, N>, ...>` has exactly the same API |
| // and behavior as `Layout<..., T, ...>` except that the first element of the |
| // array of `T` is aligned to `N` (the rest of the elements follow without |
| // padding). |
| // |
| // Requires: `N >= alignof(T)` and `N` is a power of 2. |
| template <class T, size_t N> |
| struct Aligned; |
| |
| namespace internal_layout { |
| |
| template <class T> |
| struct NotAligned {}; |
| |
| template <class T, size_t N> |
| struct NotAligned<const Aligned<T, N>> { |
| static_assert(sizeof(T) == 0, "Aligned<T, N> cannot be const-qualified"); |
| }; |
| |
| template <size_t> |
| using IntToSize = size_t; |
| |
| template <class T> |
| struct Type : NotAligned<T> { |
| using type = T; |
| }; |
| |
| template <class T, size_t N> |
| struct Type<Aligned<T, N>> { |
| using type = T; |
| }; |
| |
| template <class T> |
| struct SizeOf : NotAligned<T>, std::integral_constant<size_t, sizeof(T)> {}; |
| |
| template <class T, size_t N> |
| struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {}; |
| |
| // Note: workaround for https://gcc.gnu.org/PR88115 |
| template <class T> |
| struct AlignOf : NotAligned<T> { |
| static constexpr size_t value = alignof(T); |
| }; |
| |
| template <class T, size_t N> |
| struct AlignOf<Aligned<T, N>> { |
| static_assert(N % alignof(T) == 0, |
| "Custom alignment can't be lower than the type's alignment"); |
| static constexpr size_t value = N; |
| }; |
| |
| // Does `Ts...` contain `T`? |
| template <class T, class... Ts> |
| using Contains = absl::disjunction<std::is_same<T, Ts>...>; |
| |
| template <class From, class To> |
| using CopyConst = |
| typename std::conditional<std::is_const<From>::value, const To, To>::type; |
| |
| // Note: We're not qualifying this with absl:: because it doesn't compile under |
| // MSVC. |
| template <class T> |
| using SliceType = Span<T>; |
| |
| // This namespace contains no types. It prevents functions defined in it from |
| // being found by ADL. |
| namespace adl_barrier { |
| |
| template <class Needle, class... Ts> |
| constexpr size_t Find(Needle, Needle, Ts...) { |
| static_assert(!Contains<Needle, Ts...>(), "Duplicate element type"); |
| return 0; |
| } |
| |
| template <class Needle, class T, class... Ts> |
| constexpr size_t Find(Needle, T, Ts...) { |
| return adl_barrier::Find(Needle(), Ts()...) + 1; |
| } |
| |
| constexpr bool IsPow2(size_t n) { return !(n & (n - 1)); } |
| |
| // Returns `q * m` for the smallest `q` such that `q * m >= n`. |
| // Requires: `m` is a power of two. It's enforced by IsLegalElementType below. |
| constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); } |
| |
| constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; } |
| |
| constexpr size_t Max(size_t a) { return a; } |
| |
| template <class... Ts> |
| constexpr size_t Max(size_t a, size_t b, Ts... rest) { |
| return adl_barrier::Max(b < a ? a : b, rest...); |
| } |
| |
| template <class T> |
| std::string TypeName() { |
| std::string out; |
| #ifdef ABSL_INTERNAL_HAS_RTTI |
| absl::StrAppend(&out, "<", |
| absl::debugging_internal::DemangleString(typeid(T).name()), |
| ">"); |
| #endif |
| return out; |
| } |
| |
| } // namespace adl_barrier |
| |
| // Can `T` be a template argument of `Layout`? |
| template <class T> |
| using IsLegalElementType = std::integral_constant< |
| bool, !std::is_reference<T>::value && !std::is_volatile<T>::value && |
| !std::is_reference<typename Type<T>::type>::value && |
| !std::is_volatile<typename Type<T>::type>::value && |
| adl_barrier::IsPow2(AlignOf<T>::value)>; |
| |
| template <class Elements, class StaticSizeSeq, class RuntimeSizeSeq, |
| class SizeSeq, class OffsetSeq> |
| class LayoutImpl; |
| |
| // Public base class of `Layout` and the result type of `Layout::Partial()`. |
| // |
| // `Elements...` contains all template arguments of `Layout` that created this |
| // instance. |
| // |
| // `StaticSizeSeq...` is an index_sequence containing the sizes specified at |
| // compile-time. |
| // |
| // `RuntimeSizeSeq...` is `[0, NumRuntimeSizes)`, where `NumRuntimeSizes` is the |
| // number of arguments passed to `Layout::Partial()` or `Layout::Layout()`. |
| // |
| // `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is `NumRuntimeSizes` plus |
| // the number of sizes in `StaticSizeSeq`. |
| // |
| // `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is |
| // `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we |
| // can compute offsets). |
| template <class... Elements, size_t... StaticSizeSeq, size_t... RuntimeSizeSeq, |
| size_t... SizeSeq, size_t... OffsetSeq> |
| class LayoutImpl< |
| std::tuple<Elements...>, absl::index_sequence<StaticSizeSeq...>, |
| absl::index_sequence<RuntimeSizeSeq...>, absl::index_sequence<SizeSeq...>, |
| absl::index_sequence<OffsetSeq...>> { |
| private: |
| static_assert(sizeof...(Elements) > 0, "At least one field is required"); |
| static_assert(absl::conjunction<IsLegalElementType<Elements>...>::value, |
| "Invalid element type (see IsLegalElementType)"); |
| static_assert(sizeof...(StaticSizeSeq) <= sizeof...(Elements), |
| "Too many static sizes specified"); |
| |
| enum { |
| NumTypes = sizeof...(Elements), |
| NumStaticSizes = sizeof...(StaticSizeSeq), |
| NumRuntimeSizes = sizeof...(RuntimeSizeSeq), |
| NumSizes = sizeof...(SizeSeq), |
| NumOffsets = sizeof...(OffsetSeq), |
| }; |
| |
| // These are guaranteed by `Layout`. |
| static_assert(NumStaticSizes + NumRuntimeSizes == NumSizes, "Internal error"); |
| static_assert(NumSizes <= NumTypes, "Internal error"); |
| static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1), |
| "Internal error"); |
| static_assert(NumTypes > 0, "Internal error"); |
| |
| static constexpr std::array<size_t, sizeof...(StaticSizeSeq)> kStaticSizes = { |
| StaticSizeSeq...}; |
| |
| // Returns the index of `T` in `Elements...`. Results in a compilation error |
| // if `Elements...` doesn't contain exactly one instance of `T`. |
| template <class T> |
| static constexpr size_t ElementIndex() { |
| static_assert(Contains<Type<T>, Type<typename Type<Elements>::type>...>(), |
| "Type not found"); |
| return adl_barrier::Find(Type<T>(), |
| Type<typename Type<Elements>::type>()...); |
| } |
| |
| template <size_t N> |
| using ElementAlignment = |
| AlignOf<typename std::tuple_element<N, std::tuple<Elements...>>::type>; |
| |
| public: |
| // Element types of all arrays packed in a tuple. |
| using ElementTypes = std::tuple<typename Type<Elements>::type...>; |
| |
| // Element type of the Nth array. |
| template <size_t N> |
| using ElementType = typename std::tuple_element<N, ElementTypes>::type; |
| |
| constexpr explicit LayoutImpl(IntToSize<RuntimeSizeSeq>... sizes) |
| : size_{sizes...} {} |
| |
| // Alignment of the layout, equal to the strictest alignment of all elements. |
| // All pointers passed to the methods of layout must be aligned to this value. |
| static constexpr size_t Alignment() { |
| return adl_barrier::Max(AlignOf<Elements>::value...); |
| } |
| |
| // Offset in bytes of the Nth array. |
| // |
| // // int[3], 4 bytes of padding, double[4]. |
| // Layout<int, double> x(3, 4); |
| // assert(x.Offset<0>() == 0); // The ints starts from 0. |
| // assert(x.Offset<1>() == 16); // The doubles starts from 16. |
| // |
| // Requires: `N <= NumSizes && N < sizeof...(Ts)`. |
| template <size_t N> |
| constexpr size_t Offset() const { |
| if constexpr (N == 0) { |
| return 0; |
| } else { |
| static_assert(N < NumOffsets, "Index out of bounds"); |
| return adl_barrier::Align( |
| Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * Size<N - 1>(), |
| ElementAlignment<N>::value); |
| } |
| } |
| |
| // Offset in bytes of the array with the specified element type. There must |
| // be exactly one such array and its zero-based index must be at most |
| // `NumSizes`. |
| // |
| // // int[3], 4 bytes of padding, double[4]. |
| // Layout<int, double> x(3, 4); |
| // assert(x.Offset<int>() == 0); // The ints starts from 0. |
| // assert(x.Offset<double>() == 16); // The doubles starts from 16. |
| template <class T> |
| constexpr size_t Offset() const { |
| return Offset<ElementIndex<T>()>(); |
| } |
| |
| // Offsets in bytes of all arrays for which the offsets are known. |
| constexpr std::array<size_t, NumOffsets> Offsets() const { |
| return {{Offset<OffsetSeq>()...}}; |
| } |
| |
| // The number of elements in the Nth array (zero-based). |
| // |
| // // int[3], 4 bytes of padding, double[4]. |
| // Layout<int, double> x(3, 4); |
| // assert(x.Size<0>() == 3); |
| // assert(x.Size<1>() == 4); |
| // |
| // Requires: `N < NumSizes`. |
| template <size_t N> |
| constexpr size_t Size() const { |
| if constexpr (N < NumStaticSizes) { |
| return kStaticSizes[N]; |
| } else { |
| static_assert(N < NumSizes, "Index out of bounds"); |
| return size_[N - NumStaticSizes]; |
| } |
| } |
| |
| // The number of elements in the array with the specified element type. |
| // There must be exactly one such array and its zero-based index must be |
| // at most `NumSizes`. |
| // |
| // // int[3], 4 bytes of padding, double[4]. |
| // Layout<int, double> x(3, 4); |
| // assert(x.Size<int>() == 3); |
| // assert(x.Size<double>() == 4); |
| template <class T> |
| constexpr size_t Size() const { |
| return Size<ElementIndex<T>()>(); |
| } |
| |
| // The number of elements of all arrays for which they are known. |
| constexpr std::array<size_t, NumSizes> Sizes() const { |
| return {{Size<SizeSeq>()...}}; |
| } |
| |
| // Pointer to the beginning of the Nth array. |
| // |
| // `Char` must be `[const] [signed|unsigned] char`. |
| // |
| // // int[3], 4 bytes of padding, double[4]. |
| // Layout<int, double> x(3, 4); |
| // unsigned char* p = new unsigned char[x.AllocSize()]; |
| // int* ints = x.Pointer<0>(p); |
| // double* doubles = x.Pointer<1>(p); |
| // |
| // Requires: `N <= NumSizes && N < sizeof...(Ts)`. |
| // Requires: `p` is aligned to `Alignment()`. |
| template <size_t N, class Char> |
| CopyConst<Char, ElementType<N>>* Pointer(Char* p) const { |
| using C = typename std::remove_const<Char>::type; |
| static_assert( |
| std::is_same<C, char>() || std::is_same<C, unsigned char>() || |
| std::is_same<C, signed char>(), |
| "The argument must be a pointer to [const] [signed|unsigned] char"); |
| constexpr size_t alignment = Alignment(); |
| (void)alignment; |
| assert(reinterpret_cast<uintptr_t>(p) % alignment == 0); |
| return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>()); |
| } |
| |
| // Pointer to the beginning of the array with the specified element type. |
| // There must be exactly one such array and its zero-based index must be at |
| // most `NumSizes`. |
| // |
| // `Char` must be `[const] [signed|unsigned] char`. |
| // |
| // // int[3], 4 bytes of padding, double[4]. |
| // Layout<int, double> x(3, 4); |
| // unsigned char* p = new unsigned char[x.AllocSize()]; |
| // int* ints = x.Pointer<int>(p); |
| // double* doubles = x.Pointer<double>(p); |
| // |
| // Requires: `p` is aligned to `Alignment()`. |
| template <class T, class Char> |
| CopyConst<Char, T>* Pointer(Char* p) const { |
| return Pointer<ElementIndex<T>()>(p); |
| } |
| |
| // Pointers to all arrays for which pointers are known. |
| // |
| // `Char` must be `[const] [signed|unsigned] char`. |
| // |
| // // int[3], 4 bytes of padding, double[4]. |
| // Layout<int, double> x(3, 4); |
| // unsigned char* p = new unsigned char[x.AllocSize()]; |
| // |
| // int* ints; |
| // double* doubles; |
| // std::tie(ints, doubles) = x.Pointers(p); |
| // |
| // Requires: `p` is aligned to `Alignment()`. |
| template <class Char> |
| auto Pointers(Char* p) const { |
| return std::tuple<CopyConst<Char, ElementType<OffsetSeq>>*...>( |
| Pointer<OffsetSeq>(p)...); |
| } |
| |
| // The Nth array. |
| // |
| // `Char` must be `[const] [signed|unsigned] char`. |
| // |
| // // int[3], 4 bytes of padding, double[4]. |
| // Layout<int, double> x(3, 4); |
| // unsigned char* p = new unsigned char[x.AllocSize()]; |
| // Span<int> ints = x.Slice<0>(p); |
| // Span<double> doubles = x.Slice<1>(p); |
| // |
| // Requires: `N < NumSizes`. |
| // Requires: `p` is aligned to `Alignment()`. |
| template <size_t N, class Char> |
| SliceType<CopyConst<Char, ElementType<N>>> Slice(Char* p) const { |
| return SliceType<CopyConst<Char, ElementType<N>>>(Pointer<N>(p), Size<N>()); |
| } |
| |
| // The array with the specified element type. There must be exactly one |
| // such array and its zero-based index must be less than `NumSizes`. |
| // |
| // `Char` must be `[const] [signed|unsigned] char`. |
| // |
| // // int[3], 4 bytes of padding, double[4]. |
| // Layout<int, double> x(3, 4); |
| // unsigned char* p = new unsigned char[x.AllocSize()]; |
| // Span<int> ints = x.Slice<int>(p); |
| // Span<double> doubles = x.Slice<double>(p); |
| // |
| // Requires: `p` is aligned to `Alignment()`. |
| template <class T, class Char> |
| SliceType<CopyConst<Char, T>> Slice(Char* p) const { |
| return Slice<ElementIndex<T>()>(p); |
| } |
| |
| // All arrays with known sizes. |
| // |
| // `Char` must be `[const] [signed|unsigned] char`. |
| // |
| // // int[3], 4 bytes of padding, double[4]. |
| // Layout<int, double> x(3, 4); |
| // unsigned char* p = new unsigned char[x.AllocSize()]; |
| // |
| // Span<int> ints; |
| // Span<double> doubles; |
| // std::tie(ints, doubles) = x.Slices(p); |
| // |
| // Requires: `p` is aligned to `Alignment()`. |
| // |
| // Note: We mark the parameter as maybe_unused because GCC detects it is not |
| // used when `SizeSeq` is empty [-Werror=unused-but-set-parameter]. |
| template <class Char> |
| auto Slices([[maybe_unused]] Char* p) const { |
| return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>( |
| Slice<SizeSeq>(p)...); |
| } |
| |
| // The size of the allocation that fits all arrays. |
| // |
| // // int[3], 4 bytes of padding, double[4]. |
| // Layout<int, double> x(3, 4); |
| // unsigned char* p = new unsigned char[x.AllocSize()]; // 48 bytes |
| // |
| // Requires: `NumSizes == sizeof...(Ts)`. |
| constexpr size_t AllocSize() const { |
| static_assert(NumTypes == NumSizes, "You must specify sizes of all fields"); |
| return Offset<NumTypes - 1>() + |
| SizeOf<ElementType<NumTypes - 1>>::value * Size<NumTypes - 1>(); |
| } |
| |
| // If built with --config=asan, poisons padding bytes (if any) in the |
| // allocation. The pointer must point to a memory block at least |
| // `AllocSize()` bytes in length. |
| // |
| // `Char` must be `[const] [signed|unsigned] char`. |
| // |
| // Requires: `p` is aligned to `Alignment()`. |
| template <class Char, size_t N = NumOffsets - 1> |
| void PoisonPadding(const Char* p) const { |
| if constexpr (N == 0) { |
| Pointer<0>(p); // verify the requirements on `Char` and `p` |
| } else { |
| static_assert(N < NumOffsets, "Index out of bounds"); |
| (void)p; |
| #ifdef ABSL_HAVE_ADDRESS_SANITIZER |
| PoisonPadding<Char, N - 1>(p); |
| // The `if` is an optimization. It doesn't affect the observable behaviour. |
| if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) { |
| size_t start = |
| Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * Size<N - 1>(); |
| ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start); |
| } |
| #endif |
| } |
| } |
| |
| // Human-readable description of the memory layout. Useful for debugging. |
| // Slow. |
| // |
| // // char[5], 3 bytes of padding, int[3], 4 bytes of padding, followed |
| // // by an unknown number of doubles. |
| // auto x = Layout<char, int, double>::Partial(5, 3); |
| // assert(x.DebugString() == |
| // "@0<char>(1)[5]; @8<int>(4)[3]; @24<double>(8)"); |
| // |
| // Each field is in the following format: @offset<type>(sizeof)[size] (<type> |
| // may be missing depending on the target platform). For example, |
| // @8<int>(4)[3] means that at offset 8 we have an array of ints, where each |
| // int is 4 bytes, and we have 3 of those ints. The size of the last field may |
| // be missing (as in the example above). Only fields with known offsets are |
| // described. Type names may differ across platforms: one compiler might |
| // produce "unsigned*" where another produces "unsigned int *". |
| std::string DebugString() const { |
| const auto offsets = Offsets(); |
| const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>::value...}; |
| const std::string types[] = { |
| adl_barrier::TypeName<ElementType<OffsetSeq>>()...}; |
| std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")"); |
| for (size_t i = 0; i != NumOffsets - 1; ++i) { |
| absl::StrAppend(&res, "[", DebugSize(i), "]; @", offsets[i + 1], |
| types[i + 1], "(", sizes[i + 1], ")"); |
| } |
| // NumSizes is a constant that may be zero. Some compilers cannot see that |
| // inside the if statement "size_[NumSizes - 1]" must be valid. |
| int last = static_cast<int>(NumSizes) - 1; |
| if (NumTypes == NumSizes && last >= 0) { |
| absl::StrAppend(&res, "[", DebugSize(static_cast<size_t>(last)), "]"); |
| } |
| return res; |
| } |
| |
| private: |
| size_t DebugSize(size_t n) const { |
| if (n < NumStaticSizes) { |
| return kStaticSizes[n]; |
| } else { |
| return size_[n - NumStaticSizes]; |
| } |
| } |
| |
| // Arguments of `Layout::Partial()` or `Layout::Layout()`. |
| size_t size_[NumRuntimeSizes > 0 ? NumRuntimeSizes : 1]; |
| }; |
| |
| template <class StaticSizeSeq, size_t NumRuntimeSizes, class... Ts> |
| using LayoutType = LayoutImpl< |
| std::tuple<Ts...>, StaticSizeSeq, |
| absl::make_index_sequence<NumRuntimeSizes>, |
| absl::make_index_sequence<NumRuntimeSizes + StaticSizeSeq::size()>, |
| absl::make_index_sequence<adl_barrier::Min( |
| sizeof...(Ts), NumRuntimeSizes + StaticSizeSeq::size() + 1)>>; |
| |
| template <class StaticSizeSeq, class... Ts> |
| class LayoutWithStaticSizes |
| : public LayoutType<StaticSizeSeq, |
| sizeof...(Ts) - adl_barrier::Min(sizeof...(Ts), |
| StaticSizeSeq::size()), |
| Ts...> { |
| private: |
| using Super = |
| LayoutType<StaticSizeSeq, |
| sizeof...(Ts) - |
| adl_barrier::Min(sizeof...(Ts), StaticSizeSeq::size()), |
| Ts...>; |
| |
| public: |
| // The result type of `Partial()` with `NumSizes` arguments. |
| template <size_t NumSizes> |
| using PartialType = |
| internal_layout::LayoutType<StaticSizeSeq, NumSizes, Ts...>; |
| |
| // `Layout` knows the element types of the arrays we want to lay out in |
| // memory but not the number of elements in each array. |
| // `Partial(size1, ..., sizeN)` allows us to specify the latter. The |
| // resulting immutable object can be used to obtain pointers to the |
| // individual arrays. |
| // |
| // It's allowed to pass fewer array sizes than the number of arrays. E.g., |
| // if all you need is to the offset of the second array, you only need to |
| // pass one argument -- the number of elements in the first array. |
| // |
| // // int[3] followed by 4 bytes of padding and an unknown number of |
| // // doubles. |
| // auto x = Layout<int, double>::Partial(3); |
| // // doubles start at byte 16. |
| // assert(x.Offset<1>() == 16); |
| // |
| // If you know the number of elements in all arrays, you can still call |
| // `Partial()` but it's more convenient to use the constructor of `Layout`. |
| // |
| // Layout<int, double> x(3, 5); |
| // |
| // Note: The sizes of the arrays must be specified in number of elements, |
| // not in bytes. |
| // |
| // Requires: `sizeof...(Sizes) + NumStaticSizes <= sizeof...(Ts)`. |
| // Requires: all arguments are convertible to `size_t`. |
| template <class... Sizes> |
| static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes) { |
| static_assert(sizeof...(Sizes) + StaticSizeSeq::size() <= sizeof...(Ts), |
| ""); |
| return PartialType<sizeof...(Sizes)>( |
| static_cast<size_t>(std::forward<Sizes>(sizes))...); |
| } |
| |
| // Inherit LayoutType's constructor. |
| // |
| // Creates a layout with the sizes of all arrays specified. If you know |
| // only the sizes of the first N arrays (where N can be zero), you can use |
| // `Partial()` defined above. The constructor is essentially equivalent to |
| // calling `Partial()` and passing in all array sizes; the constructor is |
| // provided as a convenient abbreviation. |
| // |
| // Note: The sizes of the arrays must be specified in number of elements, |
| // not in bytes. |
| // |
| // Implementation note: we do this via a `using` declaration instead of |
| // defining our own explicit constructor because the signature of LayoutType's |
| // constructor depends on RuntimeSizeSeq, which we don't have access to here. |
| // If we defined our own constructor here, it would have to use a parameter |
| // pack and then cast the arguments to size_t when calling the superclass |
| // constructor, similar to what Partial() does. But that would suffer from the |
| // same problem that Partial() has, which is that the parameter types are |
| // inferred from the arguments, which may be signed types, which must then be |
| // cast to size_t. This can lead to negative values being silently (i.e. with |
| // no compiler warnings) cast to an unsigned type. Having a constructor with |
| // size_t parameters helps the compiler generate better warnings about |
| // potential bad casts, while avoiding false warnings when positive literal |
| // arguments are used. If an argument is a positive literal integer (e.g. |
| // `1`), the compiler will understand that it can be safely converted to |
| // size_t, and hence not generate a warning. But if a negative literal (e.g. |
| // `-1`) or a variable with signed type is used, then it can generate a |
| // warning about a potentially unsafe implicit cast. It would be great if we |
| // could do this for Partial() too, but unfortunately as of C++23 there seems |
| // to be no way to define a function with a variable number of parameters of a |
| // certain type, a.k.a. homogeneous function parameter packs. So we're forced |
| // to choose between explicitly casting the arguments to size_t, which |
| // suppresses all warnings, even potentially valid ones, or implicitly casting |
| // them to size_t, which generates bogus warnings whenever literal arguments |
| // are used, even if they're positive. |
| using Super::Super; |
| }; |
| |
| } // namespace internal_layout |
| |
| // Descriptor of arrays of various types and sizes laid out in memory one after |
| // another. See the top of the file for documentation. |
| // |
| // Check out the public API of internal_layout::LayoutWithStaticSizes and |
| // internal_layout::LayoutImpl above. Those types are internal to the library |
| // but their methods are public, and they are inherited by `Layout`. |
| template <class... Ts> |
| class Layout : public internal_layout::LayoutWithStaticSizes< |
| absl::make_index_sequence<0>, Ts...> { |
| private: |
| using Super = |
| internal_layout::LayoutWithStaticSizes<absl::make_index_sequence<0>, |
| Ts...>; |
| |
| public: |
| // If you know the sizes of some or all of the arrays at compile time, you can |
| // use `WithStaticSizes` or `WithStaticSizeSequence` to create a `Layout` type |
| // with those sizes baked in. This can help the compiler generate optimal code |
| // for calculating array offsets and AllocSize(). |
| // |
| // Like `Partial()`, the N sizes you specify are for the first N arrays, and |
| // they specify the number of elements in each array, not the number of bytes. |
| template <class StaticSizeSeq> |
| using WithStaticSizeSequence = |
| internal_layout::LayoutWithStaticSizes<StaticSizeSeq, Ts...>; |
| |
| template <size_t... StaticSizes> |
| using WithStaticSizes = |
| WithStaticSizeSequence<std::index_sequence<StaticSizes...>>; |
| |
| // Inherit LayoutWithStaticSizes's constructor, which requires you to specify |
| // all the array sizes. |
| using Super::Super; |
| }; |
| |
| } // namespace container_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_CONTAINER_INTERNAL_LAYOUT_H_ |
| *ðN |
| soong/.intermediates/external/abseil-cpp/absl_strings_str_format_internal_hdrs/gen/my_include_dir/absl/strings/internal/str_format/parser.hßM// Copyright 2020 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ |
| #define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ |
| |
| #include <stddef.h> |
| #include <stdlib.h> |
| |
| #include <cassert> |
| #include <cstring> |
| #include <initializer_list> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/optimization.h" |
| #include "absl/strings/internal/str_format/checker.h" |
| #include "absl/strings/internal/str_format/constexpr_parser.h" |
| #include "absl/strings/internal/str_format/extension.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace str_format_internal { |
| |
| std::string LengthModToString(LengthMod v); |
| |
| const char* ConsumeUnboundConversionNoInline(const char* p, const char* end, |
| UnboundConversion* conv, |
| int* next_arg); |
| |
| // Parse the format string provided in 'src' and pass the identified items into |
| // 'consumer'. |
| // Text runs will be passed by calling |
| // Consumer::Append(string_view); |
| // ConversionItems will be passed by calling |
| // Consumer::ConvertOne(UnboundConversion, string_view); |
| // In the case of ConvertOne, the string_view that is passed is the |
| // portion of the format string corresponding to the conversion, not including |
| // the leading %. On success, it returns true. On failure, it stops and returns |
| // false. |
| template <typename Consumer> |
| bool ParseFormatString(string_view src, Consumer consumer) { |
| int next_arg = 0; |
| const char* p = src.data(); |
| const char* const end = p + src.size(); |
| while (p != end) { |
| const char* percent = |
| static_cast<const char*>(memchr(p, '%', static_cast<size_t>(end - p))); |
| if (!percent) { |
| // We found the last substring. |
| return consumer.Append(string_view(p, static_cast<size_t>(end - p))); |
| } |
| // We found a percent, so push the text run then process the percent. |
| if (ABSL_PREDICT_FALSE(!consumer.Append( |
| string_view(p, static_cast<size_t>(percent - p))))) { |
| return false; |
| } |
| if (ABSL_PREDICT_FALSE(percent + 1 >= end)) return false; |
| |
| auto tag = GetTagForChar(percent[1]); |
| if (tag.is_conv()) { |
| if (ABSL_PREDICT_FALSE(next_arg < 0)) { |
| // This indicates an error in the format string. |
| // The only way to get `next_arg < 0` here is to have a positional |
| // argument first which sets next_arg to -1 and then a non-positional |
| // argument. |
| return false; |
| } |
| p = percent + 2; |
| |
| // Keep this case separate from the one below. |
| // ConvertOne is more efficient when the compiler can see that the `basic` |
| // flag is set. |
| UnboundConversion conv; |
| conv.conv = tag.as_conv(); |
| conv.arg_position = ++next_arg; |
| if (ABSL_PREDICT_FALSE( |
| !consumer.ConvertOne(conv, string_view(percent + 1, 1)))) { |
| return false; |
| } |
| } else if (percent[1] != '%') { |
| UnboundConversion conv; |
| p = ConsumeUnboundConversionNoInline(percent + 1, end, &conv, &next_arg); |
| if (ABSL_PREDICT_FALSE(p == nullptr)) return false; |
| if (ABSL_PREDICT_FALSE(!consumer.ConvertOne( |
| conv, string_view(percent + 1, |
| static_cast<size_t>(p - (percent + 1)))))) { |
| return false; |
| } |
| } else { |
| if (ABSL_PREDICT_FALSE(!consumer.Append("%"))) return false; |
| p = percent + 2; |
| continue; |
| } |
| } |
| return true; |
| } |
| |
| // Always returns true, or fails to compile in a constexpr context if s does not |
| // point to a constexpr char array. |
| constexpr bool EnsureConstexpr(string_view s) { |
| return s.empty() || s[0] == s[0]; |
| } |
| |
| class ParsedFormatBase { |
| public: |
| explicit ParsedFormatBase( |
| string_view format, bool allow_ignored, |
| std::initializer_list<FormatConversionCharSet> convs); |
| |
| ParsedFormatBase(const ParsedFormatBase& other) { *this = other; } |
| |
| ParsedFormatBase(ParsedFormatBase&& other) { *this = std::move(other); } |
| |
| ParsedFormatBase& operator=(const ParsedFormatBase& other) { |
| if (this == &other) return *this; |
| has_error_ = other.has_error_; |
| items_ = other.items_; |
| size_t text_size = items_.empty() ? 0 : items_.back().text_end; |
| data_ = std::make_unique<char[]>(text_size); |
| if (text_size > 0) { |
| memcpy(data_.get(), other.data_.get(), text_size); |
| } |
| return *this; |
| } |
| |
| ParsedFormatBase& operator=(ParsedFormatBase&& other) { |
| if (this == &other) return *this; |
| has_error_ = other.has_error_; |
| data_ = std::move(other.data_); |
| items_ = std::move(other.items_); |
| // Reset the vector to make sure the invariants hold. |
| other.items_.clear(); |
| return *this; |
| } |
| |
| template <typename Consumer> |
| bool ProcessFormat(Consumer consumer) const { |
| const char* const base = data_.get(); |
| string_view text(base, 0); |
| for (const auto& item : items_) { |
| const char* const end = text.data() + text.size(); |
| text = |
| string_view(end, static_cast<size_t>((base + item.text_end) - end)); |
| if (item.is_conversion) { |
| if (!consumer.ConvertOne(item.conv, text)) return false; |
| } else { |
| if (!consumer.Append(text)) return false; |
| } |
| } |
| return !has_error_; |
| } |
| |
| bool has_error() const { return has_error_; } |
| |
| private: |
| // Returns whether the conversions match and if !allow_ignored it verifies |
| // that all conversions are used by the format. |
| bool MatchesConversions( |
| bool allow_ignored, |
| std::initializer_list<FormatConversionCharSet> convs) const; |
| |
| struct ParsedFormatConsumer; |
| |
| struct ConversionItem { |
| bool is_conversion; |
| // Points to the past-the-end location of this element in the data_ array. |
| size_t text_end; |
| UnboundConversion conv; |
| }; |
| |
| bool has_error_; |
| std::unique_ptr<char[]> data_; |
| std::vector<ConversionItem> items_; |
| }; |
| |
| |
| // A value type representing a preparsed format. These can be created, copied |
| // around, and reused to speed up formatting loops. |
| // The user must specify through the template arguments the conversion |
| // characters used in the format. This will be checked at compile time. |
| // |
| // This class uses Conv enum values to specify each argument. |
| // This allows for more flexibility as you can specify multiple possible |
| // conversion characters for each argument. |
| // ParsedFormat<char...> is a simplified alias for when the user only |
| // needs to specify a single conversion character for each argument. |
| // |
| // Example: |
| // // Extended format supports multiple characters per argument: |
| // using MyFormat = ExtendedParsedFormat<Conv::d | Conv::x>; |
| // MyFormat GetFormat(bool use_hex) { |
| // if (use_hex) return MyFormat("foo %x bar"); |
| // return MyFormat("foo %d bar"); |
| // } |
| // // 'format' can be used with any value that supports 'd' and 'x', |
| // // like `int`. |
| // auto format = GetFormat(use_hex); |
| // value = StringF(format, i); |
| // |
| // This class also supports runtime format checking with the ::New() and |
| // ::NewAllowIgnored() factory functions. |
| // This is the only API that allows the user to pass a runtime specified format |
| // string. These factory functions will return NULL if the format does not match |
| // the conversions requested by the user. |
| template <FormatConversionCharSet... C> |
| class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase { |
| public: |
| explicit ExtendedParsedFormat(string_view format) |
| #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
| __attribute__(( |
| enable_if(str_format_internal::EnsureConstexpr(format), |
| "Format string is not constexpr."), |
| enable_if(str_format_internal::ValidFormatImpl<C...>(format), |
| "Format specified does not match the template arguments."))) |
| #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER |
| : ExtendedParsedFormat(format, false) { |
| } |
| |
| // ExtendedParsedFormat factory function. |
| // The user still has to specify the conversion characters, but they will not |
| // be checked at compile time. Instead, it will be checked at runtime. |
| // This delays the checking to runtime, but allows the user to pass |
| // dynamically sourced formats. |
| // It returns NULL if the format does not match the conversion characters. |
| // The user is responsible for checking the return value before using it. |
| // |
| // The 'New' variant will check that all the specified arguments are being |
| // consumed by the format and return NULL if any argument is being ignored. |
| // The 'NewAllowIgnored' variant will not verify this and will allow formats |
| // that ignore arguments. |
| static std::unique_ptr<ExtendedParsedFormat> New(string_view format) { |
| return New(format, false); |
| } |
| static std::unique_ptr<ExtendedParsedFormat> NewAllowIgnored( |
| string_view format) { |
| return New(format, true); |
| } |
| |
| private: |
| static std::unique_ptr<ExtendedParsedFormat> New(string_view format, |
| bool allow_ignored) { |
| std::unique_ptr<ExtendedParsedFormat> conv( |
| new ExtendedParsedFormat(format, allow_ignored)); |
| if (conv->has_error()) return nullptr; |
| return conv; |
| } |
| |
| ExtendedParsedFormat(string_view s, bool allow_ignored) |
| : ParsedFormatBase(s, allow_ignored, {C...}) {} |
| }; |
| } // namespace str_format_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ |
| *£V |
| ¶soong/.intermediates/build/make/tools/ide_query/prober_scripts/cpp/ide_query_proberscript_cc/android_arm_armv7-a-neon/gen/proto/build/make/tools/ide_query/prober_scripts/cpp/foo.pb.hçT// Generated by the protocol buffer compiler. DO NOT EDIT! |
| // NO CHECKED-IN PROTOBUF GENCODE |
| // source: build/make/tools/ide_query/prober_scripts/cpp/foo.proto |
| // Protobuf C++ Version: 6.33.1 |
| |
| #ifndef build_2fmake_2ftools_2fide_5fquery_2fprober_5fscripts_2fcpp_2ffoo_2eproto_2epb_2eh |
| #define build_2fmake_2ftools_2fide_5fquery_2fprober_5fscripts_2fcpp_2ffoo_2eproto_2epb_2eh |
| |
| #include <cstdint> |
| #include <limits> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "google/protobuf/runtime_version.h" |
| #if PROTOBUF_VERSION != 6033001 |
| #error "Protobuf C++ gencode is built with an incompatible version of" |
| #error "Protobuf C++ headers/runtime. See" |
| #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" |
| #endif |
| #include "google/protobuf/io/coded_stream.h" |
| #include "google/protobuf/arena.h" |
| #include "google/protobuf/arenastring.h" |
| #include "google/protobuf/generated_message_tctable_decl.h" |
| #include "google/protobuf/generated_message_util.h" |
| #include "google/protobuf/metadata_lite.h" |
| #include "google/protobuf/message_lite.h" |
| #include "google/protobuf/repeated_field.h" // IWYU pragma: export |
| #include "google/protobuf/extension_set.h" // IWYU pragma: export |
| // @@protoc_insertion_point(includes) |
| |
| // Must be included last. |
| #include "google/protobuf/port_def.inc" |
| |
| #define PROTOBUF_INTERNAL_EXPORT_build_2fmake_2ftools_2fide_5fquery_2fprober_5fscripts_2fcpp_2ffoo_2eproto |
| |
| namespace google { |
| namespace protobuf { |
| namespace internal { |
| template <typename T> |
| ::absl::string_view GetAnyMessageName(); |
| } // namespace internal |
| } // namespace protobuf |
| } // namespace google |
| |
| // Internal implementation detail -- do not use these members. |
| struct TableStruct_build_2fmake_2ftools_2fide_5fquery_2fprober_5fscripts_2fcpp_2ffoo_2eproto { |
| static const ::uint32_t offsets[]; |
| }; |
| namespace ide_query { |
| namespace prober_scripts { |
| class ProtoMsg; |
| struct ProtoMsgDefaultTypeInternal; |
| extern ProtoMsgDefaultTypeInternal _ProtoMsg_default_instance_; |
| extern const ::google::protobuf::internal::ClassDataLite<34> ProtoMsg_class_data_; |
| } // namespace prober_scripts |
| } // namespace ide_query |
| namespace google { |
| namespace protobuf { |
| } // namespace protobuf |
| } // namespace google |
| |
| namespace ide_query { |
| namespace prober_scripts { |
| |
| // =================================================================== |
| |
| |
| // ------------------------------------------------------------------- |
| |
| class ProtoMsg final : public ::google::protobuf::MessageLite |
| /* @@protoc_insertion_point(class_definition:ide_query.prober_scripts.ProtoMsg) */ { |
| public: |
| inline ProtoMsg() : ProtoMsg(nullptr) {} |
| ~ProtoMsg() PROTOBUF_FINAL; |
| |
| #if defined(PROTOBUF_CUSTOM_VTABLE) |
| void operator delete(ProtoMsg* PROTOBUF_NONNULL msg, ::std::destroying_delete_t) { |
| SharedDtor(*msg); |
| ::google::protobuf::internal::SizedDelete(msg, sizeof(ProtoMsg)); |
| } |
| #endif |
| |
| template <typename = void> |
| explicit PROTOBUF_CONSTEXPR ProtoMsg(::google::protobuf::internal::ConstantInitialized); |
| |
| inline ProtoMsg(const ProtoMsg& from) : ProtoMsg(nullptr, from) {} |
| inline ProtoMsg(ProtoMsg&& from) noexcept |
| : ProtoMsg(nullptr, ::std::move(from)) {} |
| inline ProtoMsg& operator=(const ProtoMsg& from) { |
| CopyFrom(from); |
| return *this; |
| } |
| inline ProtoMsg& operator=(ProtoMsg&& from) noexcept { |
| if (this == &from) return *this; |
| if (::google::protobuf::internal::CanMoveWithInternalSwap(GetArena(), from.GetArena())) { |
| InternalSwap(&from); |
| } else { |
| CopyFrom(from); |
| } |
| return *this; |
| } |
| |
| inline const ::std::string& unknown_fields() const |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return _internal_metadata_.unknown_fields<::std::string>(::google::protobuf::internal::GetEmptyString); |
| } |
| inline ::std::string* PROTOBUF_NONNULL mutable_unknown_fields() |
| ABSL_ATTRIBUTE_LIFETIME_BOUND { |
| return _internal_metadata_.mutable_unknown_fields<::std::string>(); |
| } |
| |
| static const ProtoMsg& default_instance() { |
| return *reinterpret_cast<const ProtoMsg*>( |
| &_ProtoMsg_default_instance_); |
| } |
| static constexpr int kIndexInFileMessages = 0; |
| friend void swap(ProtoMsg& a, ProtoMsg& b) { a.Swap(&b); } |
| inline void Swap(ProtoMsg* PROTOBUF_NONNULL other) { |
| if (other == this) return; |
| if (::google::protobuf::internal::CanUseInternalSwap(GetArena(), other->GetArena())) { |
| InternalSwap(other); |
| } else { |
| ::google::protobuf::internal::GenericSwap(this, other); |
| } |
| } |
| void UnsafeArenaSwap(ProtoMsg* PROTOBUF_NONNULL other) { |
| if (other == this) return; |
| ABSL_DCHECK(GetArena() == other->GetArena()); |
| InternalSwap(other); |
| } |
| |
| // implements Message ---------------------------------------------- |
| |
| ProtoMsg* PROTOBUF_NONNULL New(::google::protobuf::Arena* PROTOBUF_NULLABLE arena = nullptr) const { |
| return ::google::protobuf::MessageLite::DefaultConstruct<ProtoMsg>(arena); |
| } |
| void CopyFrom(const ProtoMsg& from); |
| void MergeFrom(const ProtoMsg& from) { ProtoMsg::MergeImpl(*this, from); } |
| |
| private: |
| static void MergeImpl(::google::protobuf::MessageLite& to_msg, |
| const ::google::protobuf::MessageLite& from_msg); |
| |
| public: |
| bool IsInitialized() const { |
| return true; |
| } |
| ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL; |
| #if defined(PROTOBUF_CUSTOM_VTABLE) |
| private: |
| static ::size_t ByteSizeLong(const ::google::protobuf::MessageLite& msg); |
| static ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( |
| const ::google::protobuf::MessageLite& msg, ::uint8_t* PROTOBUF_NONNULL target, |
| ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream); |
| |
| public: |
| ::size_t ByteSizeLong() const { return ByteSizeLong(*this); } |
| ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( |
| ::uint8_t* PROTOBUF_NONNULL target, |
| ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const { |
| return _InternalSerialize(*this, target, stream); |
| } |
| #else // PROTOBUF_CUSTOM_VTABLE |
| ::size_t ByteSizeLong() const final; |
| ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( |
| ::uint8_t* PROTOBUF_NONNULL target, |
| ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const final; |
| #endif // PROTOBUF_CUSTOM_VTABLE |
| int GetCachedSize() const { return _impl_._cached_size_.Get(); } |
| |
| private: |
| void SharedCtor(::google::protobuf::Arena* PROTOBUF_NULLABLE arena); |
| static void SharedDtor(MessageLite& self); |
| void InternalSwap(ProtoMsg* PROTOBUF_NONNULL other); |
| private: |
| template <typename T> |
| friend ::absl::string_view(::google::protobuf::internal::GetAnyMessageName)(); |
| static ::absl::string_view FullMessageName() { return "ide_query.prober_scripts.ProtoMsg"; } |
| |
| explicit ProtoMsg(::google::protobuf::Arena* PROTOBUF_NULLABLE arena); |
| ProtoMsg(::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const ProtoMsg& from); |
| ProtoMsg( |
| ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, ProtoMsg&& from) noexcept |
| : ProtoMsg(arena) { |
| *this = ::std::move(from); |
| } |
| const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL GetClassData() const PROTOBUF_FINAL; |
| static void* PROTOBUF_NONNULL PlacementNew_( |
| const void* PROTOBUF_NONNULL, void* PROTOBUF_NONNULL mem, |
| ::google::protobuf::Arena* PROTOBUF_NULLABLE arena); |
| static constexpr auto InternalNewImpl_(); |
| |
| public: |
| static constexpr auto InternalGenerateClassData_(); |
| |
| // nested types ---------------------------------------------------- |
| |
| // accessors ------------------------------------------------------- |
| enum : int { |
| kSomeFieldFieldNumber = 1, |
| }; |
| // int64 some_field = 1; |
| void clear_some_field() ; |
| ::int64_t some_field() const; |
| void set_some_field(::int64_t value); |
| |
| private: |
| ::int64_t _internal_some_field() const; |
| void _internal_set_some_field(::int64_t value); |
| |
| public: |
| // @@protoc_insertion_point(class_scope:ide_query.prober_scripts.ProtoMsg) |
| private: |
| class _Internal; |
| friend class ::google::protobuf::internal::TcParser; |
| static const ::google::protobuf::internal::TcParseTable<0, 1, |
| 0, 0, |
| 2> |
| _table_; |
| |
| friend class ::google::protobuf::MessageLite; |
| friend class ::google::protobuf::Arena; |
| template <typename T> |
| friend class ::google::protobuf::Arena::InternalHelper; |
| using InternalArenaConstructable_ = void; |
| using DestructorSkippable_ = void; |
| struct Impl_ { |
| inline explicit constexpr Impl_(::google::protobuf::internal::ConstantInitialized) noexcept; |
| inline explicit Impl_( |
| ::google::protobuf::internal::InternalVisibility visibility, |
| ::google::protobuf::Arena* PROTOBUF_NULLABLE arena); |
| inline explicit Impl_( |
| ::google::protobuf::internal::InternalVisibility visibility, |
| ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const Impl_& from, |
| const ProtoMsg& from_msg); |
| ::google::protobuf::internal::HasBits<1> _has_bits_; |
| ::google::protobuf::internal::CachedSize _cached_size_; |
| ::int64_t some_field_; |
| PROTOBUF_TSAN_DECLARE_MEMBER |
| }; |
| union { Impl_ _impl_; }; |
| friend struct ::TableStruct_build_2fmake_2ftools_2fide_5fquery_2fprober_5fscripts_2fcpp_2ffoo_2eproto; |
| }; |
| |
| extern const ::google::protobuf::internal::ClassDataLite<34> ProtoMsg_class_data_; |
| |
| // =================================================================== |
| |
| |
| |
| |
| // =================================================================== |
| |
| |
| #ifdef __GNUC__ |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic ignored "-Wstrict-aliasing" |
| #endif // __GNUC__ |
| // ------------------------------------------------------------------- |
| |
| // ProtoMsg |
| |
| // int64 some_field = 1; |
| inline void ProtoMsg::clear_some_field() { |
| ::google::protobuf::internal::TSanWrite(&_impl_); |
| _impl_.some_field_ = ::int64_t{0}; |
| ClearHasBit(_impl_._has_bits_[0], |
| 0x00000001U); |
| } |
| inline ::int64_t ProtoMsg::some_field() const { |
| // @@protoc_insertion_point(field_get:ide_query.prober_scripts.ProtoMsg.some_field) |
| return _internal_some_field(); |
| } |
| inline void ProtoMsg::set_some_field(::int64_t value) { |
| _internal_set_some_field(value); |
| SetHasBit(_impl_._has_bits_[0], 0x00000001U); |
| // @@protoc_insertion_point(field_set:ide_query.prober_scripts.ProtoMsg.some_field) |
| } |
| inline ::int64_t ProtoMsg::_internal_some_field() const { |
| ::google::protobuf::internal::TSanRead(&_impl_); |
| return _impl_.some_field_; |
| } |
| inline void ProtoMsg::_internal_set_some_field(::int64_t value) { |
| ::google::protobuf::internal::TSanWrite(&_impl_); |
| _impl_.some_field_ = value; |
| } |
| |
| #ifdef __GNUC__ |
| #pragma GCC diagnostic pop |
| #endif // __GNUC__ |
| |
| // @@protoc_insertion_point(namespace_scope) |
| } // namespace prober_scripts |
| } // namespace ide_query |
| |
| |
| // @@protoc_insertion_point(global_scope) |
| |
| #include "google/protobuf/port_undef.inc" |
| |
| #endif // build_2fmake_2ftools_2fide_5fquery_2fprober_5fscripts_2fcpp_2ffoo_2eproto_2epb_2eh |
| *¹Ã |
| soong/.intermediates/external/abseil-cpp/absl_strings_cord_internal_hdrs/gen/my_include_dir/absl/strings/internal/cord_rep_btree.h°Â// 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_STRINGS_INTERNAL_CORD_REP_BTREE_H_ |
| #define ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_H_ |
| |
| #include <cassert> |
| #include <cstdint> |
| #include <iosfwd> |
| |
| #include "absl/base/config.h" |
| #include "absl/base/internal/raw_logging.h" |
| #include "absl/base/optimization.h" |
| #include "absl/strings/internal/cord_data_edge.h" |
| #include "absl/strings/internal/cord_internal.h" |
| #include "absl/strings/internal/cord_rep_flat.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/types/span.h" |
| |
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace cord_internal { |
| |
| // `SetCordBtreeExhaustiveValidation()` can be set to force exhaustive |
| // validation in debug assertions, and code that calls `IsValid()` |
| // explicitly. By default, assertions should be relatively cheap and |
| // AssertValid() can easily lead to O(n^2) complexity as recursive / full tree |
| // validation is O(n). |
| void SetCordBtreeExhaustiveValidation(bool do_exaustive_validation); |
| bool IsCordBtreeExhaustiveValidationEnabled(); |
| |
| class CordRepBtreeNavigator; |
| |
| // CordRepBtree is as the name implies a btree implementation of a Cordrep tree. |
| // Data is stored at the leaf level only, non leaf nodes contain down pointers |
| // only. Allowed types of data edges are FLAT, EXTERNAL and SUBSTRINGs of FLAT |
| // or EXTERNAL nodes. The implementation allows for data to be added to either |
| // end of the tree only, it does not provide any 'insert' logic. This has the |
| // benefit that we can expect good fill ratios: all nodes except the outer |
| // 'legs' will have 100% fill ratios for trees built using Append/Prepend |
| // methods. Merged trees will typically have a fill ratio well above 50% as in a |
| // similar fashion, one side of the merged tree will typically have a 100% fill |
| // ratio, and the 'open' end will average 50%. All operations are O(log(n)) or |
| // better, and the tree never needs balancing. |
| // |
| // All methods accepting a CordRep* or CordRepBtree* adopt a reference on that |
| // input unless explicitly stated otherwise. All functions returning a CordRep* |
| // or CordRepBtree* instance transfer a reference back to the caller. |
| // Simplified, callers both 'donate' and 'consume' a reference count on each |
| // call, simplifying the API. An example of building a tree: |
| // |
| // CordRepBtree* tree = CordRepBtree::Create(MakeFlat("Hello")); |
| // tree = CordRepBtree::Append(tree, MakeFlat("world")); |
| // |
| // In the above example, all inputs are consumed, making each call affecting |
| // `tree` reference count neutral. The returned `tree` value can be different |
| // from the input if the input is shared with other threads, or if the tree |
| // grows in height, but callers typically never have to concern themselves with |
| // that and trust that all methods DTRT at all times. |
| class CordRepBtree : public CordRep { |
| public: |
| // EdgeType identifies `front` and `back` enum values. |
| // Various implementations in CordRepBtree such as `Add` and `Edge` are |
| // generic and templated on operating on either of the boundary edges. |
| // For more information on the possible edges contained in a CordRepBtree |
| // instance see the documentation for `edges_`. |
| enum class EdgeType { kFront, kBack }; |
| |
| // Convenience constants into `EdgeType` |
| static constexpr EdgeType kFront = EdgeType::kFront; |
| static constexpr EdgeType kBack = EdgeType::kBack; |
| |
| // Maximum number of edges: based on experiments and performance data, we can |
| // pick suitable values resulting in optimum cacheline aligned values. The |
| // preferred values are based on 64-bit systems where we aim to align this |
| // class onto 64 bytes, i.e.: 6 = 64 bytes, 14 = 128 bytes, etc. |
| // TODO(b/192061034): experiment with alternative sizes. |
| static constexpr size_t kMaxCapacity = 6; |
| |
| // Reasonable maximum height of the btree. We can expect a fill ratio of at |
| // least 50%: trees are always expanded at the front or back. Concatenating |
| // trees will then typically fold at the top most node, where the lower nodes |
| // are at least at capacity on one side of joined inputs. At a lower fill |
| // rate of 4 edges per node, we have capacity for ~16 million leaf nodes. |
| // We will fail / abort if an application ever exceeds this height, which |
| // should be extremely rare (near impossible) and be an indication of an |
| // application error: we do not assume it reasonable for any application to |
| // operate correctly with such monster trees. |
| // Another compelling reason for the number `12` is that any contextual stack |
| // required for navigation or insertion requires 12 words and 12 bytes, which |
| // fits inside 2 cache lines with some room to spare, and is reasonable as a |
| // local stack variable compared to Cord's current near 400 bytes stack use. |
| // The maximum `height` value of a node is then `kMaxDepth - 1` as node height |
| // values start with a value of 0 for leaf nodes. |
| static constexpr size_t kMaxDepth = 12; |
| // See comments on height() for why this is an int and not a size_t. |
| static constexpr int kMaxHeight = static_cast<int>(kMaxDepth - 1); |
| |
| // `Action` defines the action for unwinding changes done at the btree's leaf |
| // level that need to be propagated up to the parent node(s). Each operation |
| // on a node has an effect / action defined as follows: |
| // - kSelf |
| // The operation (add / update, etc) was performed directly on the node as |
| // the node is private to the current thread (i.e.: not shared directly or |
| // indirectly through a refcount > 1). Changes can be propagated directly to |
| // all parent nodes as all parent nodes are also then private to the current |
| // thread. |
| // - kCopied |
| // The operation (add / update, etc) was performed on a copy of the original |
| // node, as the node is (potentially) directly or indirectly shared with |
| // other threads. Changes need to be propagated into the parent nodes where |
| // the old down pointer must be unreffed and replaced with this new copy. |
| // Such changes to parent nodes may themselves require a copy if the parent |
| // node is also shared. A kCopied action can propagate all the way to the |
| // top node where we then must unref the `tree` input provided by the |
| // caller, and return the new copy. |
| // - kPopped |
| // The operation (typically add) could not be satisfied due to insufficient |
| // capacity in the targeted node, and a new 'leg' was created that needs to |
| // be added into the parent node. For example, adding a FLAT inside a leaf |
| // node that is at capacity will create a new leaf node containing that |
| // FLAT, that needs to be 'popped' up the btree. Such 'pop' actions can |
| // cascade up the tree if parent nodes are also at capacity. A 'Popped' |
| // action propagating all the way to the top of the tree will result in |
| // the tree becoming one level higher than the current tree through a final |
| // `CordRepBtree::New(tree, popped)` call, resulting in a new top node |
| // referencing the old tree and the new (fully popped upwards) 'leg'. |
| enum Action { kSelf, kCopied, kPopped }; |
| |
| // Result of an operation on a node. See the `Action` enum for details. |
| struct OpResult { |
| CordRepBtree* tree; |
| Action action; |
| }; |
| |
| // Return value of the CopyPrefix and CopySuffix methods which can |
| // return a node or data edge at any height inside the tree. |
| // A height of 0 defines the lowest (leaf) node, a height of -1 identifies |
| // `edge` as being a plain data node: EXTERNAL / FLAT or SUBSTRING thereof. |
| struct CopyResult { |
| CordRep* edge; |
| int height; |
| }; |
| |
| // Logical position inside a node: |
| // - index: index of the edge. |
| // - n: size or offset value depending on context. |
| struct Position { |
| size_t index; |
| size_t n; |
| }; |
| |
| // Creates a btree from the given input. Adopts a ref of `rep`. |
| // If the input `rep` is itself a btree, i.e., `IsBtree()`, then this |
| // function immediately returns `rep->btree()`. If the input is a valid data |
| // edge (see IsDataEdge()), then a new leaf node is returned containing `rep` |
| // as the sole data edge. Else, the input is assumed to be a (legacy) concat |
| // tree, and the input is consumed and transformed into a btree(). |
| static CordRepBtree* Create(CordRep* rep); |
| |
| // Destroys the provided tree. Should only be called by cord internal API's, |
| // typically after a ref_count.Decrement() on the last reference count. |
| static void Destroy(CordRepBtree* tree); |
| |
| // Destruction |
| static void Delete(CordRepBtree* tree) { delete tree; } |
| |
| // Use CordRep::Unref() as we overload for absl::Span<CordRep* const>. |
| using CordRep::Unref; |
| |
| // Unrefs all edges in `edges` which are assumed to be 'likely one'. |
| static void Unref(absl::Span<CordRep* const> edges); |
| |
| // Appends / Prepends an existing CordRep instance to this tree. |
| // The below methods accept three types of input: |
| // 1) `rep` is a data node (See `IsDataNode` for valid data edges). |
| // `rep` is appended or prepended to this tree 'as is'. |
| // 2) `rep` is a BTREE. |
| // `rep` is merged into `tree` respecting the Append/Prepend order. |
| // 3) `rep` is some other (legacy) type. |
| // `rep` is converted in place and added to `tree` |
| // Requires `tree` and `rep` to be not null. |
| static CordRepBtree* Append(CordRepBtree* tree, CordRep* rep); |
| static CordRepBtree* Prepend(CordRepBtree* tree, CordRep* rep); |
| |
| // Append/Prepend the data in `data` to this tree. |
| // The `extra` parameter defines how much extra capacity should be allocated |
| // for any additional FLAT being allocated. This is an optimization hint from |
| // the caller. For example, a caller may need to add 2 string_views of data |
| // "abc" and "defghi" which are not consecutive. The caller can in this case |
| // invoke `AddData(tree, "abc", 6)`, and any newly added flat is allocated |
| // where possible with at least 6 bytes of extra capacity beyond `length`. |
| // This helps avoiding data getting fragmented over multiple flats. |
| // There is no limit on the size of `data`. If `data` can not be stored inside |
| // a single flat, then the function will iteratively add flats until all data |
| // has been consumed and appended or prepended to the tree. |
| static CordRepBtree* Append(CordRepBtree* tree, string_view data, |
| size_t extra = 0); |
| static CordRepBtree* Prepend(CordRepBtree* tree, string_view data, |
| size_t extra = 0); |
| |
| // Returns a new tree, containing `n` bytes of data from this instance |
| // starting at offset `offset`. Where possible, the returned tree shares |
| // (re-uses) data edges and nodes with this instance to minimize the |
| // combined memory footprint of both trees. |
| // Requires `offset + n <= length`. Returns `nullptr` if `n` is zero. |
| CordRep* SubTree(size_t offset, size_t n); |
| |
| // Removes `n` trailing bytes from `tree`, and returns the resulting tree |
| // or data edge. Returns `tree` if n is zero, and nullptr if n == length. |
| // This function is logically identical to: |
| // result = tree->SubTree(0, tree->length - n); |
| // Unref(tree); |
| // return result; |
| // However, the actual implementation will as much as possible perform 'in |
| // place' modifications on the tree on all nodes and edges that are mutable. |
| // For example, in a fully privately owned tree with the last edge being a |
| // flat of length 12, RemoveSuffix(1) will simply set the length of that data |
| // edge to 11, and reduce the length of all nodes on the edge path by 1. |
| static CordRep* RemoveSuffix(CordRepBtree* tree, size_t n); |
| |
| // Returns the character at the given offset. |
| char GetCharacter(size_t offset) const; |
| |
| // Returns true if this node holds a single data edge, and if so, sets |
| // `fragment` to reference the contained data. `fragment` is an optional |
| // output parameter and allowed to be null. |
| bool IsFlat(absl::string_view* fragment) const; |
| |
| // Returns true if the data of `n` bytes starting at offset `offset` |
| // is contained in a single data edge, and if so, sets fragment to reference |
| // the contained data. `fragment` is an optional output parameter and allowed |
| // to be null. |
| bool IsFlat(size_t offset, size_t n, absl::string_view* fragment) const; |
| |
| // Returns a span (mutable range of bytes) of up to `size` bytes into the |
| // last FLAT data edge inside this tree under the following conditions: |
| // - none of the nodes down into the FLAT node are shared. |
| // - the last data edge in this tree is a non-shared FLAT. |
| // - the referenced FLAT has additional capacity available. |
| // If all these conditions are met, a non-empty span is returned, and the |
| // length of the flat node and involved tree nodes have been increased by |
| // `span.length()`. The caller is responsible for immediately assigning values |
| // to all uninitialized data reference by the returned span. |
| // Requires `this->refcount.IsOne()`: this function forces the caller to do |
| // this fast path check on the top level node, as this is the most commonly |
| // shared node of a cord tree. |
| Span<char> GetAppendBuffer(size_t size); |
| |
| // Extracts the right-most data edge from this tree iff: |
| // - the tree and all internal edges to the right-most node are not shared. |
| // - the right-most node is a FLAT node and not shared. |
| // - the right-most node has at least the desired extra capacity. |
| // |
| // Returns {tree, nullptr} if any of the above conditions are not met. |
| // This method effectively removes data from the tree. The intent of this |
| // method is to allow applications appending small string data to use |
| // pre-existing capacity, and add the modified rep back to the tree. |
| // |
| // Simplified such code would look similar to this: |
| // void MyTreeBuilder::Append(string_view data) { |
| // ExtractResult result = CordRepBtree::ExtractAppendBuffer(tree_, 1); |
| // if (CordRep* rep = result.extracted) { |
| // size_t available = rep->Capacity() - rep->length; |
| // size_t n = std::min(data.size(), n); |
| // memcpy(rep->Data(), data.data(), n); |
| // rep->length += n; |
| // data.remove_prefix(n); |
| // if (!result.tree->IsBtree()) { |
| // tree_ = CordRepBtree::Create(result.tree); |
| // } |
| // tree_ = CordRepBtree::Append(tree_, rep); |
| // } |
| // ... |
| // // Remaining edge in `result.tree`. |
| // } |
| static ExtractResult ExtractAppendBuffer(CordRepBtree* tree, |
| size_t extra_capacity = 1); |
| |
| // Returns the `height` of the tree. The height of a tree is limited to |
| // kMaxHeight. `height` is implemented as an `int` as in some places we |
| // use negative (-1) values for 'data edges'. |
| int height() const { return static_cast<int>(storage[0]); } |
| |
| // Properties: begin, back, end, front/back boundary indexes. |
| size_t begin() const { return static_cast<size_t>(storage[1]); } |
| size_t back() const { return static_cast<size_t>(storage[2]) - 1; } |
| size_t end() const { return static_cast<size_t>(storage[2]); } |
| size_t index(EdgeType edge) const { |
| return edge == kFront ? begin() : back(); |
| } |
| |
| // Properties: size and capacity. |
| // `capacity` contains the current capacity of this instance, where |
| // `kMaxCapacity` contains the maximum capacity of a btree node. |
| // For now, `capacity` and `kMaxCapacity` return the same value, but this may |
| // change in the future if we see benefit in dynamically sizing 'small' nodes |
| // to 'large' nodes for large data trees. |
| size_t size() const { return end() - begin(); } |
| size_t capacity() const { return kMaxCapacity; } |
| |
| // Edge access |
| inline CordRep* Edge(size_t index) const; |
| inline CordRep* Edge(EdgeType edge_type) const; |
| inline absl::Span<CordRep* const> Edges() const; |
| inline absl::Span<CordRep* const> Edges(size_t begin, size_t end) const; |
| |
| // Returns reference to the data edge at `index`. |
| // Requires this instance to be a leaf node, and `index` to be valid index. |
| inline absl::string_view Data(size_t index) const; |
| |
| // Diagnostics: returns true if `tree` is valid and internally consistent. |
| // If `shallow` is false, then the provided top level node and all child nodes |
| // below it are recursively checked. If `shallow` is true, only the provided |
| // node in `tree` and the cumulative length, type and height of the direct |
| // child nodes of `tree` are checked. The value of `shallow` is ignored if the |
| // internal `cord_btree_exhaustive_validation` diagnostics variable is true, |
| // in which case the performed validations works as if `shallow` were false. |
| // This function is intended for debugging and testing purposes only. |
| static bool IsValid(const CordRepBtree* tree, bool shallow = false); |
| |
| // Diagnostics: asserts that the provided tree is valid. |
| // `AssertValid()` performs a shallow validation by default. `shallow` can be |
| // set to false in which case an exhaustive validation is performed. This |
| // function is implemented in terms of calling `IsValid()` and asserting the |
| // return value to be true. See `IsValid()` for more information. |
| // This function is intended for debugging and testing purposes only. |
| static CordRepBtree* AssertValid(CordRepBtree* tree, bool shallow = true); |
| static const CordRepBtree* AssertValid(const CordRepBtree* tree, |
| bool shallow = true); |
| |
| // Diagnostics: dump the contents of this tree to `stream`. |
| // This function is intended for debugging and testing purposes only. |
| static void Dump(const CordRep* rep, std::ostream& stream); |
| static void Dump(const CordRep* rep, absl::string_view label, |
| std::ostream& stream); |
| static void Dump(const CordRep* rep, absl::string_view label, |
| bool include_contents, std::ostream& stream); |
| |
| // Adds the edge `edge` to this node if possible. `owned` indicates if the |
| // current node is potentially shared or not with other threads. Returns: |
| // - {kSelf, <this>} |
| // The edge was directly added to this node. |
| // - {kCopied, <node>} |
| // The edge was added to a copy of this node. |
| // - {kPopped, New(edge, height())} |
| // A new leg with the edge was created as this node has no extra capacity. |
| template <EdgeType edge_type> |
| inline OpResult AddEdge(bool owned, CordRep* edge, size_t delta); |
| |
| // Replaces the front or back edge with the provided new edge. Returns: |
| // - {kSelf, <this>} |
| // The edge was directly set in this node. The old edge is unreffed. |
| // - {kCopied, <node>} |
| // A copy of this node was created with the new edge value. |
| // In both cases, the function adopts a reference on `edge`. |
| template <EdgeType edge_type> |
| OpResult SetEdge(bool owned, CordRep* edge, size_t delta); |
| |
| // Creates a new empty node at the specified height. |
| static CordRepBtree* New(int height = 0); |
| |
| // Creates a new node containing `rep`, with the height being computed |
| // automatically based on the type of `rep`. |
| static CordRepBtree* New(CordRep* rep); |
| |
| // Creates a new node containing both `front` and `back` at height |
| // `front.height() + 1`. Requires `back.height() == front.height()`. |
| static CordRepBtree* New(CordRepBtree* front, CordRepBtree* back); |
| |
| // Creates a fully balanced tree from the provided tree by rebuilding a new |
| // tree from all data edges in the input. This function is automatically |
| // invoked internally when the tree exceeds the maximum height. |
| static CordRepBtree* Rebuild(CordRepBtree* tree); |
| |
| private: |
| CordRepBtree() = default; |
| ~CordRepBtree() = default; |
| |
| // Initializes the main properties `tag`, `begin`, `end`, `height`. |
| inline void InitInstance(int height, size_t begin = 0, size_t end = 0); |
| |
| // Direct property access begin / end |
| void set_begin(size_t begin) { storage[1] = static_cast<uint8_t>(begin); } |
| void set_end(size_t end) { storage[2] = static_cast<uint8_t>(end); } |
| |
| // Decreases the value of `begin` by `n`, and returns the new value. Notice |
| // how this returns the new value unlike atomic::fetch_add which returns the |
| // old value. This is because this is used to prepend edges at 'begin - 1'. |
| size_t sub_fetch_begin(size_t n) { |
| storage[1] -= static_cast<uint8_t>(n); |
| return storage[1]; |
| } |
| |
| // Increases the value of `end` by `n`, and returns the previous value. This |
| // function is typically used to append edges at 'end'. |
| size_t fetch_add_end(size_t n) { |
| const uint8_t current = storage[2]; |
| storage[2] = static_cast<uint8_t>(current + n); |
| return current; |
| } |
| |
| // Returns the index of the last edge starting on, or before `offset`, with |
| // `n` containing the relative offset of `offset` inside that edge. |
| // Requires `offset` < length. |
| Position IndexOf(size_t offset) const; |
| |
| // Returns the index of the last edge starting before `offset`, with `n` |
| // containing the relative offset of `offset` inside that edge. |
| // This function is useful to find the edges for some span of bytes ending at |
| // `offset` (i.e., `n` bytes). For example: |
| // |
| // Position pos = IndexBefore(n) |
| // edges = Edges(begin(), pos.index) // All full edges (may be empty) |
| // last = Sub(Edge(pos.index), 0, pos.n) // Last partial edge (may be empty) |
| // |
| // Requires 0 < `offset` <= length. |
| Position IndexBefore(size_t offset) const; |
| |
| // Returns the index of the edge ending at (or on) length `length`, and the |
| // number of bytes inside that edge up to `length`. For example, if we have a |
| // Node with 2 edges, one of 10 and one of 20 long, then IndexOfLength(27) |
| // will return {1, 17}, and IndexOfLength(10) will return {0, 10}. |
| Position IndexOfLength(size_t n) const; |
| |
| // Identical to the above function except starting from the position `front`. |
| // This function is equivalent to `IndexBefore(front.n + offset)`, with |
| // the difference that this function is optimized to start at `front.index`. |
| Position IndexBefore(Position front, size_t offset) const; |
| |
| // Returns the index of the edge directly beyond the edge containing offset |
| // `offset`, with `n` containing the distance of that edge from `offset`. |
| // This function is useful for iteratively finding suffix nodes and remaining |
| // partial bytes in left-most suffix nodes as for example in CopySuffix. |
| // Requires `offset` < length. |
| Position IndexBeyond(size_t offset) const; |
| |
| // Creates a new leaf node containing as much data as possible from `data`. |
| // The data is added either forwards or reversed depending on `edge_type`. |
| // Callers must check the length of the returned node to determine if all data |
| // was copied or not. |
| // See the `Append/Prepend` function for the meaning and purpose of `extra`. |
| template <EdgeType edge_type> |
| static CordRepBtree* NewLeaf(absl::string_view data, size_t extra); |
| |
| // Creates a raw copy of this Btree node with the specified length, copying |
| // all properties, but without adding any references to existing edges. |
| CordRepBtree* CopyRaw(size_t new_length) const; |
| |
| // Creates a full copy of this Btree node, adding a reference on all edges. |
| CordRepBtree* Copy() const; |
| |
| // Creates a partial copy of this Btree node, copying all edges up to `end`, |
| // adding a reference on each copied edge, and sets the length of the newly |
| // created copy to `new_length`. |
| CordRepBtree* CopyBeginTo(size_t end, size_t new_length) const; |
| |
| // Returns a tree containing the edges [tree->begin(), end) and length |
| // of `new_length`. This method consumes a reference on the provided |
| // tree, and logically performs the following operation: |
| // result = tree->CopyBeginTo(end, new_length); |
| // CordRep::Unref(tree); |
| // return result; |
| static CordRepBtree* ConsumeBeginTo(CordRepBtree* tree, size_t end, |
| size_t new_length); |
| |
| // Creates a partial copy of this Btree node, copying all edges starting at |
| // `begin`, adding a reference on each copied edge, and sets the length of |
| // the newly created copy to `new_length`. |
| CordRepBtree* CopyToEndFrom(size_t begin, size_t new_length) const; |
| |
| // Extracts and returns the front edge from the provided tree. |
| // This method consumes a reference on the provided tree, and logically |
| // performs the following operation: |
| // edge = CordRep::Ref(tree->Edge(kFront)); |
| // CordRep::Unref(tree); |
| // return edge; |
| static CordRep* ExtractFront(CordRepBtree* tree); |
| |
| // Returns a tree containing the result of appending `right` to `left`. |
| static CordRepBtree* MergeTrees(CordRepBtree* left, CordRepBtree* right); |
| |
| // Fallback functions for `Create()`, `Append()` and `Prepend()` which |
| // deal with legacy / non conforming input, i.e.: CONCAT trees. |
| static CordRepBtree* CreateSlow(CordRep* rep); |
| static CordRepBtree* AppendSlow(CordRepBtree*, CordRep* rep); |
| static CordRepBtree* PrependSlow(CordRepBtree*, CordRep* rep); |
| |
| // Recursively rebuilds `tree` into `stack`. If 'consume` is set to true, the |
| // function will consume a reference on `tree`. `stack` is a null terminated |
| // array containing the new tree's state, with the current leaf node at |
| // stack[0], and parent nodes above that, or null for 'top of tree'. |
| static void Rebuild(CordRepBtree** stack, CordRepBtree* tree, bool consume); |
| |
| // Aligns existing edges to start at index 0, to allow for a new edge to be |
| // added to the back of the current edges. |
| inline void AlignBegin(); |
| |
| // Aligns existing edges to end at `capacity`, to allow for a new edge to be |
| // added in front of the current edges. |
| inline void AlignEnd(); |
| |
| // Adds the provided edge to this node. |
| // Requires this node to have capacity for the edge. Realigns / moves |
| // existing edges as needed to prepend or append the new edge. |
| template <EdgeType edge_type> |
| inline void Add(CordRep* rep); |
| |
| // Adds the provided edges to this node. |
| // Requires this node to have capacity for the edges. Realigns / moves |
| // existing edges as needed to prepend or append the new edges. |
| template <EdgeType edge_type> |
| inline void Add(absl::Span<CordRep* const>); |
| |
| // Adds data from `data` to this node until either all data has been consumed, |
| // or there is no more capacity for additional flat nodes inside this node. |
| // Requires the current node to be a leaf node, data to be non empty, and the |
| // current node to have capacity for at least one more data edge. |
| // Returns any remaining data from `data` that was not added, which is |
| // depending on the edge type (front / back) either the remaining prefix of |
| // suffix of the input. |
| // See the `Append/Prepend` function for the meaning and purpose of `extra`. |
| template <EdgeType edge_type> |
| absl::string_view AddData(absl::string_view data, size_t extra); |
| |
| // Replace the front or back edge with the provided value. |
| // Adopts a reference on `edge` and unrefs the old edge. |
| template <EdgeType edge_type> |
| inline void SetEdge(CordRep* edge); |
| |
| // Returns a partial copy of the current tree containing the first `n` bytes |
| // of data. `CopyResult` contains both the resulting edge and its height. The |
| // resulting tree may be less high than the current tree, or even be a single |
| // matching data edge if `allow_folding` is set to true. |
| // For example, if `n == 1`, then the result will be the single data edge, and |
| // height will be set to -1 (one below the owning leaf node). If n == 0, this |
| // function returns null. Requires `n <= length` |
| CopyResult CopyPrefix(size_t n, bool allow_folding = true); |
| |
| // Returns a partial copy of the current tree containing all data starting |
| // after `offset`. `CopyResult` contains both the resulting edge and its |
| // height. The resulting tree may be less high than the current tree, or even |
| // be a single matching data edge. For example, if `n == length - 1`, then the |
| // result will be a single data edge, and height will be set to -1 (one below |
| // the owning leaf node). |
| // Requires `offset < length` |
| CopyResult CopySuffix(size_t offset); |
| |
| // Returns a OpResult value of {this, kSelf} or {Copy(), kCopied} |
| // depending on the value of `owned`. |
| inline OpResult ToOpResult(bool owned); |
| |
| // Adds `rep` to the specified tree, returning the modified tree. |
| template <EdgeType edge_type> |
| static CordRepBtree* AddCordRep(CordRepBtree* tree, CordRep* rep); |
| |
| // Adds `data` to the specified tree, returning the modified tree. |
| // See the `Append/Prepend` function for the meaning and purpose of `extra`. |
| template <EdgeType edge_type> |
| static CordRepBtree* AddData(CordRepBtree* tree, absl::string_view data, |
| size_t extra = 0); |
| |
| // Merges `src` into `dst` with `src` being added either before (kFront) or |
| // after (kBack) `dst`. Requires the height of `dst` to be greater than or |
| // equal to the height of `src`. |
| template <EdgeType edge_type> |
| static CordRepBtree* Merge(CordRepBtree* dst, CordRepBtree* src); |
| |
| // Fallback version of GetAppendBuffer for large trees: GetAppendBuffer() |
| // implements an inlined version for trees of limited height (3 levels), |
| // GetAppendBufferSlow implements the logic for large trees. |
| Span<char> GetAppendBufferSlow(size_t size); |
| |
| // `edges_` contains all edges starting from this instance. |
| // These are explicitly `child` edges only, a cord btree (or any cord tree in |
| // that respect) does not store `parent` pointers anywhere: multiple trees / |
| // parents can reference the same shared child edge. The type of these edges |
| // depends on the height of the node. `Leaf nodes` (height == 0) contain `data |
| // edges` (external or flat nodes, or sub-strings thereof). All other nodes |
| // (height > 0) contain pointers to BTREE nodes with a height of `height - 1`. |
| CordRep* edges_[kMaxCapacity]; |
| |
| friend class CordRepBtreeTestPeer; |
| friend class CordRepBtreeNavigator; |
| }; |
| |
| inline CordRepBtree* CordRep::btree() { |
| assert(IsBtree()); |
| return static_cast<CordRepBtree*>(this); |
| } |
| |
| inline const CordRepBtree* CordRep::btree() const { |
| assert(IsBtree()); |
| return static_cast<const CordRepBtree*>(this); |
| } |
| |
| inline void CordRepBtree::InitInstance(int height, size_t begin, size_t end) { |
| tag = BTREE; |
| storage[0] = static_cast<uint8_t>(height); |
| storage[1] = static_cast<uint8_t>(begin); |
| storage[2] = static_cast<uint8_t>(end); |
| } |
| |
| inline CordRep* CordRepBtree::Edge(size_t index) const { |
| assert(index >= begin()); |
| assert(index < end()); |
| return edges_[index]; |
| } |
| |
| inline CordRep* CordRepBtree::Edge(EdgeType edge_type) const { |
| return edges_[edge_type == kFront ? begin() : back()]; |
| } |
| |
| inline absl::Span<CordRep* const> CordRepBtree::Edges() const { |
| return {edges_ + begin(), size()}; |
| } |
| |
| inline absl::Span<CordRep* const> CordRepBtree::Edges(size_t begin, |
| size_t end) const { |
| assert(begin <= end); |
| assert(begin >= this->begin()); |
| assert(end <= this->end()); |
| return {edges_ + begin, static_cast<size_t>(end - begin)}; |
| } |
| |
| inline absl::string_view CordRepBtree::Data(size_t index) const { |
| assert(height() == 0); |
| return EdgeData(Edge(index)); |
| } |
| |
| inline CordRepBtree* CordRepBtree::New(int height) { |
| CordRepBtree* tree = new CordRepBtree; |
| tree->length = 0; |
| tree->InitInstance(height); |
| return tree; |
| } |
| |
| inline CordRepBtree* CordRepBtree::New(CordRep* rep) { |
| CordRepBtree* tree = new CordRepBtree; |
| int height = rep->IsBtree() ? rep->btree()->height() + 1 : 0; |
| tree->length = rep->length; |
| tree->InitInstance(height, /*begin=*/0, /*end=*/1); |
| tree->edges_[0] = rep; |
| return tree; |
| } |
| |
| inline CordRepBtree* CordRepBtree::New(CordRepBtree* front, |
| CordRepBtree* back) { |
| assert(front->height() == back->height()); |
| CordRepBtree* tree = new CordRepBtree; |
| tree->length = front->length + back->length; |
| tree->InitInstance(front->height() + 1, /*begin=*/0, /*end=*/2); |
| tree->edges_[0] = front; |
| tree->edges_[1] = back; |
| return tree; |
| } |
| |
| inline void CordRepBtree::Unref(absl::Span<CordRep* const> edges) { |
| for (CordRep* edge : edges) { |
| if (ABSL_PREDICT_FALSE(!edge->refcount.Decrement())) { |
| CordRep::Destroy(edge); |
| } |
| } |
| } |
| |
| inline CordRepBtree* CordRepBtree::CopyRaw(size_t new_length) const { |
| CordRepBtree* tree = new CordRepBtree; |
| |
| // `length` and `refcount` are the first members of `CordRepBtree`. |
| // We initialize `length` using the given length, have `refcount` be set to |
| // ref = 1 through its default constructor, and copy all data beyond |
| // 'refcount' which starts with `tag` using a single memcpy: all contents |
| // except `refcount` is trivially copyable, and the compiler does not |
| // efficiently coalesce member-wise copy of these members. |
| // See https://gcc.godbolt.org/z/qY8zsca6z |
| // LINT.IfChange(copy_raw) |
| tree->length = new_length; |
| uint8_t* dst = &tree->tag; |
| const uint8_t* src = &tag; |
| const ptrdiff_t offset = src - reinterpret_cast<const uint8_t*>(this); |
| memcpy(dst, src, sizeof(CordRepBtree) - static_cast<size_t>(offset)); |
| return tree; |
| // LINT.ThenChange() |
| } |
| |
| inline CordRepBtree* CordRepBtree::Copy() const { |
| CordRepBtree* tree = CopyRaw(length); |
| for (CordRep* rep : Edges()) CordRep::Ref(rep); |
| return tree; |
| } |
| |
| inline CordRepBtree* CordRepBtree::CopyToEndFrom(size_t begin, |
| size_t new_length) const { |
| assert(begin >= this->begin()); |
| assert(begin <= this->end()); |
| CordRepBtree* tree = CopyRaw(new_length); |
| tree->set_begin(begin); |
| for (CordRep* edge : tree->Edges()) CordRep::Ref(edge); |
| return tree; |
| } |
| |
| inline CordRepBtree* CordRepBtree::CopyBeginTo(size_t end, |
| size_t new_length) const { |
| assert(end <= capacity()); |
| assert(end >= this->begin()); |
| CordRepBtree* tree = CopyRaw(new_length); |
| tree->set_end(end); |
| for (CordRep* edge : tree->Edges()) CordRep::Ref(edge); |
| return tree; |
| } |
| |
| inline void CordRepBtree::AlignBegin() { |
| // The below code itself does not need to be fast as typically we have |
| // mono-directional append/prepend calls, and `begin` / `end` are typically |
| // adjusted no more than once. But we want to avoid potential register clobber |
| // effects, making the compiler emit register save/store/spills, and minimize |
| // the size of code. |
| const size_t delta = begin(); |
| if (ABSL_PREDICT_FALSE(delta != 0)) { |
| const size_t new_end = end() - delta; |
| set_begin(0); |
| set_end(new_end); |
| // TODO(mvels): we can write this using 2 loads / 2 stores depending on |
| // total size for the kMaxCapacity = 6 case. I.e., we can branch (switch) on |
| // size, and then do overlapping load/store of up to 4 pointers (inlined as |
| // XMM, YMM or ZMM load/store) and up to 2 pointers (XMM / YMM), which is a) |
| // compact and b) not clobbering any registers. |
| ABSL_ASSUME(new_end <= kMaxCapacity); |
| #ifdef __clang__ |
| #pragma unroll 1 |
| #endif |
| for (size_t i = 0; i < new_end; ++i) { |
| edges_[i] = edges_[i + delta]; |
| } |
| } |
| } |
| |
| inline void CordRepBtree::AlignEnd() { |
| // See comments in `AlignBegin` for motivation on the hand-rolled for loops. |
| const size_t delta = capacity() - end(); |
| if (delta != 0) { |
| const size_t new_begin = begin() + delta; |
| const size_t new_end = end() + delta; |
| set_begin(new_begin); |
| set_end(new_end); |
| ABSL_ASSUME(new_end <= kMaxCapacity); |
| #ifdef __clang__ |
| #pragma unroll 1 |
| #endif |
| for (size_t i = new_end - 1; i >= new_begin; --i) { |
| edges_[i] = edges_[i - delta]; |
| } |
| } |
| } |
| |
| template <> |
| inline void CordRepBtree::Add<CordRepBtree::kBack>(CordRep* rep) { |
| AlignBegin(); |
| edges_[fetch_add_end(1)] = rep; |
| } |
| |
| template <> |
| inline void CordRepBtree::Add<CordRepBtree::kBack>( |
| absl::Span<CordRep* const> edges) { |
| AlignBegin(); |
| size_t new_end = end(); |
| for (CordRep* edge : edges) edges_[new_end++] = edge; |
| set_end(new_end); |
| } |
| |
| template <> |
| inline void CordRepBtree::Add<CordRepBtree::kFront>(CordRep* rep) { |
| AlignEnd(); |
| edges_[sub_fetch_begin(1)] = rep; |
| } |
| |
| template <> |
| inline void CordRepBtree::Add<CordRepBtree::kFront>( |
| absl::Span<CordRep* const> edges) { |
| AlignEnd(); |
| size_t new_begin = begin() - edges.size(); |
| set_begin(new_begin); |
| for (CordRep* edge : edges) edges_[new_begin++] = edge; |
| } |
| |
| template <CordRepBtree::EdgeType edge_type> |
| inline void CordRepBtree::SetEdge(CordRep* edge) { |
| const int idx = edge_type == kFront ? begin() : back(); |
| CordRep::Unref(edges_[idx]); |
| edges_[idx] = edge; |
| } |
| |
| inline CordRepBtree::OpResult CordRepBtree::ToOpResult(bool owned) { |
| return owned ? OpResult{this, kSelf} : OpResult{Copy(), kCopied}; |
| } |
| |
| inline CordRepBtree::Position CordRepBtree::IndexOf(size_t offset) const { |
| assert(offset < length); |
| size_t index = begin(); |
| while (offset >= edges_[index]->length) offset -= edges_[index++]->length; |
| return {index, offset}; |
| } |
| |
| inline CordRepBtree::Position CordRepBtree::IndexBefore(size_t offset) const { |
| assert(offset > 0); |
| assert(offset <= length); |
| size_t index = begin(); |
| while (offset > edges_[index]->length) offset -= edges_[index++]->length; |
| return {index, offset}; |
| } |
| |
| inline CordRepBtree::Position CordRepBtree::IndexBefore(Position front, |
| size_t offset) const { |
| size_t index = front.index; |
| offset = offset + front.n; |
| while (offset > edges_[index]->length) offset -= edges_[index++]->length; |
| return {index, offset}; |
| } |
| |
| inline CordRepBtree::Position CordRepBtree::IndexOfLength(size_t n) const { |
| assert(n <= length); |
| size_t index = back(); |
| size_t strip = length - n; |
| while (strip >= edges_[index]->length) strip -= edges_[index--]->length; |
| return {index, edges_[index]->length - strip}; |
| } |
| |
| inline CordRepBtree::Position CordRepBtree::IndexBeyond( |
| const size_t offset) const { |
| // We need to find the edge which `starting offset` is beyond (>=)`offset`. |
| // For this we can't use the `offset -= length` logic of IndexOf. Instead, we |
| // track the offset of the `current edge` in `off`, which we increase as we |
| // iterate over the edges until we find the matching edge. |
| size_t off = 0; |
| size_t index = begin(); |
| while (offset > off) off += edges_[index++]->length; |
| return {index, off - offset}; |
| } |
| |
| inline CordRepBtree* CordRepBtree::Create(CordRep* rep) { |
| if (IsDataEdge(rep)) return New(rep); |
| return CreateSlow(rep); |
| } |
| |
| inline Span<char> CordRepBtree::GetAppendBuffer(size_t size) { |
| assert(refcount.IsOne()); |
| CordRepBtree* tree = this; |
| const int height = this->height(); |
| CordRepBtree* n1 = tree; |
| CordRepBtree* n2 = tree; |
| CordRepBtree* n3 = tree; |
| switch (height) { |
| case 3: |
| tree = tree->Edge(kBack)->btree(); |
| if (!tree->refcount.IsOne()) return {}; |
| n2 = tree; |
| ABSL_FALLTHROUGH_INTENDED; |
| case 2: |
| tree = tree->Edge(kBack)->btree(); |
| if (!tree->refcount.IsOne()) return {}; |
| n1 = tree; |
| ABSL_FALLTHROUGH_INTENDED; |
| case 1: |
| tree = tree->Edge(kBack)->btree(); |
| if (!tree->refcount.IsOne()) return {}; |
| ABSL_FALLTHROUGH_INTENDED; |
| case 0: |
| CordRep* edge = tree->Edge(kBack); |
| if (!edge->refcount.IsOne()) return {}; |
| if (edge->tag < FLAT) return {}; |
| size_t avail = edge->flat()->Capacity() - edge->length; |
| if (avail == 0) return {}; |
| size_t delta = (std::min)(size, avail); |
| Span<char> span = {edge->flat()->Data() + edge->length, delta}; |
| edge->length += delta; |
| switch (height) { |
| case 3: |
| n3->length += delta; |
| ABSL_FALLTHROUGH_INTENDED; |
| case 2: |
| n2->length += delta; |
| ABSL_FALLTHROUGH_INTENDED; |
| case 1: |
| n1->length += delta; |
| ABSL_FALLTHROUGH_INTENDED; |
| case 0: |
| tree->length += delta; |
| return span; |
| } |
| break; |
| } |
| return GetAppendBufferSlow(size); |
| } |
| |
| extern template CordRepBtree* CordRepBtree::AddCordRep<CordRepBtree::kBack>( |
| CordRepBtree* tree, CordRep* rep); |
| |
| extern template CordRepBtree* CordRepBtree::AddCordRep<CordRepBtree::kFront>( |
| CordRepBtree* tree, CordRep* rep); |
| |
| inline CordRepBtree* CordRepBtree::Append(CordRepBtree* tree, CordRep* rep) { |
| if (ABSL_PREDICT_TRUE(IsDataEdge(rep))) { |
| return CordRepBtree::AddCordRep<kBack>(tree, rep); |
| } |
| return AppendSlow(tree, rep); |
| } |
| |
| inline CordRepBtree* CordRepBtree::Prepend(CordRepBtree* tree, CordRep* rep) { |
| if (ABSL_PREDICT_TRUE(IsDataEdge(rep))) { |
| return CordRepBtree::AddCordRep<kFront>(tree, rep); |
| } |
| return PrependSlow(tree, rep); |
| } |
| |
| #ifdef NDEBUG |
| |
| inline CordRepBtree* CordRepBtree::AssertValid(CordRepBtree* tree, |
| bool /* shallow */) { |
| return tree; |
| } |
| |
| inline const CordRepBtree* CordRepBtree::AssertValid(const CordRepBtree* tree, |
| bool /* shallow */) { |
| return tree; |
| } |
| |
| #endif |
| |
| } // namespace cord_internal |
| ABSL_NAMESPACE_END |
| } // namespace absl |
| |
| #endif // ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_H_ |