diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index c49d621..9145d8b 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake
@@ -448,7 +448,12 @@ "debugging/leak_check.cc" ) -if(NOT MSVC) +if(MSVC) + list(APPEND ABSL_INTERNAL_DLL_FILES + "time/internal/cctz/src/time_zone_name_win.cc" + "time/internal/cctz/src/time_zone_name_win.h" + ) +else() list(APPEND ABSL_INTERNAL_DLL_FILES "flags/commandlineflag.cc" "flags/commandlineflag.h"
diff --git a/absl/base/attributes.h b/absl/base/attributes.h index 33b2c28..77482e5 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h
@@ -580,7 +580,11 @@ // 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 +// Use of this attribute is HIGHLY DISCOURAGED. Taking the address of or +// binding a reference to any unaligned member is UB, and it is very easy to +// do so unintentionally when passing such members as function arguments. +// +// 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. //
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index 68a9008..ab6533f 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel
@@ -429,6 +429,7 @@ deps = [ ":container_memory", ":test_instance_tracker", + "//absl/base:config", "//absl/base:no_destructor", "//absl/meta:type_traits", "//absl/strings",
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index 6adba18..adce9a9 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt
@@ -484,6 +484,7 @@ COPTS ${ABSL_TEST_COPTS} DEPS + absl::config absl::container_memory absl::no_destructor absl::strings
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h index 8c97469..608a865 100644 --- a/absl/container/internal/container_memory.h +++ b/absl/container/internal/container_memory.h
@@ -44,7 +44,12 @@ namespace container_internal { template <size_t Alignment> -struct alignas(Alignment) AlignedType {}; +struct alignas(Alignment) AlignedType { + // When alignment is sufficient for the allocated memory to store pointers, + // include a pointer member so that swisstable backing arrays end up in the + // pointer-containing partition for heap partitioning. + std::conditional_t<(Alignment < alignof(void*)), char, void*> pointer; +}; // Allocates at least n bytes aligned to the specified alignment. // Alignment must be a power of 2. It must be positive.
diff --git a/absl/container/internal/container_memory_test.cc b/absl/container/internal/container_memory_test.cc index 97b09f7..946d1d3 100644 --- a/absl/container/internal/container_memory_test.cc +++ b/absl/container/internal/container_memory_test.cc
@@ -25,6 +25,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/config.h" #include "absl/base/no_destructor.h" #include "absl/container/internal/test_instance_tracker.h" #include "absl/meta/type_traits.h" @@ -42,6 +43,16 @@ using ::testing::Gt; using ::testing::Pair; +#if ABSL_HAVE_BUILTIN(__builtin_infer_alloc_token) +TEST(Memory, AlignedTypeAllocToken) { +#if defined(__wasm__) + GTEST_SKIP() << "Fails on wasm due to lack of heap partitioning support."; +#endif + EXPECT_GT(__builtin_infer_alloc_token(sizeof(AlignedType<alignof(void*)>)), + __builtin_infer_alloc_token(sizeof(int))); +} +#endif + TEST(Memory, AlignmentLargerThanBase) { std::allocator<int8_t> alloc; void* mem = Allocate<2>(&alloc, 3);
diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc index 4adf591..4f6e946 100644 --- a/absl/container/internal/hashtablez_sampler.cc +++ b/absl/container/internal/hashtablez_sampler.cc
@@ -87,7 +87,6 @@ total_probe_length.store(0, std::memory_order_relaxed); hashes_bitwise_or.store(0, std::memory_order_relaxed); hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed); - hashes_bitwise_xor.store(0, std::memory_order_relaxed); max_reserve.store(0, std::memory_order_relaxed); create_time = absl::Now(); @@ -244,7 +243,6 @@ info->hashes_bitwise_and.fetch_and(hash, std::memory_order_relaxed); info->hashes_bitwise_or.fetch_or(hash, std::memory_order_relaxed); - info->hashes_bitwise_xor.fetch_xor(hash, std::memory_order_relaxed); info->max_probe_length.store( std::max(info->max_probe_length.load(std::memory_order_relaxed), probe_length),
diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h index 163b18a..6c20dc3 100644 --- a/absl/container/internal/hashtablez_sampler.h +++ b/absl/container/internal/hashtablez_sampler.h
@@ -88,7 +88,6 @@ std::atomic<size_t> total_probe_length; std::atomic<size_t> hashes_bitwise_or; std::atomic<size_t> hashes_bitwise_and; - std::atomic<size_t> hashes_bitwise_xor; std::atomic<size_t> max_reserve; // All of the fields below are set by `PrepareForSampling`, they must not be
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc index cbd8edc..9391e94 100644 --- a/absl/container/internal/hashtablez_sampler_test.cc +++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -105,7 +105,6 @@ EXPECT_EQ(info.total_probe_length.load(), 0); EXPECT_EQ(info.hashes_bitwise_or.load(), 0); EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{}); - EXPECT_EQ(info.hashes_bitwise_xor.load(), 0); EXPECT_EQ(info.max_reserve.load(), 0); EXPECT_GE(info.create_time, test_start); EXPECT_EQ(info.weight, test_stride); @@ -122,7 +121,6 @@ info.total_probe_length.store(1, std::memory_order_relaxed); info.hashes_bitwise_or.store(1, std::memory_order_relaxed); info.hashes_bitwise_and.store(1, std::memory_order_relaxed); - info.hashes_bitwise_xor.store(1, std::memory_order_relaxed); info.max_reserve.store(1, std::memory_order_relaxed); info.create_time = test_start - absl::Hours(20); @@ -139,7 +137,6 @@ EXPECT_EQ(info.total_probe_length.load(), 0); EXPECT_EQ(info.hashes_bitwise_or.load(), 0); EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{}); - EXPECT_EQ(info.hashes_bitwise_xor.load(), 0); EXPECT_EQ(info.max_reserve.load(), 0); EXPECT_EQ(info.weight, 2 * test_stride); EXPECT_EQ(info.inline_element_size, test_element_size); @@ -186,17 +183,14 @@ EXPECT_EQ(info.max_probe_length.load(), 6); EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000FF00); EXPECT_EQ(info.hashes_bitwise_or.load(), 0x0000FF00); - EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x0000FF00); RecordInsertMissSlow(&info, 0x000FF000, 4 * kProbeLength); EXPECT_EQ(info.max_probe_length.load(), 6); EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000F000); EXPECT_EQ(info.hashes_bitwise_or.load(), 0x000FFF00); - EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x000F0F00); RecordInsertMissSlow(&info, 0x00FF0000, 12 * kProbeLength); EXPECT_EQ(info.max_probe_length.load(), 12); EXPECT_EQ(info.hashes_bitwise_and.load(), 0x00000000); EXPECT_EQ(info.hashes_bitwise_or.load(), 0x00FFFF00); - EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x00F00F00); } TEST(HashtablezInfoTest, RecordErase) {
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index 0ef10ef..9955029 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc
@@ -19,6 +19,7 @@ #include <cstddef> #include <cstdint> #include <cstring> +#include <memory> #include <tuple> #include <utility> @@ -763,7 +764,16 @@ void* alloc) { RawHashSetLayout layout(new_capacity, policy.slot_size, policy.slot_align, has_infoz); - char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size())); + // Perform a direct call in the common case to allow for profile-guided + // heap optimization (PGHO) to understand which allocation function is used. + constexpr size_t kDefaultAlignment = BackingArrayAlignment(alignof(size_t)); + char* mem = static_cast<char*>( + ABSL_PREDICT_TRUE( + policy.alloc == + (&AllocateBackingArray<kDefaultAlignment, std::allocator<char>>)) + ? AllocateBackingArray<kDefaultAlignment, std::allocator<char>>( + alloc, layout.alloc_size()) + : policy.alloc(alloc, layout.alloc_size())); const GenerationType old_generation = common.generation(); common.set_generation_ptr( reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 31b117e..1d209e0 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h
@@ -1492,10 +1492,12 @@ // Allocates `n` bytes for a backing array. template <size_t AlignOfBackingArray, typename Alloc> -ABSL_ATTRIBUTE_NOINLINE void* AllocateBackingArray(void* alloc, size_t n) { +void* AllocateBackingArray(void* alloc, size_t n) { return Allocate<AlignOfBackingArray>(static_cast<Alloc*>(alloc), n); } +// Note: we mark this function as ABSL_ATTRIBUTE_NOINLINE because we don't want +// it to be inlined into e.g. the destructor to save code size. template <size_t AlignOfBackingArray, typename Alloc> ABSL_ATTRIBUTE_NOINLINE void DeallocateBackingArray( void* alloc, size_t capacity, ctrl_t* ctrl, size_t slot_size,
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index 8c80463..e8de41a 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc
@@ -2830,8 +2830,6 @@ end_size += sampler.Iterate([&](const HashtablezInfo& info) { ++end_size; if (preexisting_info.contains(&info)) return; - observed_checksums[info.hashes_bitwise_xor.load( - std::memory_order_relaxed)]++; reservations[info.max_reserve.load(std::memory_order_relaxed)]++; hit_misses[std::make_pair( info.num_insert_hits.load(std::memory_order_relaxed), @@ -2851,10 +2849,6 @@ // Expect that we sampled at the requested sampling rate of ~1%. EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()), 0.01, 0.005); - ASSERT_EQ(observed_checksums.size(), 5); - for (const auto& [_, count] : observed_checksums) { - EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.2, 0.05); - } ASSERT_EQ(reservations.size(), 10); for (const auto& [reservation, count] : reservations) {
diff --git a/absl/hash/internal/hash.cc b/absl/hash/internal/hash.cc index 9e43e94..35ab0a2 100644 --- a/absl/hash/internal/hash.cc +++ b/absl/hash/internal/hash.cc
@@ -26,6 +26,20 @@ #include "absl/base/prefetch.h" #include "absl/hash/internal/city.h" + +#ifdef ABSL_AES_INTERNAL_HAVE_X86_SIMD +#error ABSL_AES_INTERNAL_HAVE_X86_SIMD cannot be directly set +#elif defined(__SSE4_2__) && defined(__AES__) +#define ABSL_AES_INTERNAL_HAVE_X86_SIMD +#endif + + +#ifdef ABSL_AES_INTERNAL_HAVE_X86_SIMD +#include <smmintrin.h> +#include <wmmintrin.h> +#include <xmmintrin.h> +#endif // ABSL_AES_INTERNAL_HAVE_X86_SIMD + namespace absl { ABSL_NAMESPACE_BEGIN namespace hash_internal { @@ -43,47 +57,86 @@ return cs0 ^ cs1; } -[[maybe_unused]] uint64_t LowLevelHashLenGt32(const void* data, size_t len, - uint64_t seed) { +#ifdef ABSL_AES_INTERNAL_HAVE_X86_SIMD +uint64_t LowLevelHash33To64(const uint8_t* ptr, size_t len, uint64_t seed) { assert(len > 32); + assert(len <= 64); + __m128i state = + _mm_set_epi64x(static_cast<int64_t>(seed), static_cast<int64_t>(len)); + auto a = _mm_loadu_si128(reinterpret_cast<const __m128i*>(ptr)); + auto b = _mm_loadu_si128(reinterpret_cast<const __m128i*>(ptr + 16)); + auto* last32_ptr = ptr + len - 32; + auto c = _mm_loadu_si128(reinterpret_cast<const __m128i*>(last32_ptr)); + auto d = _mm_loadu_si128(reinterpret_cast<const __m128i*>(last32_ptr + 16)); + + // Bits of the second argument to _mm_aesdec_si128/_mm_aesenc_si128 are + // XORed with the state argument after encryption. + // We use each value as the first argument to shuffle all the bits around. + // We do not add any salt to the state or loaded data, instead we vary + // instructions used to mix bits _mm_aesdec_si128/_mm_aesenc_si128 and + // _mm_add_epi64/_mm_sub_epi64. + // _mm_add_epi64/_mm_sub_epi64 are combined to one instruction with data + // loading like `vpaddq xmm1, xmm0, xmmword ptr [rdi]`. + auto na = _mm_aesdec_si128(_mm_add_epi64(state, a), state); + auto nb = _mm_aesdec_si128(_mm_sub_epi64(state, b), state); + auto nc = _mm_aesenc_si128(_mm_add_epi64(state, c), state); + auto nd = _mm_aesenc_si128(_mm_sub_epi64(state, d), state); + + // We perform another round of encryption to mix bits between two halves of + // the input. + auto res128 = _mm_add_epi64(_mm_aesenc_si128(_mm_add_epi64(na, nc), nd), + _mm_aesdec_si128(_mm_sub_epi64(nb, nd), na)); + auto x64 = static_cast<uint64_t>(_mm_cvtsi128_si64(res128)); + auto y64 = static_cast<uint64_t>(_mm_extract_epi64(res128, 1)); + return x64 ^ y64; +} +#else +uint64_t LowLevelHash33To64(const uint8_t* ptr, size_t len, uint64_t seed) { + assert(len > 32); + assert(len <= 64); + uint64_t current_state = seed ^ kStaticRandomData[0] ^ len; + const uint8_t* last_32_ptr = ptr + len - 32; + return Mix32Bytes(last_32_ptr, Mix32Bytes(ptr, current_state)); +} +#endif // ABSL_AES_INTERNAL_HAVE_X86_SIMD + +[[maybe_unused]] ABSL_ATTRIBUTE_NOINLINE uint64_t +LowLevelHashLenGt64(const void* data, size_t len, uint64_t seed) { + assert(len > 64); const uint8_t* ptr = static_cast<const uint8_t*>(data); uint64_t current_state = seed ^ kStaticRandomData[0] ^ len; const uint8_t* last_32_ptr = ptr + len - 32; + // If we have more than 64 bytes, we're going to handle chunks of 64 + // bytes at a time. We're going to build up four separate hash states + // which we will then hash together. This avoids short dependency chains. + uint64_t duplicated_state0 = current_state; + uint64_t duplicated_state1 = current_state; + uint64_t duplicated_state2 = current_state; - if (len > 64) { - // If we have more than 64 bytes, we're going to handle chunks of 64 - // bytes at a time. We're going to build up four separate hash states - // which we will then hash together. This avoids short dependency chains. - uint64_t duplicated_state0 = current_state; - uint64_t duplicated_state1 = current_state; - uint64_t duplicated_state2 = current_state; + do { + PrefetchToLocalCache(ptr + 5 * ABSL_CACHELINE_SIZE); - do { - PrefetchToLocalCache(ptr + 5 * ABSL_CACHELINE_SIZE); + uint64_t a = absl::base_internal::UnalignedLoad64(ptr); + uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8); + uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16); + uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24); + uint64_t e = absl::base_internal::UnalignedLoad64(ptr + 32); + uint64_t f = absl::base_internal::UnalignedLoad64(ptr + 40); + uint64_t g = absl::base_internal::UnalignedLoad64(ptr + 48); + uint64_t h = absl::base_internal::UnalignedLoad64(ptr + 56); - uint64_t a = absl::base_internal::UnalignedLoad64(ptr); - uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8); - uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16); - uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24); - uint64_t e = absl::base_internal::UnalignedLoad64(ptr + 32); - uint64_t f = absl::base_internal::UnalignedLoad64(ptr + 40); - uint64_t g = absl::base_internal::UnalignedLoad64(ptr + 48); - uint64_t h = absl::base_internal::UnalignedLoad64(ptr + 56); + current_state = Mix(a ^ kStaticRandomData[1], b ^ current_state); + duplicated_state0 = Mix(c ^ kStaticRandomData[2], d ^ duplicated_state0); - current_state = Mix(a ^ kStaticRandomData[1], b ^ current_state); - duplicated_state0 = Mix(c ^ kStaticRandomData[2], d ^ duplicated_state0); + duplicated_state1 = Mix(e ^ kStaticRandomData[3], f ^ duplicated_state1); + duplicated_state2 = Mix(g ^ kStaticRandomData[4], h ^ duplicated_state2); - duplicated_state1 = Mix(e ^ kStaticRandomData[3], f ^ duplicated_state1); - duplicated_state2 = Mix(g ^ kStaticRandomData[4], h ^ duplicated_state2); + ptr += 64; + len -= 64; + } while (len > 64); - ptr += 64; - len -= 64; - } while (len > 64); - - current_state = (current_state ^ duplicated_state0) ^ - (duplicated_state1 + duplicated_state2); - } - + current_state = (current_state ^ duplicated_state0) ^ + (duplicated_state1 + duplicated_state2); // We now have a data `ptr` with at most 64 bytes and the current state // of the hashing state machine stored in current_state. if (len > 32) { @@ -96,6 +149,15 @@ return Mix32Bytes(last_32_ptr, current_state); } +[[maybe_unused]] uint64_t LowLevelHashLenGt32(const void* data, size_t len, + uint64_t seed) { + assert(len > 32); + if (ABSL_PREDICT_FALSE(len > 64)) { + return LowLevelHashLenGt64(data, len, seed); + } + return LowLevelHash33To64(static_cast<const uint8_t*>(data), len, seed); +} + ABSL_ATTRIBUTE_ALWAYS_INLINE inline uint64_t HashBlockOn32Bit( const unsigned char* data, size_t len, uint64_t state) { // TODO(b/417141985): expose and use CityHash32WithSeed.
diff --git a/absl/hash/internal/low_level_hash_test.cc b/absl/hash/internal/low_level_hash_test.cc index 9b7868c..c8573b1 100644 --- a/absl/hash/internal/low_level_hash_test.cc +++ b/absl/hash/internal/low_level_hash_test.cc
@@ -364,6 +364,41 @@ GTEST_SKIP() << "We only maintain golden data for little endian 64 bit systems with " "128 bit intristics."; +#elif defined(__SSE4_2__) && defined(__AES__) + constexpr uint64_t kGolden[kNumGoldenOutputs] = { + 0xd6bdb2c9ba5e55f2, 0xffd3e23d4115a8ae, 0x2c3218ef486127de, + 0x554fa7f3a262b886, 0x06304cbf82e312d3, 0x490b3fb5af80622c, + 0x7398a90b8cc59c5d, 0x65fb3168b98030ab, 0xd4564363c53617bb, + 0x0545c26351925fe7, 0xc30700723b634bf4, 0xfb23a140a76dbe94, + 0x2fa1467fe218a47c, 0x92e05ec3a7b966eb, 0x6112b56e5624dd50, + 0x8760801365f9d722, 0x41f7187b61db0e5e, 0x7fe9188a1f5f50ad, + 0x25800bd4c2002ef1, 0x91fecd33a78ef0aa, 0x93986ad71e983613, + 0xe4c78173c7ea537b, 0x0bbdc2bcabdb50b1, 0xd9aa134df2d87623, + 0x6c4907c9477a9409, 0xc3e418a5dbda52e5, 0x4d24f3e9d0dda93a, + 0xcdb565a363dbe45f, 0xa95f228c8ee57478, 0x6b8f00bab5130227, + 0x2d05a0f44818b67a, 0xa64b55b071afbbea, 0xa205bfe6c724ce4d, + 0x69dd26ca8ac21744, 0xef80e2ff2f6a9bc0, 0xde266c0baa202c20, + 0xfa3463080ac74c50, 0x379d968a40125c2b, 0x4cbbd0a7b3c7d648, + 0xc92afd93f4c665d2, 0x6e28f5adb7ae38dc, 0x7c689c9c237be35e, + 0xaea41b29bd9d0f73, 0x832cef631d77e59f, 0x70cac8e87bc37dd3, + 0x8e8c98bbde68e764, 0xd6117aeb3ddedded, 0xd796ab808e766240, + 0x8953d0ea1a7d9814, 0xa212eba4281b391c, 0x21a555a8939ce597, + 0x809d31660f6d81a8, 0x2356524b20ab400f, 0x5bc611e1e49d0478, + 0xba9c065e2f385ce2, 0xb0a0fd12f4e83899, 0x14d076a35b1ff2ca, + 0x8acd0bb8cf9a93c0, 0xe62e8ec094039ee4, 0x38a536a7072bdc61, + 0xca256297602524f8, 0xfc62ebfb3530caeb, 0x8d8b0c05520569f6, + 0xbbaca65cf154c59d, 0x3739b5ada7e338d3, 0xdb9ea31f47365340, + 0x410b5c9c1da56755, 0x7e0abc03dbd10283, 0x136f87be70ed442e, + 0x6b727d4feddbe1e9, 0x074ebb21183b01df, 0x3fe92185b1985484, + 0xc5d8efd3c68305ca, 0xd9bada21b17e272e, 0x64d73133e1360f83, + 0xeb8563aa993e21f9, 0xe5e8da50cceab28f, 0x7a6f92eb3223d2f3, + 0xbdaf98370ea9b31b, 0x1682a84457f077bc, 0x4abd2d33b6e3be37, + 0xb35bc81a7c9d4c04, 0x3e5bde3fb7cfe63d, 0xff3abe6e2ffec974, + 0xb8116dd26cf6feec, 0x7a77a6e4ed0cf081, 0xb71eec2d5a184316, + 0x6fa932f77b4da817, 0x795f79b33909b2c4, 0x1b8755ef6b5eb34e, + 0x2255b72d7d6b2d79, 0xf2bdafafa90bd50a, 0x442a578f02cb1fc8, + 0xc25aefe55ecf83db, 0x3114c056f9c5a676, + }; #else constexpr uint64_t kGolden[kNumGoldenOutputs] = { 0x669da02f8d009e0f, 0xceb19bf2255445cd, 0x0e746992d6d43a7c,
diff --git a/absl/profiling/hashtable.cc b/absl/profiling/hashtable.cc index 17148d1..7c1a839 100644 --- a/absl/profiling/hashtable.cc +++ b/absl/profiling/hashtable.cc
@@ -70,7 +70,6 @@ const auto key_size_id = builder.InternString("key_size"); const auto value_size_id = builder.InternString("value_size"); const auto soo_capacity_id = builder.InternString("soo_capacity"); - const auto checksum_id = builder.InternString("checksum"); const auto table_age_id = builder.InternString("table_age"); const auto max_reserve_id = builder.InternString("max_reserve"); @@ -106,8 +105,6 @@ add_label(key_size_id, info.key_size); add_label(value_size_id, info.value_size); add_label(soo_capacity_id, info.soo_capacity); - add_label(checksum_id, - info.hashes_bitwise_xor.load(std::memory_order_relaxed)); add_label( table_age_id, static_cast<uint64_t>(ToInt64Microseconds(now - info.create_time)));
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index 49df37c..3176657 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h
@@ -246,6 +246,9 @@ } #endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L + // Deleted constructor from std::nullptr_t from C++23. + string_view(std::nullptr_t) = delete; + constexpr string_view(const string_view&) noexcept = default; string_view& operator=(const string_view&) noexcept = default;
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt index ea91ba3..34a5ad4 100644 --- a/absl/time/CMakeLists.txt +++ b/absl/time/CMakeLists.txt
@@ -77,6 +77,8 @@ "internal/cctz/src/time_zone_posix.h" "internal/cctz/src/tzfile.h" "internal/cctz/src/zone_info_source.cc" + $<$<PLATFORM_ID:Windows>:internal/cctz/src/time_zone_name_win.cc> + $<$<PLATFORM_ID:Windows>:internal/cctz/src/time_zone_name_win.h> COPTS ${ABSL_DEFAULT_COPTS} DEPS
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel index 6e17874..e7e2ee0 100644 --- a/absl/time/internal/cctz/BUILD.bazel +++ b/absl/time/internal/cctz/BUILD.bazel
@@ -59,7 +59,13 @@ "src/time_zone_posix.h", "src/tzfile.h", "src/zone_info_source.cc", - ], + ] + select({ + "@platforms//os:windows": [ + "src/time_zone_name_win.cc", + "src/time_zone_name_win.h", + ], + "//conditions:default": [], + }), hdrs = [ "include/cctz/time_zone.h", "include/cctz/zone_info_source.h",
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc index e8f1d93..d1078de 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -32,31 +32,6 @@ #include <zircon/types.h> #endif -#if defined(_WIN32) -// Include only when <icu.h> is available. -// https://learn.microsoft.com/en-us/windows/win32/intl/international-components-for-unicode--icu- -// https://devblogs.microsoft.com/oldnewthing/20210527-00/?p=105255 -#if defined(__has_include) -#if __has_include(<icu.h>) -#define USE_WIN32_LOCAL_TIME_ZONE -#include <windows.h> -#pragma push_macro("_WIN32_WINNT") -#pragma push_macro("NTDDI_VERSION") -// Minimum _WIN32_WINNT and NTDDI_VERSION to use ucal_getTimeZoneIDForWindowsID -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0A00 // == _WIN32_WINNT_WIN10 -#undef NTDDI_VERSION -#define NTDDI_VERSION 0x0A000004 // == NTDDI_WIN10_RS3 -#include <icu.h> -#pragma pop_macro("NTDDI_VERSION") -#pragma pop_macro("_WIN32_WINNT") -#include <timezoneapi.h> - -#include <atomic> -#endif // __has_include(<icu.h>) -#endif // __has_include -#endif // _WIN32 - #include <array> #include <cstdint> #include <cstdlib> @@ -66,87 +41,15 @@ #include "absl/time/internal/cctz/src/time_zone_fixed.h" #include "absl/time/internal/cctz/src/time_zone_impl.h" +#if defined(_WIN32) +#include "absl/time/internal/cctz/src/time_zone_name_win.h" +#endif // _WIN32 + namespace absl { ABSL_NAMESPACE_BEGIN namespace time_internal { namespace cctz { -namespace { -#if defined(USE_WIN32_LOCAL_TIME_ZONE) -// True if we have already failed to load the API. -static std::atomic_bool g_ucal_getTimeZoneIDForWindowsIDUnavailable; -static std::atomic<decltype(ucal_getTimeZoneIDForWindowsID)*> - g_ucal_getTimeZoneIDForWindowsIDRef; - -std::string win32_local_time_zone() { - // If we have already failed to load the API, then just give up. - if (g_ucal_getTimeZoneIDForWindowsIDUnavailable.load()) { - return ""; - } - - auto ucal_getTimeZoneIDForWindowsIDFunc = - g_ucal_getTimeZoneIDForWindowsIDRef.load(); - if (ucal_getTimeZoneIDForWindowsIDFunc == nullptr) { - // If we have already failed to load the API, then just give up. - if (g_ucal_getTimeZoneIDForWindowsIDUnavailable.load()) { - return ""; - } - - const HMODULE icudll = - ::LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); - - if (icudll == nullptr) { - g_ucal_getTimeZoneIDForWindowsIDUnavailable.store(true); - return ""; - } - - ucal_getTimeZoneIDForWindowsIDFunc = - reinterpret_cast<decltype(ucal_getTimeZoneIDForWindowsID)*>( - ::GetProcAddress(icudll, "ucal_getTimeZoneIDForWindowsID")); - - if (ucal_getTimeZoneIDForWindowsIDFunc == nullptr) { - g_ucal_getTimeZoneIDForWindowsIDUnavailable.store(true); - return ""; - } - // store-race is not a problem here, because ::GetProcAddress() returns the - // same address for the same function in the same DLL. - g_ucal_getTimeZoneIDForWindowsIDRef.store( - ucal_getTimeZoneIDForWindowsIDFunc); - - // We intentionally do not call ::FreeLibrary() here to avoid frequent DLL - // loadings and unloading. As "icu.dll" is a system library, keeping it on - // memory is supposed to have no major drawback. - } - - DYNAMIC_TIME_ZONE_INFORMATION info = {}; - if (::GetDynamicTimeZoneInformation(&info) == TIME_ZONE_ID_INVALID) { - return ""; - } - - std::array<UChar, 128> buffer; - UErrorCode status = U_ZERO_ERROR; - const auto num_chars_in_buffer = ucal_getTimeZoneIDForWindowsIDFunc( - reinterpret_cast<const UChar*>(info.TimeZoneKeyName), -1, nullptr, - buffer.data(), static_cast<int32_t>(buffer.size()), &status); - if (status != U_ZERO_ERROR || num_chars_in_buffer <= 0 || - num_chars_in_buffer > static_cast<int32_t>(buffer.size())) { - return ""; - } - - const int num_bytes_in_utf8 = ::WideCharToMultiByte( - CP_UTF8, 0, reinterpret_cast<const wchar_t*>(buffer.data()), - static_cast<int>(num_chars_in_buffer), nullptr, 0, nullptr, nullptr); - std::string local_time_str; - local_time_str.resize(static_cast<size_t>(num_bytes_in_utf8)); - ::WideCharToMultiByte( - CP_UTF8, 0, reinterpret_cast<const wchar_t*>(buffer.data()), - static_cast<int>(num_chars_in_buffer), &local_time_str[0], - num_bytes_in_utf8, nullptr, nullptr); - return local_time_str; -} -#endif // USE_WIN32_LOCAL_TIME_ZONE -} // namespace - std::string time_zone::name() const { return effective_impl().Name(); } time_zone::absolute_lookup time_zone::lookup( @@ -261,8 +164,8 @@ zone = primary_tz.c_str(); } #endif -#if defined(USE_WIN32_LOCAL_TIME_ZONE) - std::string win32_tz = win32_local_time_zone(); +#if defined(_WIN32) + std::string win32_tz = GetWindowsLocalTimeZone(); if (!win32_tz.empty()) { zone = win32_tz.c_str(); }
diff --git a/absl/time/internal/cctz/src/time_zone_name_win.cc b/absl/time/internal/cctz/src/time_zone_name_win.cc new file mode 100644 index 0000000..c3351cf --- /dev/null +++ b/absl/time/internal/cctz/src/time_zone_name_win.cc
@@ -0,0 +1,187 @@ +// Copyright 2025 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. + +#include "absl/time/internal/cctz/src/time_zone_name_win.h" + +#include "absl/base/config.h" + +#if !defined(NOMINMAX) +#define NOMINMAX +#endif // !defined(NOMINMAX) +#include <windows.h> + +#include <algorithm> +#include <atomic> +#include <cstdint> +#include <limits> +#include <string> +#include <type_traits> +#include <utility> + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { +namespace { + +// Define UChar as wchar_t here because Win32 APIs receive UTF-16 strings as +// wchar_t* instead of char16_t*. Using char16_t would require additional casts. +using UChar = wchar_t; + +enum UErrorCode : std::int32_t { + U_ZERO_ERROR = 0, + U_BUFFER_OVERFLOW_ERROR = 15, +}; + +bool U_SUCCESS(UErrorCode error) { return error <= U_ZERO_ERROR; } + +using ucal_getTimeZoneIDForWindowsID_func = std::int32_t(__cdecl*)( + const UChar* winid, std::int32_t len, const char* region, UChar* id, + std::int32_t id_capacity, UErrorCode* status); + +std::atomic<bool> g_unavailable; +std::atomic<ucal_getTimeZoneIDForWindowsID_func> + g_ucal_getTimeZoneIDForWindowsID; + +template <typename T> +static T AsProcAddress(HMODULE module, const char* name) { + static_assert( + std::is_pointer<T>::value && + std::is_function<typename std::remove_pointer<T>::type>::value, + "T must be a function pointer type"); + const auto proc_address = ::GetProcAddress(module, name); + return reinterpret_cast<T>(reinterpret_cast<void*>(proc_address)); +} + +std::wstring GetSystem32Dir() { + std::wstring result; + std::uint32_t len = std::max<std::uint32_t>( + static_cast<std::uint32_t>(std::min<size_t>( + result.capacity(), std::numeric_limits<std::uint32_t>::max())), + 1); + do { + result.resize(len); + len = ::GetSystemDirectoryW(&result[0], len); + } while (len > result.size()); + result.resize(len); + return result; +} + +ucal_getTimeZoneIDForWindowsID_func LoadIcuGetTimeZoneIDForWindowsID() { + // This function is intended to be lock free to avoid potential deadlocks + // with loader-lock taken inside LoadLibraryW. As LoadLibraryW and + // GetProcAddress are idempotent unless the DLL is unloaded, we just need to + // make sure global variables are read/written atomically, where + // memory_order_relaxed is also acceptable. + + if (g_unavailable.load(std::memory_order_relaxed)) { + return nullptr; + } + + { + const auto ucal_getTimeZoneIDForWindowsIDRef = + g_ucal_getTimeZoneIDForWindowsID.load(std::memory_order_relaxed); + if (ucal_getTimeZoneIDForWindowsIDRef != nullptr) { + return ucal_getTimeZoneIDForWindowsIDRef; + } + } + + const std::wstring system32_dir = GetSystem32Dir(); + if (system32_dir.empty()) { + g_unavailable.store(true, std::memory_order_relaxed); + return nullptr; + } + + // Here LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) does + // not work if "icu.dll" is already loaded from somewhere other than the + // system32 directory. Specifying the full path with LoadLibraryW is more + // reliable. + const std::wstring icu_dll_path = system32_dir + L"\\icu.dll"; + const HMODULE icu_dll = ::LoadLibraryW(icu_dll_path.c_str()); + if (icu_dll == nullptr) { + g_unavailable.store(true, std::memory_order_relaxed); + return nullptr; + } + + const auto ucal_getTimeZoneIDForWindowsIDRef = + AsProcAddress<ucal_getTimeZoneIDForWindowsID_func>( + icu_dll, "ucal_getTimeZoneIDForWindowsID"); + if (ucal_getTimeZoneIDForWindowsIDRef != nullptr) { + g_unavailable.store(true, std::memory_order_relaxed); + return nullptr; + } + + g_ucal_getTimeZoneIDForWindowsID.store(ucal_getTimeZoneIDForWindowsIDRef, + std::memory_order_relaxed); + + return ucal_getTimeZoneIDForWindowsIDRef; +} + +// Convert wchar_t array (UTF-16) to UTF-8 string +std::string Utf16ToUtf8(const wchar_t* ptr, size_t size) { + if (size > std::numeric_limits<int>::max()) { + return std::string(); + } + const int chars_len = static_cast<int>(size); + std::string result; + std::int32_t len = std::max<std::int32_t>( + static_cast<std::int32_t>(std::min<size_t>( + result.capacity(), std::numeric_limits<std::int32_t>::max())), + 1); + do { + result.resize(len); + // TODO: Switch to std::string::data() when we require C++17 or higher. + len = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, chars_len, + &result[0], len, nullptr, nullptr); + } while (len > result.size()); + result.resize(len); + return result; +} + +} // namespace + +std::string GetWindowsLocalTimeZone() { + const auto getTimeZoneIDForWindowsID = LoadIcuGetTimeZoneIDForWindowsID(); + if (getTimeZoneIDForWindowsID == nullptr) { + return std::string(); + } + + DYNAMIC_TIME_ZONE_INFORMATION info = {}; + if (::GetDynamicTimeZoneInformation(&info) == TIME_ZONE_ID_INVALID) { + return std::string(); + } + + std::wstring result; + std::int32_t len = std::max<std::int32_t>( + static_cast<std::int32_t>(std::min<size_t>( + result.capacity(), std::numeric_limits<std::int32_t>::max())), + 1); + for (;;) { + UErrorCode status = U_ZERO_ERROR; + result.resize(len); + len = getTimeZoneIDForWindowsID(info.TimeZoneKeyName, -1, nullptr, + &result[0], len, &status); + if (U_SUCCESS(status)) { + return Utf16ToUtf8(result.data(), len); + } + if (status != U_BUFFER_OVERFLOW_ERROR) { + return std::string(); + } + } +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_name_win.h b/absl/time/internal/cctz/src/time_zone_name_win.h new file mode 100644 index 0000000..f53b5a9 --- /dev/null +++ b/absl/time/internal/cctz/src/time_zone_name_win.h
@@ -0,0 +1,37 @@ +// Copyright 2025 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_TIME_ZONE_NAME_WIN_H_ +#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_NAME_WIN_H_ + +#include <string> + +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// Returns the local time zone ID in IANA format (e.g. "America/Los_Angeles"), +// or the empty string on failure. Not supported on Windows 10 1809 and earlier, +// where "icu.dll" is not available in the System32 directory. +std::string GetWindowsLocalTimeZone(); + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_NAME_WIN_H_
diff --git a/absl/types/span.h b/absl/types/span.h index d2cf627..556c846 100644 --- a/absl/types/span.h +++ b/absl/types/span.h
@@ -47,6 +47,9 @@ // * `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 +// * `absl::Span::subspan(pos, len)` always truncates `len` to +// `size() - pos`, whereas `std::span::subspan()` only truncates when the +// `len` parameter is defaulted. // // For more information, see the class comments below. #ifndef ABSL_TYPES_SPAN_H_ @@ -449,6 +452,11 @@ // 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. // + // Note that trimming behavior differs from `std::span::subspan()`. + // `std::span::subspan()` requires `len == npos || pos + len <= size()`. + // In other words, `std::span::subspan()` only trims `len` when its value is + // defaulted. + // // Examples: // // std::vector<int> vec = {10, 11, 12, 13};
diff --git a/ci/cmake_common.sh b/ci/cmake_common.sh index 484230c..53d3a37 100644 --- a/ci/cmake_common.sh +++ b/ci/cmake_common.sh
@@ -16,4 +16,4 @@ # Keep this in sync with the commit in the MODULE.bazel file. readonly ABSL_GOOGLETEST_VERSION="1.17.0" -readonly ABSL_GOOGLETEST_DOWNLOAD_URL="https://github.com/google/googletest/releases/download/v${ABSL_GOOGLETEST_VERSION}/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" +ABSL_GOOGLETEST_DOWNLOAD_URL="https://github.com/google/googletest/releases/download/v${ABSL_GOOGLETEST_VERSION}/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
diff --git a/ci/cmake_install_test.sh b/ci/cmake_install_test.sh index 871490f..5e3e07b 100755 --- a/ci/cmake_install_test.sh +++ b/ci/cmake_install_test.sh
@@ -26,6 +26,12 @@ source "${ABSEIL_ROOT}/ci/cmake_common.sh" +# Avoid depending on GitHub by looking for a cached copy of GoogleTest. +if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then + ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" + DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}" +fi + source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh" readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
diff --git a/ci/linux_clang-latest_libcxx_asan_bazel.sh b/ci/linux_clang-latest_libcxx_asan_bazel.sh index cfc5510..cea10ff 100755 --- a/ci/linux_clang-latest_libcxx_asan_bazel.sh +++ b/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -81,6 +81,7 @@ --action_env=\"CPLUS_INCLUDE_PATH=/opt/llvm/libcxx/include/c++/v1\" \ --compilation_mode=\"${compilation_mode}\" \ --copt=\"${exceptions_mode}\" \ + --copt=\"-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG\" \ --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \ --copt=\"-fsanitize=address\" \ --copt=\"-fsanitize=${UBSAN_CHECKS}\" \
diff --git a/ci/linux_gcc-latest_libstdcxx_cmake.sh b/ci/linux_gcc-latest_libstdcxx_cmake.sh index d75209b..2f69bba 100755 --- a/ci/linux_gcc-latest_libstdcxx_cmake.sh +++ b/ci/linux_gcc-latest_libstdcxx_cmake.sh
@@ -22,6 +22,12 @@ source "${ABSEIL_ROOT}/ci/cmake_common.sh" +# Avoid depending on GitHub by looking for a cached copy of GoogleTest. +if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then + ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" + DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}" +fi + if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then ABSL_CMAKE_CXX_STANDARDS="17 20" fi
diff --git a/ci/linux_gcc_alpine_cmake.sh b/ci/linux_gcc_alpine_cmake.sh index 7cf25f7..1d64a95 100755 --- a/ci/linux_gcc_alpine_cmake.sh +++ b/ci/linux_gcc_alpine_cmake.sh
@@ -22,6 +22,12 @@ source "${ABSEIL_ROOT}/ci/cmake_common.sh" +# Avoid depending on GitHub by looking for a cached copy of GoogleTest. +if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then + ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" + DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}" +fi + if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then ABSL_CMAKE_CXX_STANDARDS="17" fi
diff --git a/ci/macos_xcode_cmake.sh b/ci/macos_xcode_cmake.sh index 5b11b89..37be939 100755 --- a/ci/macos_xcode_cmake.sh +++ b/ci/macos_xcode_cmake.sh
@@ -31,6 +31,11 @@ source "${ABSEIL_ROOT}/ci/cmake_common.sh" +# Avoid depending on GitHub by looking for a cached copy of GoogleTest. +if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then + ABSL_GOOGLETEST_DOWNLOAD_URL="${KOKORO_GFILE_DIR}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" +fi + if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then ABSL_CMAKE_BUILD_TYPES="Debug" fi
diff --git a/ci/windows_msvc_cmake.bat b/ci/windows_msvc_cmake.bat index 62cdb70..c0083a1 100755 --- a/ci/windows_msvc_cmake.bat +++ b/ci/windows_msvc_cmake.bat
@@ -17,7 +17,12 @@ :: The version of GoogleTest to be used in the CMake tests in this directory. :: Keep this in sync with the version in the WORKSPACE file. SET ABSL_GOOGLETEST_VERSION=1.17.0 -SET ABSL_GOOGLETEST_DOWNLOAD_URL=https://github.com/google/googletest/releases/download/v%ABSL_GOOGLETEST_VERSION%/googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz + +IF EXIST %KOKORO_GFILE_DIR%\distdir\googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz ( + SET ABSL_GOOGLETEST_DOWNLOAD_URL=file://%KOKORO_GFILE_DIR%\distdir\googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz +) ELSE ( + SET ABSL_GOOGLETEST_DOWNLOAD_URL=https://github.com/google/googletest/releases/download/v%ABSL_GOOGLETEST_VERSION%/googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz +) :: Replace '\' with '/' in Windows paths for CMake. :: Note that this cannot go inside the IF block above, because BAT files are weird.