diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index ca60d83..0debd3e 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel
@@ -719,6 +719,7 @@ testonly = True, srcs = ["internal/scoped_set_env.cc"], hdrs = ["internal/scoped_set_env.h"], + copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__",
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h index 6c238fc..b08735f 100644 --- a/absl/container/fixed_array.h +++ b/absl/container/fixed_array.h
@@ -392,8 +392,7 @@ template <typename H> friend H AbslHashValue(H h, const FixedArray& v) { - return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()), - hash_internal::WeaklyMixedInteger{v.size()}); + return H::combine_contiguous(std::move(h), v.data(), v.size()); } private:
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h index f871b34..c53cbd2 100644 --- a/absl/container/inlined_vector.h +++ b/absl/container/inlined_vector.h
@@ -1008,9 +1008,7 @@ // 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}); + return H::combine_contiguous(std::move(h), a.data(), a.size()); } ABSL_NAMESPACE_END
diff --git a/absl/container/internal/compressed_tuple.h b/absl/container/internal/compressed_tuple.h index 6db0468..2dd8d6c 100644 --- a/absl/container/internal/compressed_tuple.h +++ b/absl/container/internal/compressed_tuple.h
@@ -64,24 +64,24 @@ 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; + !std::is_final<T>::value; } +// Tag type used to disambiguate Storage types for different CompresseedTuples. +// Without it, CompressedTuple<T, CompressedTuple<T>> would inherit from +// Storage<T, 0> twice. +template <typename... Ts> +struct StorageTag; + // 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>()> +// Tag should be set to StorageTag<Ts...>. +template <typename T, size_t I, typename Tag, bool UseBase = ShouldUseBase<T>()> struct Storage { T value; constexpr Storage() = default; @@ -94,8 +94,8 @@ 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 { +template <typename T, size_t I, typename Tag> +struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<T, I, Tag, true> : T { constexpr Storage() = default; template <typename V> @@ -111,30 +111,35 @@ 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> +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>... { + : Storage<Ts, std::integral_constant<size_t, I>::value, + StorageTag<Ts...>>... { 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))... {} + : Storage<Ts, I, StorageTag<Ts...>>(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> +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>... { + : Storage<Ts, std::integral_constant<size_t, I>::value, StorageTag<Ts...>, + 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))... {} + : Storage<Ts, I, StorageTag<Ts...>, false>(absl::in_place, + std::forward<Vs>(args))... {} friend CompressedTuple<Ts...>; }; @@ -183,9 +188,7 @@ // 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.) +// empty classes, then CompressedTuple<Ts...> is itself an empty class. // // To access the members, use member .get<N>() function. // @@ -208,7 +211,8 @@ using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>; template <int I> - using StorageT = internal_compressed_tuple::Storage<ElemT<I>, I>; + using StorageT = internal_compressed_tuple::Storage< + ElemT<I>, I, internal_compressed_tuple::StorageTag<Ts...>>; public: // There seems to be a bug in MSVC dealing in which using '=default' here will
diff --git a/absl/container/internal/compressed_tuple_test.cc b/absl/container/internal/compressed_tuple_test.cc index 01b334e..662f944 100644 --- a/absl/container/internal/compressed_tuple_test.cc +++ b/absl/container/internal/compressed_tuple_test.cc
@@ -452,14 +452,15 @@ } #endif -// TODO(b/214288561): enable this test. -TEST(CompressedTupleTest, DISABLED_NestedEbo) { +TEST(CompressedTupleTest, NestedEbo) { struct Empty1 {}; struct Empty2 {}; CompressedTuple<Empty1, CompressedTuple<Empty2>, int> x; CompressedTuple<Empty1, Empty2, int> y; - // Currently fails with sizeof(x) == 8, sizeof(y) == 4. EXPECT_EQ(sizeof(x), sizeof(y)); + + using NestedEmpty = CompressedTuple<Empty1, CompressedTuple<Empty2>>; + EXPECT_TRUE(std::is_empty_v<NestedEmpty>); } } // namespace
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index e4122b4..f332320 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc
@@ -580,9 +580,13 @@ const auto insert_slot = [&](void* slot) { size_t hash = policy.hash_slot(hash_fn, slot); - FindInfo target = - common.is_small() ? FindInfo{0, 0} : find_first_non_full(common, hash); - SetCtrl(common, target.offset, H2(hash), slot_size); + FindInfo target; + if (common.is_small()) { + target = FindInfo{0, 0}; + } else { + target = find_first_non_full(common, hash); + SetCtrl(common, target.offset, H2(hash), slot_size); + } policy.transfer_n(&common, SlotAddress(new_slots, target.offset, slot_size), slot, 1); return target.probe_length;
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 32ba5b2..ac0ff4a 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h
@@ -1497,6 +1497,7 @@ // mirror the value to the cloned tail if necessary. inline void SetCtrl(const CommonFields& c, size_t i, ctrl_t h, size_t slot_size) { + ABSL_SWISSTABLE_ASSERT(!c.is_small()); DoSanitizeOnSetCtrl(c, i, h, slot_size); ctrl_t* ctrl = c.control(); ctrl[i] = h; @@ -1512,6 +1513,7 @@ // setting the cloned control byte. inline void SetCtrlInSingleGroupTable(const CommonFields& c, size_t i, ctrl_t h, size_t slot_size) { + ABSL_SWISSTABLE_ASSERT(!c.is_small()); ABSL_SWISSTABLE_ASSERT(is_single_group(c.capacity())); DoSanitizeOnSetCtrl(c, i, h, slot_size); ctrl_t* ctrl = c.control();
diff --git a/absl/copts/GENERATED_AbseilCopts.cmake b/absl/copts/GENERATED_AbseilCopts.cmake index 7d8af92..32b97fc 100644 --- a/absl/copts/GENERATED_AbseilCopts.cmake +++ b/absl/copts/GENERATED_AbseilCopts.cmake
@@ -121,6 +121,7 @@ "-Wno-implicit-float-conversion" "-Wno-implicit-int-float-conversion" "-Wno-unknown-warning-option" + "-Wno-unused-command-line-argument" "-DNOMINMAX" ) @@ -160,6 +161,7 @@ "-Wno-implicit-float-conversion" "-Wno-implicit-int-float-conversion" "-Wno-unknown-warning-option" + "-Wno-unused-command-line-argument" "-DNOMINMAX" "-Wno-deprecated-declarations" "-Wno-implicit-int-conversion"
diff --git a/absl/copts/GENERATED_copts.bzl b/absl/copts/GENERATED_copts.bzl index 23896e9..8d72190 100644 --- a/absl/copts/GENERATED_copts.bzl +++ b/absl/copts/GENERATED_copts.bzl
@@ -122,6 +122,7 @@ "-Wno-implicit-float-conversion", "-Wno-implicit-int-float-conversion", "-Wno-unknown-warning-option", + "-Wno-unused-command-line-argument", "-DNOMINMAX", ] @@ -161,6 +162,7 @@ "-Wno-implicit-float-conversion", "-Wno-implicit-int-float-conversion", "-Wno-unknown-warning-option", + "-Wno-unused-command-line-argument", "-DNOMINMAX", "-Wno-deprecated-declarations", "-Wno-implicit-int-conversion",
diff --git a/absl/copts/copts.py b/absl/copts/copts.py index 8cf8f31..e6c4385 100644 --- a/absl/copts/copts.py +++ b/absl/copts/copts.py
@@ -84,6 +84,7 @@ # Disable warnings on unknown warning flags (when warning flags are # unknown on older compiler versions) "-Wno-unknown-warning-option", + "-Wno-unused-command-line-argument", # Don't define min and max macros (Build on Windows using clang) "-DNOMINMAX", ]
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc index 7582f54..85e34c9 100644 --- a/absl/hash/hash_test.cc +++ b/absl/hash/hash_test.cc
@@ -171,6 +171,9 @@ constexpr size_t kLog2NumValues = 5; constexpr size_t kNumValues = 1 << kLog2NumValues; + int64_t test_count = 0; + int64_t total_stuck_bit_count = 0; + for (size_t align = 1; align < kTotalSize / kNumValues; align < 8 ? align += 1 : align < 1024 ? align += 8 : align += 32) { SCOPED_TRACE(align); @@ -188,9 +191,16 @@ // Limit the scope to the bits we would be using for Swisstable. constexpr size_t kMask = (1 << (kLog2NumValues + 7)) - 1; size_t stuck_bits = (~bits_or | bits_and) & kMask; - // Test that there are at most 3 stuck bits. - EXPECT_LE(absl::popcount(stuck_bits), 3) << "0x" << std::hex << stuck_bits; + int stuck_bit_count = absl::popcount(stuck_bits); + // Test that there are at most 4 stuck bits. + EXPECT_LE(stuck_bit_count, 4) << "0x" << std::hex << stuck_bits; + + total_stuck_bit_count += stuck_bit_count; + ++test_count; } + // Test that average across alignments are at most 0.2 stuck bits. + // As of 2025-05-30 test is also passing with 0.07 stuck bits. + EXPECT_LE(total_stuck_bit_count, 0.2 * test_count); } TEST(HashValueTest, PointerToMember) { @@ -1224,4 +1234,9 @@ absl::Hash<AutoReturnTypeUser>{}(AutoReturnTypeUser{1, s})); } +TEST(HashOf, DoubleSignCollision) { + // These values differ only in their most significant bit. + EXPECT_NE(absl::HashOf(-1.0), absl::HashOf(1.0)); +} + } // namespace
diff --git a/absl/hash/internal/hash.cc b/absl/hash/internal/hash.cc index b185a0a..1b47e61 100644 --- a/absl/hash/internal/hash.cc +++ b/absl/hash/internal/hash.cc
@@ -27,27 +27,39 @@ namespace hash_internal { uint64_t MixingHashState::CombineLargeContiguousImpl32( - uint64_t state, const unsigned char* first, size_t len) { + const unsigned char* first, size_t len, uint64_t state) { while (len >= PiecewiseChunkSize()) { - state = Mix( - state ^ hash_internal::CityHash32(reinterpret_cast<const char*>(first), + // TODO(b/417141985): avoid code duplication with CombineContiguousImpl. + state = + Mix(PrecombineLengthMix(state, PiecewiseChunkSize()) ^ + hash_internal::CityHash32(reinterpret_cast<const char*>(first), PiecewiseChunkSize()), - kMul); + kMul); len -= PiecewiseChunkSize(); first += PiecewiseChunkSize(); } + // Do not call CombineContiguousImpl for empty range since it is modifying + // state. + if (len == 0) { + return state; + } // Handle the remainder. return CombineContiguousImpl(state, first, len, std::integral_constant<int, 4>{}); } uint64_t MixingHashState::CombineLargeContiguousImpl64( - uint64_t state, const unsigned char* first, size_t len) { + const unsigned char* first, size_t len, uint64_t state) { while (len >= PiecewiseChunkSize()) { state = Hash64(first, PiecewiseChunkSize(), state); len -= PiecewiseChunkSize(); first += PiecewiseChunkSize(); } + // Do not call CombineContiguousImpl for empty range since it is modifying + // state. + if (len == 0) { + return state; + } // Handle the remainder. return CombineContiguousImpl(state, first, len, std::integral_constant<int, 8>{});
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index f400c7b..fa88227 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h
@@ -127,7 +127,7 @@ // return combiner.finalize(std::move(state)); class PiecewiseCombiner { public: - PiecewiseCombiner() : position_(0) {} + PiecewiseCombiner() = default; PiecewiseCombiner(const PiecewiseCombiner&) = delete; PiecewiseCombiner& operator=(const PiecewiseCombiner&) = delete; @@ -157,7 +157,8 @@ private: unsigned char buf_[PiecewiseChunkSize()]; - size_t position_; + size_t position_ = 0; + bool added_something_ = false; }; // is_hashable() @@ -620,9 +621,7 @@ // `eq()` member isn't equivalent to `==` on the underlying character type. template <typename H> H AbslHashValue(H hash_state, absl::string_view str) { - return H::combine( - H::combine_contiguous(std::move(hash_state), str.data(), str.size()), - WeaklyMixedInteger{str.size()}); + return H::combine_contiguous(std::move(hash_state), str.data(), str.size()); } // Support std::wstring, std::u16string and std::u32string. @@ -633,9 +632,7 @@ H AbslHashValue( H hash_state, const std::basic_string<Char, std::char_traits<Char>, Alloc>& str) { - return H::combine( - H::combine_contiguous(std::move(hash_state), str.data(), str.size()), - WeaklyMixedInteger{str.size()}); + return H::combine_contiguous(std::move(hash_state), str.data(), str.size()); } // Support std::wstring_view, std::u16string_view and std::u32string_view. @@ -644,9 +641,7 @@ std::is_same<Char, char16_t>::value || std::is_same<Char, char32_t>::value>> H AbslHashValue(H hash_state, std::basic_string_view<Char> str) { - return H::combine( - H::combine_contiguous(std::move(hash_state), str.data(), str.size()), - WeaklyMixedInteger{str.size()}); + return H::combine_contiguous(std::move(hash_state), str.data(), str.size()); } #if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \ @@ -728,9 +723,8 @@ typename std::enable_if<is_hashable<T>::value && !std::is_same<T, bool>::value, H>::type AbslHashValue(H hash_state, const std::vector<T, Allocator>& vector) { - return H::combine(H::combine_contiguous(std::move(hash_state), vector.data(), - vector.size()), - WeaklyMixedInteger{vector.size()}); + return H::combine_contiguous(std::move(hash_state), vector.data(), + vector.size()); } // AbslHashValue special cases for hashing std::vector<bool> @@ -957,7 +951,23 @@ for (const auto end = data + size; data < end; ++data) { hash_state = H::combine(std::move(hash_state), *data); } - return hash_state; + return H::combine(std::move(hash_state), + hash_internal::WeaklyMixedInteger{size}); +} + +// Extremely weak mixture of length that is added to the state before combining +// the data. It is used only for small strings. +inline uint64_t PrecombineLengthMix(uint64_t state, size_t len) { + // The length is always one byte here. We place it to 4th byte for the + // following reasons: + // 1. 4th byte is unused for very short strings 0-3 bytes. + // 2. 4th byte is duplicated for 4 bytes string. + // 3. 4th byte is in the middle and mixed well for 5-8 bytes strings. + // + // There were experiments with adding just `len` here. + // Also seems have slightly better performance overall, that gives collisions + // for small strings. + return state + (uint64_t{len} << 24); } #if defined(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE) && \ @@ -1201,8 +1211,8 @@ } else if (len > 0) { v = Read1To3(first, len); } else { - // Empty ranges have no effect. - return state; + // Empty string must modify the state. + v = 0x57; } return WeakMix(state, v); } @@ -1238,12 +1248,10 @@ // Slow dispatch path for calls to CombineContiguousImpl with a size argument // larger than PiecewiseChunkSize(). Has the same effect as calling // CombineContiguousImpl() repeatedly with the chunk stride size. - static uint64_t CombineLargeContiguousImpl32(uint64_t state, - const unsigned char* first, - size_t len); - static uint64_t CombineLargeContiguousImpl64(uint64_t state, - const unsigned char* first, - size_t len); + static uint64_t CombineLargeContiguousImpl32(const unsigned char* first, + size_t len, uint64_t state); + static uint64_t CombineLargeContiguousImpl64(const unsigned char* first, + size_t len, uint64_t state); // Reads 9 to 16 bytes from p. // The first 8 bytes are in .first, and the rest of the bytes are in .second @@ -1266,16 +1274,18 @@ #endif } - // Reads 4 to 8 bytes from p. Some input bytes may be duplicated in output. + // Reads 4 to 8 bytes from p. + // Bytes are permuted and some input bytes may be duplicated in output. static uint64_t Read4To8(const unsigned char* p, size_t len) { - // If `len < 8`, we duplicate bytes in the middle. - // E.g.: + // If `len < 8`, we duplicate bytes. We always put low memory at the end. + // E.g., on little endian platforms: // `ABCD` will be read as `ABCDABCD`. - // `ABCDE` will be read as `ABCDBCDE`. - // `ABCDEF` will be read as `ABCDCDEF`. - // `ABCDEFG` will be read as `ABCDDEFG`. + // `ABCDE` will be read as `BCDEABCD`. + // `ABCDEF` will be read as `CDEFABCD`. + // `ABCDEFG` will be read as `DEFGABCD`. + // `ABCDEFGH` will be read as `EFGHABCD`. // We also do not care about endianness. On big-endian platforms, bytes will - // be shuffled (it's fine). We always shift low memory by 32, because that + // be permuted differently. We always shift low memory by 32, because that // can be pipelined earlier. Reading high memory requires computing // `p + len - 4`. uint64_t most_significant = @@ -1373,15 +1383,17 @@ // For large values we use CityHash, for small ones we use custom low latency // hash. if (len <= 8) { - return CombineSmallContiguousImpl(state, first, len); + return CombineSmallContiguousImpl(PrecombineLengthMix(state, len), first, + len); } if (ABSL_PREDICT_TRUE(len <= PiecewiseChunkSize())) { // TODO(b/417141985): expose and use CityHash32WithSeed. - return Mix(state ^ hash_internal::CityHash32( - reinterpret_cast<const char*>(first), len), + return Mix(PrecombineLengthMix(state, len) ^ + hash_internal::CityHash32( + reinterpret_cast<const char*>(first), len), kMul); } - return CombineLargeContiguousImpl32(state, first, len); + return CombineLargeContiguousImpl32(first, len, state); } // Overload of MixingHashState::CombineContiguousImpl() @@ -1391,18 +1403,25 @@ // For large values we use LowLevelHash or CityHash depending on the platform, // for small ones we use custom low latency hash. if (len <= 8) { - return CombineSmallContiguousImpl(state, first, len); + return CombineSmallContiguousImpl(PrecombineLengthMix(state, len), first, + len); } if (len <= 16) { - return CombineContiguousImpl9to16(state, first, len); + return CombineContiguousImpl9to16(PrecombineLengthMix(state, len), first, + len); } if (len <= 32) { - return CombineContiguousImpl17to32(state, first, len); + return CombineContiguousImpl17to32(PrecombineLengthMix(state, len), first, + len); } if (ABSL_PREDICT_TRUE(len <= PiecewiseChunkSize())) { + // Length is mixed into the state inside of Hash64. return Hash64(first, len, state); } - return CombineLargeContiguousImpl64(state, first, len); + // We must not mix length to the state here because calling + // CombineContiguousImpl twice with PiecewiseChunkSize() must be equivalent + // to calling CombineLargeContiguousImpl once with 2 * PiecewiseChunkSize(). + return CombineLargeContiguousImpl64(first, len, state); } struct AggregateBarrier {}; @@ -1462,7 +1481,7 @@ position_ += size; return state; } - + added_something_ = true; // If the buffer is partially filled we need to complete the buffer // and hash it. if (position_ != 0) { @@ -1488,7 +1507,12 @@ // HashStateBase::PiecewiseCombiner::finalize() template <typename H> H PiecewiseCombiner::finalize(H state) { - // Hash the remainder left in the buffer, which may be empty + // Do not call combine_contiguous with empty remainder since it is modifying + // state. + if (added_something_ && position_ == 0) { + return state; + } + // We still call combine_contiguous for the entirely empty buffer. return H::combine_contiguous(std::move(state), buf_, position_); }
diff --git a/absl/hash/internal/spy_hash_state.h b/absl/hash/internal/spy_hash_state.h index e403113..823e1e9 100644 --- a/absl/hash/internal/spy_hash_state.h +++ b/absl/hash/internal/spy_hash_state.h
@@ -151,6 +151,9 @@ static SpyHashStateImpl combine_contiguous(SpyHashStateImpl hash_state, const unsigned char* begin, size_t size) { + if (size == 0) { + return SpyHashStateImpl::combine_raw(std::move(hash_state), 0); + } const size_t large_chunk_stride = PiecewiseChunkSize(); // Combining a large contiguous buffer must have the same effect as // doing it piecewise by the stride length, followed by the (possibly @@ -165,6 +168,7 @@ if (size > 0) { hash_state.hash_representation_.emplace_back( reinterpret_cast<const char*>(begin), size); + hash_state = SpyHashStateImpl::combine_raw(std::move(hash_state), size); } return hash_state; } @@ -224,8 +228,9 @@ // Combines raw data from e.g. integrals/floats/pointers/etc. static SpyHashStateImpl combine_raw(SpyHashStateImpl state, uint64_t value) { - const unsigned char* data = reinterpret_cast<const unsigned char*>(&value); - return SpyHashStateImpl::combine_contiguous(std::move(state), data, 8); + state.hash_representation_.emplace_back( + reinterpret_cast<const char*>(&value), 8); + return state; } // This is true if SpyHashStateImpl<T> has been passed to a call of
diff --git a/absl/log/internal/check_op.h b/absl/log/internal/check_op.h index 7253402..17afded 100644 --- a/absl/log/internal/check_op.h +++ b/absl/log/internal/check_op.h
@@ -133,41 +133,39 @@ // 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)) \ +#define ABSL_LOG_INTERNAL_CHECK_OK(val, val_text) \ + for (::std::pair<const ::absl::Status* absl_nonnull, \ + const char* absl_nonnull> \ + 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()) \ + ? "" /* Don't use nullptr, to keep the annotation happy */ \ + : ::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_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)) \ +#define ABSL_LOG_INTERNAL_QCHECK_OK(val, val_text) \ + for (::std::pair<const ::absl::Status* absl_nonnull, \ + const char* absl_nonnull> \ + 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()) \ + ? "" /* Don't use nullptr, to keep the annotation happy */ \ + : ::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_log_internal_qcheck_ok_goo.second) \ .InternalStream() namespace absl {
diff --git a/absl/profiling/BUILD.bazel b/absl/profiling/BUILD.bazel index ee4800d..4a3c644 100644 --- a/absl/profiling/BUILD.bazel +++ b/absl/profiling/BUILD.bazel
@@ -49,6 +49,7 @@ cc_test( name = "sample_recorder_test", srcs = ["internal/sample_recorder_test.cc"], + copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, tags = [ "no_test_wasm", @@ -69,6 +70,7 @@ name = "exponential_biased", srcs = ["internal/exponential_biased.cc"], hdrs = ["internal/exponential_biased.h"], + copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__",
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index bb152ac..0b9d372 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel
@@ -1462,6 +1462,7 @@ testonly = True, srcs = ["internal/pow10_helper.cc"], hdrs = ["internal/pow10_helper.h"], + copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = ["//absl/base:config"],
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 547ef26..32ad263 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt
@@ -663,7 +663,7 @@ SRCS "internal/pow10_helper.cc" COPTS - ${ABSL_TEST_COPTS} + ${ABSL_DEFAULT_COPTS} DEPS absl::config TESTONLY
diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 5aa232e..edda551 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h
@@ -1098,8 +1098,7 @@ 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()}); + return combiner.finalize(std::move(hash_state)); } friend class CrcCord;
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc index 969e1f9..3f265d1 100644 --- a/absl/strings/str_format_test.cc +++ b/absl/strings/str_format_test.cc
@@ -516,14 +516,11 @@ EXPECT_EQ(result, 17); EXPECT_EQ(std::string(buffer), "NUMBER: 1234567"); - // The `output` parameter is annotated nonnull, but we want to test that - // it is never written to if the size is zero. - // Use a variable instead of passing nullptr directly to avoid a `-Wnonnull` - // warning. - char* null_output = nullptr; - result = - SNPrintF(null_output, 0, "Just checking the %s of the output.", "size"); + // Test that the buffer is never written to if the size is zero. + buffer[0] = '\0'; + result = SNPrintF(buffer, 0, "Just checking the %s of the output.", "size"); EXPECT_EQ(result, 37); + EXPECT_EQ(buffer[0], '\0'); } TEST_F(FormatEntryPointTest, SNPrintFWithV) { @@ -551,14 +548,11 @@ std::string size = "size"; - // The `output` parameter is annotated nonnull, but we want to test that - // it is never written to if the size is zero. - // Use a variable instead of passing nullptr directly to avoid a `-Wnonnull` - // warning. - char* null_output = nullptr; - result = - SNPrintF(null_output, 0, "Just checking the %v of the output.", size); + // Test that the buffer is never written to if the size is zero. + buffer[0] = '\0'; + result = SNPrintF(buffer, 0, "Just checking the %v of the output.", size); EXPECT_EQ(result, 37); + EXPECT_EQ(buffer[0], '\0'); } TEST(StrFormat, BehavesAsDocumented) {
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index 9a1933b..eca5404 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h
@@ -198,11 +198,15 @@ // 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) {} + : ptr_(str), length_(str ? StrlenInternal(str) : 0) { + assert(str != nullptr); + } // 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)) {} + : ptr_(data), length_(CheckLengthInternal(len)) { + ABSL_ASSERT(data != nullptr || len == 0); + } constexpr string_view(const string_view&) noexcept = default; string_view& operator=(const string_view&) noexcept = default; @@ -376,7 +380,7 @@ // // 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 { + size_type copy(char* absl_nonnull buf, size_type n, size_type pos = 0) const { if (ABSL_PREDICT_FALSE(pos > length_)) { base_internal::ThrowStdOutOfRange("absl::string_view::copy"); } @@ -624,7 +628,7 @@ // 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 { + constexpr bool starts_with(const char* absl_nonnull s) const { return starts_with(string_view(s)); } @@ -649,7 +653,7 @@ // 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 { + constexpr bool ends_with(const char* absl_nonnull s) const { return ends_with(string_view(s)); } #endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc index 0a2a7a9..adf4d1b 100644 --- a/absl/strings/string_view_test.cc +++ b/absl/strings/string_view_test.cc
@@ -870,42 +870,10 @@ #endif } -// `std::string_view::string_view(const char*)` calls -// `std::char_traits<char>::length(const char*)` to get the string length. In -// libc++, it doesn't allow `nullptr` in the constexpr context, with the error -// "read of dereferenced null pointer is not allowed in a constant expression". -// At run time, the behavior of `std::char_traits::length()` on `nullptr` is -// undefined by the standard and usually results in crash with libc++. -// GCC also started rejected this in libstdc++ starting in GCC9. -// In MSVC, creating a constexpr string_view from nullptr also triggers an -// "unevaluable pointer value" error. This compiler implementation conforms -// to the standard, but `absl::string_view` implements a different -// behavior for historical reasons. We work around tests that construct -// `string_view` from `nullptr` when using libc++. -#if !defined(ABSL_USES_STD_STRING_VIEW) || \ - (!(defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 9) && \ - !defined(_LIBCPP_VERSION) && !defined(_MSC_VER)) -#define ABSL_HAVE_STRING_VIEW_FROM_NULLPTR 1 -#endif - -TEST(StringViewTest, NULLInput) { +TEST(StringViewTest, DefaultConstructor) { absl::string_view s; EXPECT_EQ(s.data(), nullptr); EXPECT_EQ(s.size(), 0u); - -#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR - // The `str` parameter is annotated nonnull, but we want to test the defensive - // null check. Use a variable instead of passing nullptr directly to avoid a - // `-Wnonnull` warning. - char* null_str = nullptr; - s = absl::string_view(null_str); - EXPECT_EQ(s.data(), nullptr); - EXPECT_EQ(s.size(), 0u); - - // .ToString() on a absl::string_view with nullptr should produce the empty - // string. - EXPECT_EQ("", std::string(s)); -#endif // ABSL_HAVE_STRING_VIEW_FROM_NULLPTR } TEST(StringViewTest, Comparisons2) { @@ -1086,16 +1054,6 @@ // know at compile time that the argument is nullptr and complain because the // parameter is annotated nonnull. We hence turn the warning off for this // test. -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnonnull" -#endif -#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR - constexpr absl::string_view cstr(nullptr); -#endif -#if defined(__clang__) -#pragma clang diagnostic pop -#endif constexpr absl::string_view cstr_len("cstr", 4); #if defined(ABSL_USES_STD_STRING_VIEW) @@ -1163,12 +1121,6 @@ constexpr absl::string_view::iterator const_end_empty = sp.end(); EXPECT_EQ(const_begin_empty, const_end_empty); -#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR - constexpr absl::string_view::iterator const_begin_nullptr = cstr.begin(); - constexpr absl::string_view::iterator const_end_nullptr = cstr.end(); - EXPECT_EQ(const_begin_nullptr, const_end_nullptr); -#endif // ABSL_HAVE_STRING_VIEW_FROM_NULLPTR - constexpr absl::string_view::iterator const_begin = cstr_len.begin(); constexpr absl::string_view::iterator const_end = cstr_len.end(); constexpr absl::string_view::size_type const_size = cstr_len.size();
diff --git a/absl/time/time.h b/absl/time/time.h index db17a4c..53bca90 100644 --- a/absl/time/time.h +++ b/absl/time/time.h
@@ -1869,8 +1869,9 @@ 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); } - return d / Nanoseconds(1); } ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Microseconds( @@ -1880,8 +1881,9 @@ return (time_internal::GetRepHi(d) * 1000 * 1000) + (time_internal::GetRepLo(d) / (time_internal::kTicksPerNanosecond * 1000)); + } else { + return d / Microseconds(1); } - return d / Microseconds(1); } ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Milliseconds( @@ -1891,8 +1893,9 @@ return (time_internal::GetRepHi(d) * 1000) + (time_internal::GetRepLo(d) / (time_internal::kTicksPerNanosecond * 1000 * 1000)); + } else { + return d / Milliseconds(1); } - return d / Milliseconds(1); } ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Seconds(Duration d) {
diff --git a/absl/types/span.h b/absl/types/span.h index 39e6a8a..772681c 100644 --- a/absl/types/span.h +++ b/absl/types/span.h
@@ -499,8 +499,7 @@ // 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()}); + return H::combine_contiguous(std::move(h), v.data(), v.size()); } private:
diff --git a/ci/linux_docker_containers.sh b/ci/linux_docker_containers.sh index 0f45471..cb0904c 100644 --- a/ci/linux_docker_containers.sh +++ b/ci/linux_docker_containers.sh
@@ -16,7 +16,7 @@ # Test scripts should source this file to get the identifiers. readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20230612" -readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250430" +readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250527" readonly LINUX_ARM_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_arm_hybrid-latest:20250430" -readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250430" +readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250527" readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20250430"
diff --git a/ci/macos_xcode_bazel.sh b/ci/macos_xcode_bazel.sh index b05cfac..f19cd50 100755 --- a/ci/macos_xcode_bazel.sh +++ b/ci/macos_xcode_bazel.sh
@@ -19,8 +19,8 @@ set -euox pipefail -# Use Xcode 16.0 -sudo xcode-select -s /Applications/Xcode_16.0.app/Contents/Developer +# Use Xcode 16.3 +sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer if [[ -z ${ABSEIL_ROOT:-} ]]; then ABSEIL_ROOT="$(realpath $(dirname ${0})/..)" @@ -54,9 +54,6 @@ cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1 fi -# Avoid using the system version of google-benchmark. -brew uninstall google-benchmark - ${BAZEL_BIN} test ... \ --copt="-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1" \ --copt="-Werror" \
diff --git a/ci/macos_xcode_cmake.sh b/ci/macos_xcode_cmake.sh index 6811b87..5b11b89 100755 --- a/ci/macos_xcode_cmake.sh +++ b/ci/macos_xcode_cmake.sh
@@ -16,8 +16,10 @@ set -euox pipefail -# Use Xcode 16.0 -sudo xcode-select -s /Applications/Xcode_16.0.app/Contents/Developer +# Use Xcode 16.3 +sudo xcode-select -s /Applications/Xcode_16.3.app/Contents/Developer + +brew install cmake export CMAKE_BUILD_PARALLEL_LEVEL=$(sysctl -n hw.ncpu) export CTEST_PARALLEL_LEVEL=$(sysctl -n hw.ncpu)