summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--WORKSPACE8
-rw-r--r--absl/base/attributes.h4
-rw-r--r--absl/base/internal/raw_logging.h2
-rw-r--r--absl/base/internal/sysinfo.cc89
-rw-r--r--absl/base/internal/unscaledcycleclock.cc4
-rw-r--r--absl/container/fixed_array.h21
-rw-r--r--absl/container/fixed_array_test.cc16
-rw-r--r--absl/container/internal/raw_hash_set.cc11
-rw-r--r--absl/container/internal/raw_hash_set.h26
-rw-r--r--absl/copts/AbseilConfigureCopts.cmake10
-rw-r--r--absl/debugging/failure_signal_handler.cc10
-rw-r--r--absl/flags/BUILD.bazel1
-rw-r--r--absl/flags/CMakeLists.txt1
-rw-r--r--absl/flags/internal/usage.cc11
-rw-r--r--absl/flags/internal/usage_test.cc63
-rw-r--r--absl/flags/marshalling.cc27
-rw-r--r--absl/flags/marshalling.h3
-rw-r--r--absl/flags/marshalling_test.cc137
-rw-r--r--absl/hash/BUILD.bazel27
-rw-r--r--absl/hash/CMakeLists.txt21
-rw-r--r--absl/hash/hash_instantiated_test.cc224
-rw-r--r--absl/hash/hash_test.cc228
-rw-r--r--absl/hash/internal/hash_test.h87
-rw-r--r--absl/log/internal/globals.cc15
-rw-r--r--absl/status/internal/statusor_internal.h36
-rw-r--r--absl/status/statusor.h8
-rw-r--r--absl/strings/BUILD.bazel12
-rw-r--r--absl/strings/CMakeLists.txt14
-rw-r--r--absl/strings/char_formatting_test.cc189
-rw-r--r--absl/strings/internal/str_split_internal.h62
-rw-r--r--absl/time/CMakeLists.txt1
-rw-r--r--absl/time/clock.cc13
-rw-r--r--absl/time/internal/cctz/src/time_zone_if.cc2
-rw-r--r--absl/time/internal/cctz/src/time_zone_libc.cc61
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup.cc11
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup_test.cc21
36 files changed, 1040 insertions, 436 deletions
diff --git a/WORKSPACE b/WORKSPACE
index ce8e8596..19e1385c 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -28,13 +28,11 @@ http_archive(
)
# RE2 (the regular expression library used by GoogleTest)
-# Note this must use a commit from the `abseil` branch of the RE2 project.
-# https://github.com/google/re2/tree/abseil
http_archive(
name = "com_googlesource_code_re2",
- sha256 = "0a890c2aa0bb05b2ce906a15efb520d0f5ad4c7d37b8db959c43772802991887",
- strip_prefix = "re2-a427f10b9fb4622dd6d8643032600aa1b50fbd12",
- urls = ["https://github.com/google/re2/archive/a427f10b9fb4622dd6d8643032600aa1b50fbd12.zip"], # 2022-06-09
+ sha256 = "1726508efc93a50854c92e3f7ac66eb28f0e57652e413f11d7c1e28f97d997ba",
+ strip_prefix = "re2-03da4fc0857c285e3a26782f6bc8931c4c950df4",
+ urls = ["https://github.com/google/re2/archive/03da4fc0857c285e3a26782f6bc8931c4c950df4.zip"], # 2023-06-01
)
# Google benchmark.
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index 34a35538..cb3f367f 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -695,7 +695,7 @@
// ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
// Baz ComputeBazFromFoo(Foo f);
// ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
-#ifdef __GNUC__
+#if defined(__GNUC__) || defined(__clang__)
// Clang also supports these GCC pragmas.
#define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING \
_Pragma("GCC diagnostic push") \
@@ -705,7 +705,7 @@
#else
#define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
#define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
-#endif // __GNUC__
+#endif // defined(__GNUC__) || defined(__clang__)
// ABSL_CONST_INIT
//
diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h
index e8765254..3f852d31 100644
--- a/absl/base/internal/raw_logging.h
+++ b/absl/base/internal/raw_logging.h
@@ -129,7 +129,7 @@ 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.
+// manner. Preserves errno.
void AsyncSignalSafeWriteToStderr(const char* s, size_t len);
// compile-time function to get the "base" filename, that is, the part of
diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc
index 8429fb90..7de8ead2 100644
--- a/absl/base/internal/sysinfo.cc
+++ b/absl/base/internal/sysinfo.cc
@@ -41,6 +41,7 @@
#include <string.h>
#include <cassert>
+#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
@@ -225,8 +226,8 @@ static int64_t ReadMonotonicClockNanos() {
int rc = clock_gettime(CLOCK_MONOTONIC, &t);
#endif
if (rc != 0) {
- perror("clock_gettime() failed");
- abort();
+ ABSL_INTERNAL_LOG(
+ FATAL, "clock_gettime() failed: (" + std::to_string(errno) + ")");
}
return int64_t{t.tv_sec} * 1000000000 + t.tv_nsec;
}
@@ -414,82 +415,24 @@ pid_t GetTID() {
return tid;
}
-#else
+#elif defined(__APPLE__)
-// Fallback implementation of GetTID using pthread_getspecific.
-ABSL_CONST_INIT static once_flag tid_once;
-ABSL_CONST_INIT static pthread_key_t tid_key;
-ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock(
- absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
-
-// We set a bit per thread in this array to indicate that an ID is in
-// use. ID 0 is unused because it is the default value returned by
-// pthread_getspecific().
-ABSL_CONST_INIT static std::vector<uint32_t> *tid_array
- ABSL_GUARDED_BY(tid_lock) = nullptr;
-static constexpr int kBitsPerWord = 32; // tid_array is uint32_t.
-
-// Returns the TID to tid_array.
-static void FreeTID(void *v) {
- intptr_t tid = reinterpret_cast<intptr_t>(v);
- intptr_t word = tid / kBitsPerWord;
- uint32_t mask = ~(1u << (tid % kBitsPerWord));
- absl::base_internal::SpinLockHolder lock(&tid_lock);
- assert(0 <= word && static_cast<size_t>(word) < tid_array->size());
- (*tid_array)[static_cast<size_t>(word)] &= mask;
+pid_t GetTID() {
+ uint64_t tid;
+ // `nullptr` here implies this thread. This only fails if the specified
+ // thread is invalid or the pointer-to-tid is null, so we needn't worry about
+ // it.
+ pthread_threadid_np(nullptr, &tid);
+ return static_cast<pid_t>(tid);
}
-static void InitGetTID() {
- if (pthread_key_create(&tid_key, FreeTID) != 0) {
- // The logging system calls GetTID() so it can't be used here.
- perror("pthread_key_create failed");
- abort();
- }
-
- // Initialize tid_array.
- absl::base_internal::SpinLockHolder lock(&tid_lock);
- tid_array = new std::vector<uint32_t>(1);
- (*tid_array)[0] = 1; // ID 0 is never-allocated.
-}
+#else
-// Return a per-thread small integer ID from pthread's thread-specific data.
+// Fallback implementation of `GetTID` using `pthread_self`.
pid_t GetTID() {
- absl::call_once(tid_once, InitGetTID);
-
- intptr_t tid = reinterpret_cast<intptr_t>(pthread_getspecific(tid_key));
- if (tid != 0) {
- return static_cast<pid_t>(tid);
- }
-
- int bit; // tid_array[word] = 1u << bit;
- size_t word;
- {
- // Search for the first unused ID.
- absl::base_internal::SpinLockHolder lock(&tid_lock);
- // First search for a word in the array that is not all ones.
- word = 0;
- while (word < tid_array->size() && ~(*tid_array)[word] == 0) {
- ++word;
- }
- if (word == tid_array->size()) {
- tid_array->push_back(0); // No space left, add kBitsPerWord more IDs.
- }
- // Search for a zero bit in the word.
- bit = 0;
- while (bit < kBitsPerWord && (((*tid_array)[word] >> bit) & 1) != 0) {
- ++bit;
- }
- tid =
- static_cast<intptr_t>((word * kBitsPerWord) + static_cast<size_t>(bit));
- (*tid_array)[word] |= 1u << bit; // Mark the TID as allocated.
- }
-
- if (pthread_setspecific(tid_key, reinterpret_cast<void *>(tid)) != 0) {
- perror("pthread_setspecific failed");
- abort();
- }
-
- return static_cast<pid_t>(tid);
+ // `pthread_t` need not be arithmetic per POSIX; platforms where it isn't
+ // should be handled above.
+ return static_cast<pid_t>(pthread_self());
}
#endif
diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc
index 128dc52f..05e0e7ba 100644
--- a/absl/base/internal/unscaledcycleclock.cc
+++ b/absl/base/internal/unscaledcycleclock.cc
@@ -75,8 +75,8 @@ int64_t UnscaledCycleClock::Now() {
"mftb %[lo32]\n"
"mftbu %[tmp]\n"
"cmpw %[tmp],%[hi32]\n"
- "bne $-16\n" // retry on failure
- : [ hi32 ] "=r"(tbu), [ lo32 ] "=r"(tbl), [ tmp ] "=r"(tmp));
+ "bne $-16\n" // Retry on failure.
+ : [hi32] "=r"(tbu), [lo32] "=r"(tbl), [tmp] "=r"(tmp));
return (static_cast<int64_t>(tbu) << 32) | tbl;
#endif
#endif
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h
index e99137a4..9f1c813d 100644
--- a/absl/container/fixed_array.h
+++ b/absl/container/fixed_array.h
@@ -117,14 +117,20 @@ class FixedArray {
(N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
: static_cast<size_type>(N));
- FixedArray(
- const FixedArray& other,
- const allocator_type& a = allocator_type()) noexcept(NoexceptCopyable())
+ FixedArray(const FixedArray& other) noexcept(NoexceptCopyable())
+ : FixedArray(other,
+ AllocatorTraits::select_on_container_copy_construction(
+ other.storage_.alloc())) {}
+
+ FixedArray(const FixedArray& other,
+ const allocator_type& a) noexcept(NoexceptCopyable())
: FixedArray(other.begin(), other.end(), a) {}
- FixedArray(
- FixedArray&& other,
- const allocator_type& a = allocator_type()) noexcept(NoexceptMovable())
+ FixedArray(FixedArray&& other) noexcept(NoexceptMovable())
+ : FixedArray(std::move(other), other.storage_.alloc()) {}
+
+ FixedArray(FixedArray&& other,
+ const allocator_type& a) noexcept(NoexceptMovable())
: FixedArray(std::make_move_iterator(other.begin()),
std::make_move_iterator(other.end()), a) {}
@@ -480,6 +486,9 @@ class FixedArray {
StorageElement* begin() const { return data_; }
StorageElement* end() const { return begin() + size(); }
allocator_type& alloc() { return size_alloc_.template get<1>(); }
+ const allocator_type& alloc() const {
+ return size_alloc_.template get<1>();
+ }
private:
static bool UsingInlinedStorage(size_type n) {
diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc
index 49598e7a..9dbf2a84 100644
--- a/absl/container/fixed_array_test.cc
+++ b/absl/container/fixed_array_test.cc
@@ -768,6 +768,22 @@ TEST(AllocatorSupportTest, SizeValAllocConstructor) {
}
}
+TEST(AllocatorSupportTest, PropagatesStatefulAllocator) {
+ constexpr size_t inlined_size = 4;
+ using Alloc = absl::container_internal::CountingAllocator<int>;
+ using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
+
+ auto len = inlined_size * 2;
+ auto val = 0;
+ int64_t allocated = 0;
+ AllocFxdArr arr(len, val, Alloc(&allocated));
+
+ EXPECT_EQ(allocated, len * sizeof(int));
+
+ AllocFxdArr copy = arr;
+ EXPECT_EQ(allocated, len * sizeof(int) * 2);
+}
+
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
absl::FixedArray<int, 32> a(10);
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc
index b91d5a47..1ccee1ed 100644
--- a/absl/container/internal/raw_hash_set.cc
+++ b/absl/container/internal/raw_hash_set.cc
@@ -107,21 +107,22 @@ FindInfo find_first_non_full_outofline(const CommonFields& common,
return find_first_non_full(common, hash);
}
-// Return address of the ith slot in slots where each slot occupies slot_size.
+// Returns the address of the ith slot in slots where each slot occupies
+// slot_size.
static inline void* SlotAddress(void* slot_array, size_t slot,
size_t slot_size) {
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot_array) +
(slot * slot_size));
}
-// Return the address of the slot just after slot assuming each slot
-// has the specified size.
+// Returns the address of the slot just after slot assuming each slot has the
+// specified size.
static inline void* NextSlot(void* slot, size_t slot_size) {
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) + slot_size);
}
-// Return the address of the slot just before slot assuming each slot
-// has the specified size.
+// Returns the address of the slot just before slot assuming each slot has the
+// specified size.
static inline void* PrevSlot(void* slot, size_t slot_size) {
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) - slot_size);
}
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index df7ff793..2880af70 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -376,12 +376,12 @@ class NonIterableBitMask {
return static_cast<uint32_t>((bit_width(mask_) - 1) >> Shift);
}
- // Return the number of trailing zero *abstract* bits.
+ // Returns the number of trailing zero *abstract* bits.
uint32_t TrailingZeros() const {
return container_internal::TrailingZeros(mask_) >> Shift;
}
- // Return the number of leading zero *abstract* bits.
+ // Returns the number of leading zero *abstract* bits.
uint32_t LeadingZeros() const {
constexpr int total_significant_bits = SignificantBits << Shift;
constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits;
@@ -961,7 +961,7 @@ class CommonFields : public CommonFieldsGenerationInfo {
compressed_tuple_{0u, HashtablezInfoHandle{}};
};
-// Returns he number of "cloned control bytes".
+// Returns the number of "cloned control bytes".
//
// This is the number of control bytes that are present both at the beginning
// of the control byte array and at the end, such that we can create a
@@ -1361,7 +1361,7 @@ ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c, Alloc alloc) {
struct PolicyFunctions {
size_t slot_size;
- // Return the hash of the pointed-to slot.
+ // Returns the hash of the pointed-to slot.
size_t (*hash_slot)(void* set, void* slot);
// Transfer the contents of src_slot to dst_slot.
@@ -1644,9 +1644,9 @@ class raw_hash_set {
// Note: can't use `= default` due to non-default noexcept (causes
// problems for some compilers). NOLINTNEXTLINE
raw_hash_set() noexcept(
- std::is_nothrow_default_constructible<hasher>::value&&
- std::is_nothrow_default_constructible<key_equal>::value&&
- std::is_nothrow_default_constructible<allocator_type>::value) {}
+ std::is_nothrow_default_constructible<hasher>::value &&
+ std::is_nothrow_default_constructible<key_equal>::value &&
+ std::is_nothrow_default_constructible<allocator_type>::value) {}
ABSL_ATTRIBUTE_NOINLINE explicit raw_hash_set(
size_t bucket_count, const hasher& hash = hasher(),
@@ -1772,9 +1772,9 @@ class raw_hash_set {
}
ABSL_ATTRIBUTE_NOINLINE raw_hash_set(raw_hash_set&& that) noexcept(
- std::is_nothrow_copy_constructible<hasher>::value&&
- std::is_nothrow_copy_constructible<key_equal>::value&&
- std::is_nothrow_copy_constructible<allocator_type>::value)
+ std::is_nothrow_copy_constructible<hasher>::value &&
+ std::is_nothrow_copy_constructible<key_equal>::value &&
+ std::is_nothrow_copy_constructible<allocator_type>::value)
: // Hash, equality and allocator are copied instead of moved because
// `that` must be left valid. If Hash is std::function<Key>, moving it
// would create a nullptr functor that cannot be called.
@@ -1803,9 +1803,9 @@ class raw_hash_set {
}
raw_hash_set& operator=(raw_hash_set&& that) noexcept(
- absl::allocator_traits<allocator_type>::is_always_equal::value&&
- std::is_nothrow_move_assignable<hasher>::value&&
- std::is_nothrow_move_assignable<key_equal>::value) {
+ absl::allocator_traits<allocator_type>::is_always_equal::value &&
+ std::is_nothrow_move_assignable<hasher>::value &&
+ std::is_nothrow_move_assignable<key_equal>::value) {
// TODO(sbenza): We should only use the operations from the noexcept clause
// to make sure we actually adhere to that contract.
// NOLINTNEXTLINE: not returning *this for performance.
diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake
index 8209b262..3f737c81 100644
--- a/absl/copts/AbseilConfigureCopts.cmake
+++ b/absl/copts/AbseilConfigureCopts.cmake
@@ -83,6 +83,16 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # MATCHES so we get both Clang an
set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}")
set(ABSL_TEST_COPTS "${ABSL_LLVM_TEST_FLAGS}")
endif()
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
+ # IntelLLVM is similar to Clang, with some additional flags.
+ if(MSVC)
+ # clang-cl is half MSVC, half LLVM
+ set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}")
+ set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_TEST_FLAGS}")
+ else()
+ set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}")
+ set(ABSL_TEST_COPTS "${ABSL_LLVM_TEST_FLAGS}")
+ endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}")
set(ABSL_TEST_COPTS "${ABSL_MSVC_TEST_FLAGS}")
diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc
index 9f399d02..0db2a896 100644
--- a/absl/debugging/failure_signal_handler.cc
+++ b/absl/debugging/failure_signal_handler.cc
@@ -236,10 +236,6 @@ static void InstallOneFailureHandler(FailureSignalData* data,
#endif
-static void WriteToStderr(const char* data) {
- absl::raw_log_internal::AsyncSignalSafeWriteToStderr(data, strlen(data));
-}
-
static void WriteSignalMessage(int signo, int cpu,
void (*writerfn)(const char*)) {
char buf[96];
@@ -380,7 +376,11 @@ static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) {
#endif
// First write to stderr.
- WriteFailureInfo(signo, ucontext, my_cpu, WriteToStderr);
+ WriteFailureInfo(
+ signo, ucontext, my_cpu, +[](const char* data) {
+ absl::raw_log_internal::AsyncSignalSafeWriteToStderr(data,
+ strlen(data));
+ });
// Riskier code (because it is less likely to be async-signal-safe)
// goes after this point.
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 627f453a..583e6d94 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -99,6 +99,7 @@ cc_library(
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:log_severity",
+ "//absl/numeric:int128",
"//absl/strings",
"//absl/strings:str_format",
"//absl/types:optional",
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index b9d3b97b..6525eb2a 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -87,6 +87,7 @@ absl_cc_library(
absl::config
absl::core_headers
absl::log_severity
+ absl::int128
absl::optional
absl::strings
absl::str_format
diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc
index 6a56fce9..13852e14 100644
--- a/absl/flags/internal/usage.cc
+++ b/absl/flags/internal/usage.cc
@@ -92,8 +92,16 @@ class XMLElement {
case '>':
out << "&gt;";
break;
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\t':
+ out << " ";
+ break;
default:
- out << c;
+ if (IsValidXmlCharacter(static_cast<unsigned char>(c))) {
+ out << c;
+ }
break;
}
}
@@ -102,6 +110,7 @@ class XMLElement {
}
private:
+ static bool IsValidXmlCharacter(unsigned char c) { return c >= 0x20; }
absl::string_view tag_;
absl::string_view txt_;
};
diff --git a/absl/flags/internal/usage_test.cc b/absl/flags/internal/usage_test.cc
index c3ab4a42..6847386f 100644
--- a/absl/flags/internal/usage_test.cc
+++ b/absl/flags/internal/usage_test.cc
@@ -39,6 +39,8 @@ ABSL_FLAG(double, usage_reporting_test_flag_03, 1.03,
"usage_reporting_test_flag_03 help message");
ABSL_FLAG(int64_t, usage_reporting_test_flag_04, 1000000000000004L,
"usage_reporting_test_flag_04 help message");
+ABSL_FLAG(std::string, usage_reporting_test_flag_07, "\r\n\f\v\a\b\t ",
+ "usage_reporting_test_flag_07 help \r\n\f\v\a\b\t ");
static const char kTestUsageMessage[] = "Custom usage message";
@@ -203,8 +205,12 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) {
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
@@ -267,8 +273,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpshort) {
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage),
flags::HelpMode::kShort);
- EXPECT_EQ(test_buf.str(),
- R"(usage_test: Custom usage message
+ EXPECT_EQ(
+ test_buf.str(),
+ R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
@@ -285,8 +292,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpshort) {
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
@@ -301,8 +312,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_simple) {
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage),
flags::HelpMode::kImportant);
- EXPECT_EQ(test_buf.str(),
- R"(usage_test: Custom usage message
+ EXPECT_EQ(
+ test_buf.str(),
+ R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
@@ -319,8 +331,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_simple) {
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
@@ -361,8 +377,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) {
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage),
flags::HelpMode::kMatch);
- EXPECT_EQ(test_buf.str(),
- R"(usage_test: Custom usage message
+ EXPECT_EQ(
+ test_buf.str(),
+ R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
@@ -379,8 +396,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) {
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
@@ -395,8 +416,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_helppackage) {
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage),
flags::HelpMode::kPackage);
- EXPECT_EQ(test_buf.str(),
- R"(usage_test: Custom usage message
+ EXPECT_EQ(
+ test_buf.str(),
+ R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
@@ -413,8 +435,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_helppackage) {
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
@@ -471,8 +497,9 @@ path.
std::stringstream test_buf_02;
EXPECT_EQ(flags::HandleUsageFlags(test_buf_02, kTestUsageMessage),
flags::HelpMode::kMatch);
- EXPECT_EQ(test_buf_02.str(),
- R"(usage_test: Custom usage message
+ EXPECT_EQ(
+ test_buf_02.str(),
+ R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
@@ -489,8 +516,12 @@ path.
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
diff --git a/absl/flags/marshalling.cc b/absl/flags/marshalling.cc
index 81f9cebd..cf6312b1 100644
--- a/absl/flags/marshalling.cc
+++ b/absl/flags/marshalling.cc
@@ -26,6 +26,7 @@
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/base/macros.h"
+#include "absl/numeric/int128.h"
#include "absl/strings/ascii.h"
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
@@ -125,6 +126,32 @@ bool AbslParseFlag(absl::string_view text, unsigned long long* dst,
return ParseFlagImpl(text, *dst);
}
+bool AbslParseFlag(absl::string_view text, absl::int128* dst, std::string*) {
+ text = absl::StripAsciiWhitespace(text);
+
+ // check hex
+ int base = NumericBase(text);
+ if (!absl::numbers_internal::safe_strto128_base(text, dst, base)) {
+ return false;
+ }
+
+ return base == 16 ? absl::SimpleHexAtoi(text, dst)
+ : absl::SimpleAtoi(text, dst);
+}
+
+bool AbslParseFlag(absl::string_view text, absl::uint128* dst, std::string*) {
+ text = absl::StripAsciiWhitespace(text);
+
+ // check hex
+ int base = NumericBase(text);
+ if (!absl::numbers_internal::safe_strtou128_base(text, dst, base)) {
+ return false;
+ }
+
+ return base == 16 ? absl::SimpleHexAtoi(text, dst)
+ : absl::SimpleAtoi(text, dst);
+}
+
// --------------------------------------------------------------------
// AbslParseFlag for floating point types.
diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h
index 325e75e5..21d955d5 100644
--- a/absl/flags/marshalling.h
+++ b/absl/flags/marshalling.h
@@ -200,6 +200,7 @@
#define ABSL_FLAGS_MARSHALLING_H_
#include "absl/base/config.h"
+#include "absl/numeric/int128.h"
#if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL)
#include <optional>
@@ -233,6 +234,8 @@ bool AbslParseFlag(absl::string_view, unsigned long*, std::string*); // NOLINT
bool AbslParseFlag(absl::string_view, long long*, std::string*); // NOLINT
bool AbslParseFlag(absl::string_view, unsigned long long*, // NOLINT
std::string*);
+bool AbslParseFlag(absl::string_view, absl::int128*, std::string*); // NOLINT
+bool AbslParseFlag(absl::string_view, absl::uint128*, std::string*); // NOLINT
bool AbslParseFlag(absl::string_view, float*, std::string*);
bool AbslParseFlag(absl::string_view, double*, std::string*);
bool AbslParseFlag(absl::string_view, std::string*, std::string*);
diff --git a/absl/flags/marshalling_test.cc b/absl/flags/marshalling_test.cc
index 7b6d2ad5..d996ca7f 100644
--- a/absl/flags/marshalling_test.cc
+++ b/absl/flags/marshalling_test.cc
@@ -455,6 +455,143 @@ TEST(MarshallingTest, TestUInt64Parsing) {
// --------------------------------------------------------------------
+TEST(MarshallingTest, TestInt128Parsing) {
+ std::string err;
+ absl::int128 value;
+
+ absl::int128 zero = 0;
+ absl::int128 one = 1;
+ absl::int128 neg_one = -1;
+ absl::int128 hundred = 100;
+ absl::int128 hundreds_val = 123;
+ absl::int128 neg_thousands_val = -98765;
+ absl::int128 pos_three = 3;
+
+ // Decimal values.
+ EXPECT_TRUE(absl::ParseFlag("0", &value, &err));
+ EXPECT_EQ(value, zero);
+ EXPECT_TRUE(absl::ParseFlag("1", &value, &err));
+ EXPECT_EQ(value, one);
+ EXPECT_TRUE(absl::ParseFlag("-1", &value, &err));
+ EXPECT_EQ(value, neg_one);
+ EXPECT_TRUE(absl::ParseFlag("123", &value, &err));
+ EXPECT_EQ(value, hundreds_val);
+ EXPECT_TRUE(absl::ParseFlag("-98765", &value, &err));
+ EXPECT_EQ(value, neg_thousands_val);
+ EXPECT_TRUE(absl::ParseFlag("+3", &value, &err));
+ EXPECT_EQ(value, pos_three);
+
+ // Leading zero values.
+ EXPECT_TRUE(absl::ParseFlag("01", &value, &err));
+ EXPECT_EQ(value, one);
+ EXPECT_TRUE(absl::ParseFlag("001", &value, &err));
+ EXPECT_EQ(value, one);
+ EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err));
+ EXPECT_EQ(value, hundred);
+
+ absl::int128 sixteen = 16;
+ absl::int128 quintillion_val = 1152827684197027293;
+ absl::int128 quintillion_val2 =
+ absl::MakeInt128(0x000000000000fff, 0xFFFFFFFFFFFFFFF);
+
+ // Hex values.
+ EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err));
+ EXPECT_EQ(value, sixteen);
+ EXPECT_TRUE(absl::ParseFlag("0xFFFAAABBBCCCDDD", &value, &err));
+ EXPECT_EQ(value, quintillion_val);
+ EXPECT_TRUE(absl::ParseFlag("0xFFF0FFFFFFFFFFFFFFF", &value, &err));
+ EXPECT_EQ(value, quintillion_val2);
+
+ // TODO(b/285183223): Add support for parsing negative hex representation
+
+ // Whitespace handling
+ EXPECT_TRUE(absl::ParseFlag("16 ", &value, &err));
+ EXPECT_EQ(value, sixteen);
+ EXPECT_TRUE(absl::ParseFlag(" 16", &value, &err));
+ EXPECT_EQ(value, sixteen);
+ EXPECT_TRUE(absl::ParseFlag(" 0100 ", &value, &err));
+ EXPECT_EQ(value, hundred);
+ EXPECT_TRUE(absl::ParseFlag(" 0x7B ", &value, &err));
+ EXPECT_EQ(value, hundreds_val); // =123
+
+ // Invalid values.
+ EXPECT_FALSE(absl::ParseFlag("", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("--1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("2U", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err));
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestUint128Parsing) {
+ std::string err;
+ absl::uint128 value;
+
+ absl::uint128 zero = 0;
+ absl::uint128 one = 1;
+ absl::uint128 hundred = 100;
+ absl::uint128 hundreds_val = 123;
+ absl::uint128 pos_three = 3;
+
+ // Decimal values.
+ EXPECT_TRUE(absl::ParseFlag("0", &value, &err));
+ EXPECT_EQ(value, zero);
+ EXPECT_TRUE(absl::ParseFlag("1", &value, &err));
+ EXPECT_EQ(value, one);
+ EXPECT_TRUE(absl::ParseFlag("123", &value, &err));
+ EXPECT_EQ(value, hundreds_val);
+ EXPECT_TRUE(absl::ParseFlag("+3", &value, &err));
+ EXPECT_EQ(value, pos_three);
+
+ // Leading zero values.
+ EXPECT_TRUE(absl::ParseFlag("01", &value, &err));
+ EXPECT_EQ(value, one);
+ EXPECT_TRUE(absl::ParseFlag("001", &value, &err));
+ EXPECT_EQ(value, one);
+ EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err));
+ EXPECT_EQ(value, hundred);
+
+ absl::uint128 sixteen = 16;
+ absl::uint128 quintillion_val = 1152827684197027293;
+ absl::uint128 quintillion_val2 =
+ absl::MakeInt128(0x000000000000fff, 0xFFFFFFFFFFFFFFF);
+
+ // Hex values.
+ EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err));
+ EXPECT_EQ(value, sixteen);
+ EXPECT_TRUE(absl::ParseFlag("0xFFFAAABBBCCCDDD", &value, &err));
+ EXPECT_EQ(value, quintillion_val);
+ EXPECT_TRUE(absl::ParseFlag("0xFFF0FFFFFFFFFFFFFFF", &value, &err));
+ EXPECT_EQ(value, quintillion_val2);
+
+ // Whitespace handling
+ EXPECT_TRUE(absl::ParseFlag("16 ", &value, &err));
+ EXPECT_EQ(value, sixteen);
+ EXPECT_TRUE(absl::ParseFlag(" 16", &value, &err));
+ EXPECT_EQ(value, sixteen);
+ EXPECT_TRUE(absl::ParseFlag(" 0100 ", &value, &err));
+ EXPECT_EQ(value, hundred);
+ EXPECT_TRUE(absl::ParseFlag(" 0x7B ", &value, &err));
+ EXPECT_EQ(value, hundreds_val); // =123
+
+ // Invalid values.
+ EXPECT_FALSE(absl::ParseFlag("", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("-1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("--1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("2U", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err));
+}
+
+// --------------------------------------------------------------------
+
TEST(MarshallingTest, TestFloatParsing) {
std::string err;
float value;
diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel
index a0db919b..7f964ae7 100644
--- a/absl/hash/BUILD.bazel
+++ b/absl/hash/BUILD.bazel
@@ -68,13 +68,17 @@ cc_library(
cc_test(
name = "hash_test",
- srcs = ["hash_test.cc"],
+ srcs = [
+ "hash_test.cc",
+ "internal/hash_test.h",
+ ],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash",
":hash_testing",
":spy_hash_state",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/container:btree",
"//absl/container:flat_hash_map",
@@ -88,6 +92,27 @@ cc_test(
],
)
+cc_test(
+ name = "hash_instantiated_test",
+ srcs = [
+ "hash_instantiated_test.cc",
+ "internal/hash_test.h",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":hash",
+ ":hash_testing",
+ "//absl/base:config",
+ "//absl/container:btree",
+ "//absl/container:flat_hash_map",
+ "//absl/container:flat_hash_set",
+ "//absl/container:node_hash_map",
+ "//absl/container:node_hash_set",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
cc_binary(
name = "hash_benchmark",
testonly = 1,
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt
index f99f35bc..1adce617 100644
--- a/absl/hash/CMakeLists.txt
+++ b/absl/hash/CMakeLists.txt
@@ -64,6 +64,7 @@ absl_cc_test(
hash_test
SRCS
"hash_test.cc"
+ "internal/hash_test.h"
COPTS
${ABSL_TEST_COPTS}
DEPS
@@ -82,6 +83,26 @@ absl_cc_test(
GTest::gmock_main
)
+absl_cc_test(
+ NAME
+ hash_instantiated_test
+ SRCS
+ "hash_test.cc"
+ "internal/hash_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::hash
+ absl::hash_testing
+ absl::config
+ absl::btree
+ absl::flat_hash_map
+ absl::flat_hash_set
+ absl::node_hash_map
+ absl::node_hash_set
+ GTest::gtest_main
+)
+
# Internal-only target, do not depend on directly.
#
# Note: Even though external code should not depend on this target
diff --git a/absl/hash/hash_instantiated_test.cc b/absl/hash/hash_instantiated_test.cc
new file mode 100644
index 00000000..e65de9ca
--- /dev/null
+++ b/absl/hash/hash_instantiated_test.cc
@@ -0,0 +1,224 @@
+// 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.
+
+// This file contains a few select absl::Hash tests that, due to their reliance
+// on INSTANTIATE_TYPED_TEST_SUITE_P, require a large amount of memory to
+// compile. Put new tests in hash_test.cc, not this file.
+
+#include "absl/hash/hash.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <deque>
+#include <forward_list>
+#include <initializer_list>
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/container/btree_map.h"
+#include "absl/container/btree_set.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/container/flat_hash_set.h"
+#include "absl/container/node_hash_map.h"
+#include "absl/container/node_hash_set.h"
+#include "absl/hash/hash_testing.h"
+#include "absl/hash/internal/hash_test.h"
+
+namespace {
+
+using ::absl::hash_test_internal::is_hashable;
+using ::absl::hash_test_internal::TypeErasedContainer;
+
+// Dummy type with unordered equality and hashing semantics. This preserves
+// input order internally, and is used below to ensure we get test coverage
+// for equal sequences with different iteraton orders.
+template <typename T>
+class UnorderedSequence {
+ public:
+ UnorderedSequence() = default;
+ template <typename TT>
+ UnorderedSequence(std::initializer_list<TT> l)
+ : values_(l.begin(), l.end()) {}
+ template <typename ForwardIterator,
+ typename std::enable_if<!std::is_integral<ForwardIterator>::value,
+ bool>::type = true>
+ UnorderedSequence(ForwardIterator begin, ForwardIterator end)
+ : values_(begin, end) {}
+ // one-argument constructor of value type T, to appease older toolchains that
+ // get confused by one-element initializer lists in some contexts
+ explicit UnorderedSequence(const T& v) : values_(&v, &v + 1) {}
+
+ using value_type = T;
+
+ size_t size() const { return values_.size(); }
+ typename std::vector<T>::const_iterator begin() const {
+ return values_.begin();
+ }
+ typename std::vector<T>::const_iterator end() const { return values_.end(); }
+
+ friend bool operator==(const UnorderedSequence& lhs,
+ const UnorderedSequence& rhs) {
+ return lhs.size() == rhs.size() &&
+ std::is_permutation(lhs.begin(), lhs.end(), rhs.begin());
+ }
+ friend bool operator!=(const UnorderedSequence& lhs,
+ const UnorderedSequence& rhs) {
+ return !(lhs == rhs);
+ }
+ template <typename H>
+ friend H AbslHashValue(H h, const UnorderedSequence& u) {
+ return H::combine(H::combine_unordered(std::move(h), u.begin(), u.end()),
+ u.size());
+ }
+
+ private:
+ std::vector<T> values_;
+};
+
+template <typename T>
+class HashValueSequenceTest : public testing::Test {};
+TYPED_TEST_SUITE_P(HashValueSequenceTest);
+
+TYPED_TEST_P(HashValueSequenceTest, BasicUsage) {
+ EXPECT_TRUE((is_hashable<TypeParam>::value));
+
+ using IntType = typename TypeParam::value_type;
+ auto a = static_cast<IntType>(0);
+ auto b = static_cast<IntType>(23);
+ auto c = static_cast<IntType>(42);
+
+ std::vector<TypeParam> exemplars = {
+ TypeParam(), TypeParam(), TypeParam{a, b, c},
+ TypeParam{a, c, b}, TypeParam{c, a, b}, TypeParam{a},
+ TypeParam{a, a}, TypeParam{a, a, a}, TypeParam{a, a, b},
+ TypeParam{a, b, a}, TypeParam{b, a, a}, TypeParam{a, b},
+ TypeParam{b, c}};
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars));
+}
+
+REGISTER_TYPED_TEST_SUITE_P(HashValueSequenceTest, BasicUsage);
+using IntSequenceTypes = testing::Types<
+ std::deque<int>, std::forward_list<int>, std::list<int>, std::vector<int>,
+ std::vector<bool>, TypeErasedContainer<std::vector<int>>, std::set<int>,
+ std::multiset<int>, UnorderedSequence<int>,
+ TypeErasedContainer<UnorderedSequence<int>>, std::unordered_set<int>,
+ std::unordered_multiset<int>, absl::flat_hash_set<int>,
+ absl::node_hash_set<int>, absl::btree_set<int>>;
+INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueSequenceTest, IntSequenceTypes);
+
+template <typename T>
+class HashValueNestedSequenceTest : public testing::Test {};
+TYPED_TEST_SUITE_P(HashValueNestedSequenceTest);
+
+TYPED_TEST_P(HashValueNestedSequenceTest, BasicUsage) {
+ using T = TypeParam;
+ using V = typename T::value_type;
+ std::vector<T> exemplars = {
+ // empty case
+ T{},
+ // sets of empty sets
+ T{V{}}, T{V{}, V{}}, T{V{}, V{}, V{}},
+ // multisets of different values
+ T{V{1}}, T{V{1, 1}, V{1, 1}}, T{V{1, 1, 1}, V{1, 1, 1}, V{1, 1, 1}},
+ // various orderings of same nested sets
+ T{V{}, V{1, 2}}, T{V{}, V{2, 1}}, T{V{1, 2}, V{}}, T{V{2, 1}, V{}},
+ // various orderings of various nested sets, case 2
+ T{V{1, 2}, V{3, 4}}, T{V{1, 2}, V{4, 3}}, T{V{1, 3}, V{2, 4}},
+ T{V{1, 3}, V{4, 2}}, T{V{1, 4}, V{2, 3}}, T{V{1, 4}, V{3, 2}},
+ T{V{2, 3}, V{1, 4}}, T{V{2, 3}, V{4, 1}}, T{V{2, 4}, V{1, 3}},
+ T{V{2, 4}, V{3, 1}}, T{V{3, 4}, V{1, 2}}, T{V{3, 4}, V{2, 1}}};
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars));
+}
+
+REGISTER_TYPED_TEST_SUITE_P(HashValueNestedSequenceTest, BasicUsage);
+template <typename T>
+using TypeErasedSet = TypeErasedContainer<UnorderedSequence<T>>;
+
+using NestedIntSequenceTypes = testing::Types<
+ std::vector<std::vector<int>>, std::vector<UnorderedSequence<int>>,
+ std::vector<TypeErasedSet<int>>, UnorderedSequence<std::vector<int>>,
+ UnorderedSequence<UnorderedSequence<int>>,
+ UnorderedSequence<TypeErasedSet<int>>, TypeErasedSet<std::vector<int>>,
+ TypeErasedSet<UnorderedSequence<int>>, TypeErasedSet<TypeErasedSet<int>>>;
+INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueNestedSequenceTest,
+ NestedIntSequenceTypes);
+
+template <typename T>
+class HashValueAssociativeMapTest : public testing::Test {};
+TYPED_TEST_SUITE_P(HashValueAssociativeMapTest);
+
+TYPED_TEST_P(HashValueAssociativeMapTest, BasicUsage) {
+ using M = TypeParam;
+ using V = typename M::value_type;
+ std::vector<M> exemplars{M{},
+ M{V{0, "foo"}},
+ M{V{1, "foo"}},
+ M{V{0, "bar"}},
+ M{V{1, "bar"}},
+ M{V{0, "foo"}, V{42, "bar"}},
+ M{V{42, "bar"}, V{0, "foo"}},
+ M{V{1, "foo"}, V{42, "bar"}},
+ M{V{1, "foo"}, V{43, "bar"}},
+ M{V{1, "foo"}, V{43, "baz"}}};
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars));
+}
+
+REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMapTest, BasicUsage);
+using AssociativeMapTypes = testing::Types<
+ std::map<int, std::string>, std::unordered_map<int, std::string>,
+ absl::flat_hash_map<int, std::string>,
+ absl::node_hash_map<int, std::string>, absl::btree_map<int, std::string>,
+ UnorderedSequence<std::pair<const int, std::string>>>;
+INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMapTest,
+ AssociativeMapTypes);
+
+template <typename T>
+class HashValueAssociativeMultimapTest : public testing::Test {};
+TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest);
+
+TYPED_TEST_P(HashValueAssociativeMultimapTest, BasicUsage) {
+ using MM = TypeParam;
+ using V = typename MM::value_type;
+ std::vector<MM> exemplars{MM{},
+ MM{V{0, "foo"}},
+ MM{V{1, "foo"}},
+ MM{V{0, "bar"}},
+ MM{V{1, "bar"}},
+ MM{V{0, "foo"}, V{0, "bar"}},
+ MM{V{0, "bar"}, V{0, "foo"}},
+ MM{V{0, "foo"}, V{42, "bar"}},
+ MM{V{1, "foo"}, V{42, "bar"}},
+ MM{V{1, "foo"}, V{1, "foo"}, V{43, "bar"}},
+ MM{V{1, "foo"}, V{43, "bar"}, V{1, "foo"}},
+ MM{V{1, "foo"}, V{43, "baz"}}};
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars));
+}
+
+REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest, BasicUsage);
+using AssociativeMultimapTypes =
+ testing::Types<std::multimap<int, std::string>,
+ std::unordered_multimap<int, std::string>>;
+INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMultimapTest,
+ AssociativeMultimapTypes);
+
+} // namespace
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index 6727dafa..a0e2e4a7 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -48,6 +48,7 @@
#include "absl/container/node_hash_map.h"
#include "absl/container/node_hash_set.h"
#include "absl/hash/hash_testing.h"
+#include "absl/hash/internal/hash_test.h"
#include "absl/hash/internal/spy_hash_state.h"
#include "absl/meta/type_traits.h"
#include "absl/numeric/int128.h"
@@ -59,52 +60,9 @@
namespace {
-// Utility wrapper of T for the purposes of testing the `AbslHash` type erasure
-// mechanism. `TypeErasedValue<T>` can be constructed with a `T`, and can
-// be compared and hashed. However, all hashing goes through the hashing
-// type-erasure framework.
-template <typename T>
-class TypeErasedValue {
- public:
- TypeErasedValue() = default;
- TypeErasedValue(const TypeErasedValue&) = default;
- TypeErasedValue(TypeErasedValue&&) = default;
- explicit TypeErasedValue(const T& n) : n_(n) {}
-
- template <typename H>
- friend H AbslHashValue(H hash_state, const TypeErasedValue& v) {
- v.HashValue(absl::HashState::Create(&hash_state));
- return hash_state;
- }
-
- void HashValue(absl::HashState state) const {
- absl::HashState::combine(std::move(state), n_);
- }
-
- bool operator==(const TypeErasedValue& rhs) const { return n_ == rhs.n_; }
- bool operator!=(const TypeErasedValue& rhs) const { return !(*this == rhs); }
-
- private:
- T n_;
-};
-
-// A TypeErasedValue refinement, for containers. It exposes the wrapped
-// `value_type` and is constructible from an initializer list.
-template <typename T>
-class TypeErasedContainer : public TypeErasedValue<T> {
- public:
- using value_type = typename T::value_type;
- TypeErasedContainer() = default;
- TypeErasedContainer(const TypeErasedContainer&) = default;
- TypeErasedContainer(TypeErasedContainer&&) = default;
- explicit TypeErasedContainer(const T& n) : TypeErasedValue<T>(n) {}
- TypeErasedContainer(std::initializer_list<value_type> init_list)
- : TypeErasedContainer(T(init_list.begin(), init_list.end())) {}
- // one-argument constructor of value type T, to appease older toolchains that
- // get confused by one-element initializer lists in some contexts
- explicit TypeErasedContainer(const value_type& v)
- : TypeErasedContainer(T(&v, &v + 1)) {}
-};
+using ::absl::hash_test_internal::is_hashable;
+using ::absl::hash_test_internal::TypeErasedContainer;
+using ::absl::hash_test_internal::TypeErasedValue;
template <typename T>
using TypeErasedVector = TypeErasedContainer<std::vector<T>>;
@@ -122,11 +80,6 @@ SpyHashState SpyHash(const T& value) {
return SpyHashState::combine(SpyHashState(), value);
}
-// Helper trait to verify if T is hashable. We use absl::Hash's poison status to
-// detect it.
-template <typename T>
-using is_hashable = std::is_default_constructible<absl::Hash<T>>;
-
TYPED_TEST_P(HashValueIntTest, BasicUsage) {
EXPECT_TRUE((is_hashable<TypeParam>::value));
@@ -566,121 +519,6 @@ TEST(HashValueTest, StdBitset) {
std::bitset<kNumBits>(bit_strings[5].c_str())}));
} // namespace
-// Dummy type with unordered equality and hashing semantics. This preserves
-// input order internally, and is used below to ensure we get test coverage
-// for equal sequences with different iteraton orders.
-template <typename T>
-class UnorderedSequence {
- public:
- UnorderedSequence() = default;
- template <typename TT>
- UnorderedSequence(std::initializer_list<TT> l)
- : values_(l.begin(), l.end()) {}
- template <typename ForwardIterator,
- typename std::enable_if<!std::is_integral<ForwardIterator>::value,
- bool>::type = true>
- UnorderedSequence(ForwardIterator begin, ForwardIterator end)
- : values_(begin, end) {}
- // one-argument constructor of value type T, to appease older toolchains that
- // get confused by one-element initializer lists in some contexts
- explicit UnorderedSequence(const T& v) : values_(&v, &v + 1) {}
-
- using value_type = T;
-
- size_t size() const { return values_.size(); }
- typename std::vector<T>::const_iterator begin() const {
- return values_.begin();
- }
- typename std::vector<T>::const_iterator end() const { return values_.end(); }
-
- friend bool operator==(const UnorderedSequence& lhs,
- const UnorderedSequence& rhs) {
- return lhs.size() == rhs.size() &&
- std::is_permutation(lhs.begin(), lhs.end(), rhs.begin());
- }
- friend bool operator!=(const UnorderedSequence& lhs,
- const UnorderedSequence& rhs) {
- return !(lhs == rhs);
- }
- template <typename H>
- friend H AbslHashValue(H h, const UnorderedSequence& u) {
- return H::combine(H::combine_unordered(std::move(h), u.begin(), u.end()),
- u.size());
- }
-
- private:
- std::vector<T> values_;
-};
-
-template <typename T>
-class HashValueSequenceTest : public testing::Test {
-};
-TYPED_TEST_SUITE_P(HashValueSequenceTest);
-
-TYPED_TEST_P(HashValueSequenceTest, BasicUsage) {
- EXPECT_TRUE((is_hashable<TypeParam>::value));
-
- using IntType = typename TypeParam::value_type;
- auto a = static_cast<IntType>(0);
- auto b = static_cast<IntType>(23);
- auto c = static_cast<IntType>(42);
-
- std::vector<TypeParam> exemplars = {
- TypeParam(), TypeParam(), TypeParam{a, b, c},
- TypeParam{a, c, b}, TypeParam{c, a, b}, TypeParam{a},
- TypeParam{a, a}, TypeParam{a, a, a}, TypeParam{a, a, b},
- TypeParam{a, b, a}, TypeParam{b, a, a}, TypeParam{a, b},
- TypeParam{b, c}};
- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars));
-}
-
-REGISTER_TYPED_TEST_SUITE_P(HashValueSequenceTest, BasicUsage);
-using IntSequenceTypes = testing::Types<
- std::deque<int>, std::forward_list<int>, std::list<int>, std::vector<int>,
- std::vector<bool>, TypeErasedContainer<std::vector<int>>, std::set<int>,
- std::multiset<int>, UnorderedSequence<int>,
- TypeErasedContainer<UnorderedSequence<int>>, std::unordered_set<int>,
- std::unordered_multiset<int>, absl::flat_hash_set<int>,
- absl::node_hash_set<int>, absl::btree_set<int>>;
-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueSequenceTest, IntSequenceTypes);
-
-template <typename T>
-class HashValueNestedSequenceTest : public testing::Test {};
-TYPED_TEST_SUITE_P(HashValueNestedSequenceTest);
-
-TYPED_TEST_P(HashValueNestedSequenceTest, BasicUsage) {
- using T = TypeParam;
- using V = typename T::value_type;
- std::vector<T> exemplars = {
- // empty case
- T{},
- // sets of empty sets
- T{V{}}, T{V{}, V{}}, T{V{}, V{}, V{}},
- // multisets of different values
- T{V{1}}, T{V{1, 1}, V{1, 1}}, T{V{1, 1, 1}, V{1, 1, 1}, V{1, 1, 1}},
- // various orderings of same nested sets
- T{V{}, V{1, 2}}, T{V{}, V{2, 1}}, T{V{1, 2}, V{}}, T{V{2, 1}, V{}},
- // various orderings of various nested sets, case 2
- T{V{1, 2}, V{3, 4}}, T{V{1, 2}, V{4, 3}}, T{V{1, 3}, V{2, 4}},
- T{V{1, 3}, V{4, 2}}, T{V{1, 4}, V{2, 3}}, T{V{1, 4}, V{3, 2}},
- T{V{2, 3}, V{1, 4}}, T{V{2, 3}, V{4, 1}}, T{V{2, 4}, V{1, 3}},
- T{V{2, 4}, V{3, 1}}, T{V{3, 4}, V{1, 2}}, T{V{3, 4}, V{2, 1}}};
- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars));
-}
-
-REGISTER_TYPED_TEST_SUITE_P(HashValueNestedSequenceTest, BasicUsage);
-template <typename T>
-using TypeErasedSet = TypeErasedContainer<UnorderedSequence<T>>;
-
-using NestedIntSequenceTypes = testing::Types<
- std::vector<std::vector<int>>, std::vector<UnorderedSequence<int>>,
- std::vector<TypeErasedSet<int>>, UnorderedSequence<std::vector<int>>,
- UnorderedSequence<UnorderedSequence<int>>,
- UnorderedSequence<TypeErasedSet<int>>, TypeErasedSet<std::vector<int>>,
- TypeErasedSet<UnorderedSequence<int>>, TypeErasedSet<TypeErasedSet<int>>>;
-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueNestedSequenceTest,
- NestedIntSequenceTypes);
-
// Private type that only supports AbslHashValue to make sure our chosen hash
// implementation is recursive within absl::Hash.
// It uses std::abs() on the value to provide different bitwise representations
@@ -839,64 +677,6 @@ TEST(HashValueTest, Variant) {
#endif
}
-template <typename T>
-class HashValueAssociativeMapTest : public testing::Test {};
-TYPED_TEST_SUITE_P(HashValueAssociativeMapTest);
-
-TYPED_TEST_P(HashValueAssociativeMapTest, BasicUsage) {
- using M = TypeParam;
- using V = typename M::value_type;
- std::vector<M> exemplars{M{},
- M{V{0, "foo"}},
- M{V{1, "foo"}},
- M{V{0, "bar"}},
- M{V{1, "bar"}},
- M{V{0, "foo"}, V{42, "bar"}},
- M{V{42, "bar"}, V{0, "foo"}},
- M{V{1, "foo"}, V{42, "bar"}},
- M{V{1, "foo"}, V{43, "bar"}},
- M{V{1, "foo"}, V{43, "baz"}}};
- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars));
-}
-
-REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMapTest, BasicUsage);
-using AssociativeMapTypes = testing::Types<
- std::map<int, std::string>, std::unordered_map<int, std::string>,
- absl::flat_hash_map<int, std::string>,
- absl::node_hash_map<int, std::string>, absl::btree_map<int, std::string>,
- UnorderedSequence<std::pair<const int, std::string>>>;
-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMapTest,
- AssociativeMapTypes);
-
-template <typename T>
-class HashValueAssociativeMultimapTest : public testing::Test {};
-TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest);
-
-TYPED_TEST_P(HashValueAssociativeMultimapTest, BasicUsage) {
- using MM = TypeParam;
- using V = typename MM::value_type;
- std::vector<MM> exemplars{MM{},
- MM{V{0, "foo"}},
- MM{V{1, "foo"}},
- MM{V{0, "bar"}},
- MM{V{1, "bar"}},
- MM{V{0, "foo"}, V{0, "bar"}},
- MM{V{0, "bar"}, V{0, "foo"}},
- MM{V{0, "foo"}, V{42, "bar"}},
- MM{V{1, "foo"}, V{42, "bar"}},
- MM{V{1, "foo"}, V{1, "foo"}, V{43, "bar"}},
- MM{V{1, "foo"}, V{43, "bar"}, V{1, "foo"}},
- MM{V{1, "foo"}, V{43, "baz"}}};
- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars));
-}
-
-REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest, BasicUsage);
-using AssociativeMultimapTypes =
- testing::Types<std::multimap<int, std::string>,
- std::unordered_multimap<int, std::string>>;
-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMultimapTest,
- AssociativeMultimapTypes);
-
TEST(HashValueTest, ReferenceWrapper) {
EXPECT_TRUE(is_hashable<std::reference_wrapper<Private>>::value);
diff --git a/absl/hash/internal/hash_test.h b/absl/hash/internal/hash_test.h
new file mode 100644
index 00000000..9963dc0b
--- /dev/null
+++ b/absl/hash/internal/hash_test.h
@@ -0,0 +1,87 @@
+// 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.
+
+// Common code shared between absl/hash/hash_test.cc and
+// absl/hash/hash_instantiated_test.cc.
+
+#ifndef ABSL_HASH_INTERNAL_HASH_TEST_H_
+#define ABSL_HASH_INTERNAL_HASH_TEST_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/hash/hash.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace hash_test_internal {
+
+// Utility wrapper of T for the purposes of testing the `AbslHash` type erasure
+// mechanism. `TypeErasedValue<T>` can be constructed with a `T`, and can
+// be compared and hashed. However, all hashing goes through the hashing
+// type-erasure framework.
+template <typename T>
+class TypeErasedValue {
+ public:
+ TypeErasedValue() = default;
+ TypeErasedValue(const TypeErasedValue&) = default;
+ TypeErasedValue(TypeErasedValue&&) = default;
+ explicit TypeErasedValue(const T& n) : n_(n) {}
+
+ template <typename H>
+ friend H AbslHashValue(H hash_state, const TypeErasedValue& v) {
+ v.HashValue(absl::HashState::Create(&hash_state));
+ return hash_state;
+ }
+
+ void HashValue(absl::HashState state) const {
+ absl::HashState::combine(std::move(state), n_);
+ }
+
+ bool operator==(const TypeErasedValue& rhs) const { return n_ == rhs.n_; }
+ bool operator!=(const TypeErasedValue& rhs) const { return !(*this == rhs); }
+
+ private:
+ T n_;
+};
+
+// A TypeErasedValue refinement, for containers. It exposes the wrapped
+// `value_type` and is constructible from an initializer list.
+template <typename T>
+class TypeErasedContainer : public TypeErasedValue<T> {
+ public:
+ using value_type = typename T::value_type;
+ TypeErasedContainer() = default;
+ TypeErasedContainer(const TypeErasedContainer&) = default;
+ TypeErasedContainer(TypeErasedContainer&&) = default;
+ explicit TypeErasedContainer(const T& n) : TypeErasedValue<T>(n) {}
+ TypeErasedContainer(std::initializer_list<value_type> init_list)
+ : TypeErasedContainer(T(init_list.begin(), init_list.end())) {}
+ // one-argument constructor of value type T, to appease older toolchains that
+ // get confused by one-element initializer lists in some contexts
+ explicit TypeErasedContainer(const value_type& v)
+ : TypeErasedContainer(T(&v, &v + 1)) {}
+};
+
+// Helper trait to verify if T is hashable. We use absl::Hash's poison status to
+// detect it.
+template <typename T>
+using is_hashable = std::is_default_constructible<absl::Hash<T>>;
+
+} // namespace hash_test_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_HASH_INTERNAL_HASH_TEST_H_
diff --git a/absl/log/internal/globals.cc b/absl/log/internal/globals.cc
index 863b047f..9ba997d5 100644
--- a/absl/log/internal/globals.cc
+++ b/absl/log/internal/globals.cc
@@ -16,6 +16,9 @@
#include <atomic>
#include <cstdio>
+#if defined(__EMSCRIPTEN__)
+#include <emscripten/console.h>
+#endif
#include "absl/base/attributes.h"
#include "absl/base/config.h"
@@ -55,9 +58,21 @@ void SetInitialized() {
}
void WriteToStderr(absl::string_view message, absl::LogSeverity severity) {
+#if defined(__EMSCRIPTEN__)
+ // In WebAssembly, bypass filesystem emulation via fwrite.
+ // TODO(b/282811932): Avoid this copy if these emscripten functions can
+ // be updated to accept size directly.
+ std::string null_terminated_message(message);
+ if (!null_terminated_message.empty() &&
+ null_terminated_message.back() == '\n') {
+ null_terminated_message.pop_back();
+ }
+ _emscripten_err(null_terminated_message.c_str());
+#else
// Avoid using std::cerr from this module since we may get called during
// exit code, and cerr may be partially or fully destroyed by then.
std::fwrite(message.data(), message.size(), 1, stderr);
+#endif
#if defined(_WIN64) || defined(_WIN32) || defined(_WIN16)
// C99 requires stderr to not be fully-buffered by default (7.19.3.7), but
diff --git a/absl/status/internal/statusor_internal.h b/absl/status/internal/statusor_internal.h
index eaac2c0b..49cead7a 100644
--- a/absl/status/internal/statusor_internal.h
+++ b/absl/status/internal/statusor_internal.h
@@ -69,11 +69,8 @@ using IsConstructibleOrConvertibleOrAssignableFromStatusOr =
template <typename T, typename U>
struct IsDirectInitializationAmbiguous
: public absl::conditional_t<
- std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
- U>::value,
- std::false_type,
- IsDirectInitializationAmbiguous<
- T, absl::remove_cv_t<absl::remove_reference_t<U>>>> {};
+ std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type,
+ IsDirectInitializationAmbiguous<T, absl::remove_cvref_t<U>>> {};
template <typename T, typename V>
struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>>
@@ -84,14 +81,11 @@ struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>>
template <typename T, typename U>
using IsDirectInitializationValid = absl::disjunction<
// Short circuits if T is basically U.
- std::is_same<T, absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ std::is_same<T, absl::remove_cvref_t<U>>,
absl::negation<absl::disjunction<
- std::is_same<absl::StatusOr<T>,
- absl::remove_cv_t<absl::remove_reference_t<U>>>,
- std::is_same<absl::Status,
- absl::remove_cv_t<absl::remove_reference_t<U>>>,
- std::is_same<absl::in_place_t,
- absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
+ std::is_same<absl::Status, absl::remove_cvref_t<U>>,
+ std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
IsDirectInitializationAmbiguous<T, U>>>>;
// This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which
@@ -107,11 +101,8 @@ using IsDirectInitializationValid = absl::disjunction<
template <typename T, typename U>
struct IsForwardingAssignmentAmbiguous
: public absl::conditional_t<
- std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
- U>::value,
- std::false_type,
- IsForwardingAssignmentAmbiguous<
- T, absl::remove_cv_t<absl::remove_reference_t<U>>>> {};
+ std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type,
+ IsForwardingAssignmentAmbiguous<T, absl::remove_cvref_t<U>>> {};
template <typename T, typename U>
struct IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>>
@@ -122,14 +113,11 @@ struct IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>>
template <typename T, typename U>
using IsForwardingAssignmentValid = absl::disjunction<
// Short circuits if T is basically U.
- std::is_same<T, absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ std::is_same<T, absl::remove_cvref_t<U>>,
absl::negation<absl::disjunction<
- std::is_same<absl::StatusOr<T>,
- absl::remove_cv_t<absl::remove_reference_t<U>>>,
- std::is_same<absl::Status,
- absl::remove_cv_t<absl::remove_reference_t<U>>>,
- std::is_same<absl::in_place_t,
- absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
+ std::is_same<absl::Status, absl::remove_cvref_t<U>>,
+ std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
IsForwardingAssignmentAmbiguous<T, U>>>>;
class Helper {
diff --git a/absl/status/statusor.h b/absl/status/statusor.h
index 935366d5..54c7ce02 100644
--- a/absl/status/statusor.h
+++ b/absl/status/statusor.h
@@ -411,7 +411,7 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
typename = typename std::enable_if<absl::conjunction<
std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
absl::disjunction<
- std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>, T>,
+ std::is_same<absl::remove_cvref_t<U>, T>,
absl::conjunction<
absl::negation<std::is_convertible<U&&, absl::Status>>,
absl::negation<internal_statusor::
@@ -444,8 +444,7 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
internal_statusor::IsDirectInitializationValid<T, U&&>,
std::is_constructible<T, U&&>, std::is_convertible<U&&, T>,
absl::disjunction<
- std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
- T>,
+ std::is_same<absl::remove_cvref_t<U>, T>,
absl::conjunction<
absl::negation<std::is_convertible<U&&, absl::Status>>,
absl::negation<
@@ -461,8 +460,7 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
absl::conjunction<
internal_statusor::IsDirectInitializationValid<T, U&&>,
absl::disjunction<
- std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
- T>,
+ std::is_same<absl::remove_cvref_t<U>, T>,
absl::conjunction<
absl::negation<std::is_constructible<absl::Status, U&&>>,
absl::negation<
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index bd33c533..4a111b5a 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -1319,3 +1319,15 @@ cc_binary(
"//absl/types:optional",
],
)
+
+cc_test(
+ name = "char_formatting_test",
+ srcs = [
+ "char_formatting_test.cc",
+ ],
+ deps = [
+ ":str_format",
+ ":strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index 9aaa7932..2ad052a3 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -548,6 +548,20 @@ absl_cc_test(
GTest::gmock_main
)
+absl_cc_test(
+ NAME
+ char_formatting_test
+ SRCS
+ "char_formatting_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::base
+ absl::str_format
+ absl::strings
+ GTest::gmock_main
+)
+
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
diff --git a/absl/strings/char_formatting_test.cc b/absl/strings/char_formatting_test.cc
new file mode 100644
index 00000000..60416af3
--- /dev/null
+++ b/absl/strings/char_formatting_test.cc
@@ -0,0 +1,189 @@
+// 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.
+
+#include <cstddef>
+
+#include "gtest/gtest.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/substitute.h"
+
+namespace {
+
+TEST(CharFormatting, Char) {
+ const char v = 'A';
+
+ // Desired behavior: does not compile:
+ // EXPECT_EQ(absl::StrCat(v, "B"), "AB");
+ // EXPECT_EQ(absl::StrFormat("%vB", v), "AB");
+
+ // Legacy behavior: format as char:
+ EXPECT_EQ(absl::Substitute("$0B", v), "AB");
+}
+
+enum CharEnum : char {};
+TEST(CharFormatting, CharEnum) {
+ auto v = static_cast<CharEnum>('A');
+
+ // Desired behavior: format as decimal
+ // (No APIs do this today.)
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Legacy behavior: does not compile:
+ // EXPECT_EQ(absl::StrCat(ch, "B"), "AB");
+
+ // Legacy behavior: format as character:
+
+ // Some older versions of gcc behave differently in this one case.
+#if !defined(__GNUC__) || defined(__clang__)
+ EXPECT_EQ(absl::Substitute("$0B", v), "AB");
+#endif
+}
+
+enum class CharEnumClass: char {};
+TEST(CharFormatting, CharEnumClass) {
+ auto v = static_cast<CharEnumClass>('A');
+
+ // Desired behavior: format as decimal
+ // (No APIs do this today.)
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Legacy behavior: does not compile:
+ // EXPECT_EQ(absl::StrCat(ch, "B"), "AB");
+
+ // Legacy behavior: format as character:
+ EXPECT_EQ(absl::Substitute("$0B", v), "AB");
+}
+
+TEST(CharFormatting, UnsignedChar) {
+ const unsigned char v = 'A';
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // Legacy behavior: does not compile:
+ // EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
+
+ // Signedness check
+ const unsigned char w = 255;
+ EXPECT_EQ(absl::StrCat(w, "B"), "255B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "255B");
+ // EXPECT_EQ(absl::StrFormat("%vB", v), "255B");
+}
+
+TEST(CharFormatting, SignedChar) {
+ const signed char v = 'A';
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // Legacy behavior: does not compile:
+ // EXPECT_EQ(absl::StrFormat("%vB", v), "AB");
+
+ // Signedness check
+ const signed char w = -128;
+ EXPECT_EQ(absl::StrCat(w, "B"), "-128B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "-128B");
+}
+
+enum UnsignedCharEnum : unsigned char {};
+TEST(CharFormatting, UnsignedCharEnum) {
+ auto v = static_cast<UnsignedCharEnum>('A');
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Signedness check
+ auto w = static_cast<UnsignedCharEnum>(255);
+ EXPECT_EQ(absl::StrCat(w, "B"), "255B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "255B");
+}
+
+enum SignedCharEnum : signed char {};
+TEST(CharFormatting, SignedCharEnum) {
+ auto v = static_cast<SignedCharEnum>('A');
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Signedness check
+ auto w = static_cast<SignedCharEnum>(-128);
+ EXPECT_EQ(absl::StrCat(w, "B"), "-128B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "-128B");
+}
+
+enum class UnsignedCharEnumClass : unsigned char {};
+TEST(CharFormatting, UnsignedCharEnumClass) {
+ auto v = static_cast<UnsignedCharEnumClass>('A');
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Signedness check
+ auto w = static_cast<UnsignedCharEnumClass>(255);
+ EXPECT_EQ(absl::StrCat(w, "B"), "255B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "255B");
+}
+
+enum SignedCharEnumClass : signed char {};
+TEST(CharFormatting, SignedCharEnumClass) {
+ auto v = static_cast<SignedCharEnumClass>('A');
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Signedness check
+ auto w = static_cast<SignedCharEnumClass>(-128);
+ EXPECT_EQ(absl::StrCat(w, "B"), "-128B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "-128B");
+}
+
+#ifdef __cpp_lib_byte
+TEST(CharFormatting, StdByte) {
+ auto v = static_cast<std::byte>('A');
+ // Desired behavior: format as 0xff
+ // (No APIs do this today.)
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Legacy behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+}
+#endif // _cpp_lib_byte
+
+} // namespace
diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h
index 35edf3aa..081ad85a 100644
--- a/absl/strings/internal/str_split_internal.h
+++ b/absl/strings/internal/str_split_internal.h
@@ -235,6 +235,24 @@ struct SplitterIsConvertibleTo
HasMappedType<C>::value> {
};
+template <typename StringType, typename Container, typename = void>
+struct ShouldUseLifetimeBound : std::false_type {};
+
+template <typename StringType, typename Container>
+struct ShouldUseLifetimeBound<
+ StringType, Container,
+ std::enable_if_t<
+ std::is_same<StringType, std::string>::value &&
+ std::is_same<typename Container::value_type, absl::string_view>::value>>
+ : std::true_type {};
+
+template <typename StringType, typename First, typename Second>
+using ShouldUseLifetimeBoundForPair = std::integral_constant<
+ bool, std::is_same<StringType, std::string>::value &&
+ (std::is_same<First, absl::string_view>::value ||
+ std::is_same<Second, absl::string_view>::value)>;
+
+
// This class implements the range that is returned by absl::StrSplit(). This
// class has templated conversion operators that allow it to be implicitly
// converted to a variety of types that the caller may have specified on the
@@ -281,10 +299,24 @@ class Splitter {
// An implicit conversion operator that is restricted to only those containers
// that the splitter is convertible to.
- template <typename Container,
- typename = typename std::enable_if<
- SplitterIsConvertibleTo<Container>::value>::type>
- operator Container() const { // NOLINT(runtime/explicit)
+ template <
+ typename Container,
+ std::enable_if_t<ShouldUseLifetimeBound<StringType, Container>::value &&
+ SplitterIsConvertibleTo<Container>::value,
+ std::nullptr_t> = nullptr>
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ operator Container() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return ConvertToContainer<Container, typename Container::value_type,
+ HasMappedType<Container>::value>()(*this);
+ }
+
+ template <
+ typename Container,
+ std::enable_if_t<!ShouldUseLifetimeBound<StringType, Container>::value &&
+ SplitterIsConvertibleTo<Container>::value,
+ std::nullptr_t> = nullptr>
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ operator Container() const {
return ConvertToContainer<Container, typename Container::value_type,
HasMappedType<Container>::value>()(*this);
}
@@ -293,8 +325,27 @@ class Splitter {
// strings returned by the begin() iterator. Either/both of .first and .second
// will be constructed with empty strings if the iterator doesn't have a
// corresponding value.
+ template <typename First, typename Second,
+ std::enable_if_t<
+ ShouldUseLifetimeBoundForPair<StringType, First, Second>::value,
+ std::nullptr_t> = nullptr>
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ operator std::pair<First, Second>() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return ConvertToPair<First, Second>();
+ }
+
+ template <typename First, typename Second,
+ std::enable_if_t<!ShouldUseLifetimeBoundForPair<StringType, First,
+ Second>::value,
+ std::nullptr_t> = nullptr>
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ operator std::pair<First, Second>() const {
+ return ConvertToPair<First, Second>();
+ }
+
+ private:
template <typename First, typename Second>
- operator std::pair<First, Second>() const { // NOLINT(runtime/explicit)
+ std::pair<First, Second> ConvertToPair() const {
absl::string_view first, second;
auto it = begin();
if (it != end()) {
@@ -306,7 +357,6 @@ class Splitter {
return {First(first), Second(second)};
}
- private:
// ConvertToContainer is a functor converting a Splitter to the requested
// Container of ValueType. It is specialized below to optimize splitting to
// certain combinations of Container and ValueType.
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt
index b3124251..1c830c7a 100644
--- a/absl/time/CMakeLists.txt
+++ b/absl/time/CMakeLists.txt
@@ -84,6 +84,7 @@ absl_cc_library(
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ Threads::Threads
$<$<PLATFORM_ID:Darwin>:${CoreFoundation}>
)
diff --git a/absl/time/clock.cc b/absl/time/clock.cc
index 2bf53d9c..aa74367b 100644
--- a/absl/time/clock.cc
+++ b/absl/time/clock.cc
@@ -48,17 +48,16 @@ Time Now() {
ABSL_NAMESPACE_END
} // namespace absl
-// Decide if we should use the fast GetCurrentTimeNanos() algorithm
-// based on the cyclecounter, otherwise just get the time directly
-// from the OS on every call. This can be chosen at compile-time via
+// Decide if we should use the fast GetCurrentTimeNanos() algorithm based on the
+// cyclecounter, otherwise just get the time directly from the OS on every call.
+// By default, the fast algorithm based on the cyclecount is disabled because in
+// certain situations, for example, if the OS enters a "sleep" mode, it may
+// produce incorrect values immediately upon waking.
+// This can be chosen at compile-time via
// -DABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS=[0|1]
#ifndef ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
-#if ABSL_USE_UNSCALED_CYCLECLOCK
-#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 1
-#else
#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 0
#endif
-#endif
#if defined(__APPLE__) || defined(_WIN32)
#include "absl/time/internal/get_current_time_chrono.inc"
diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc
index 0319b2f9..1d44dde7 100644
--- a/absl/time/internal/cctz/src/time_zone_if.cc
+++ b/absl/time/internal/cctz/src/time_zone_if.cc
@@ -26,6 +26,8 @@ namespace cctz {
std::unique_ptr<TimeZoneIf> TimeZoneIf::Load(const std::string& name) {
// Support "libc:localtime" and "libc:*" to access the legacy
// localtime and UTC support respectively from the C library.
+ // NOTE: The "libc:*" zones are internal, test-only interfaces, and
+ // are subject to change/removal without notice. Do not use them.
if (name.compare(0, 5, "libc:") == 0) {
return std::unique_ptr<TimeZoneIf>(new TimeZoneLibC(name.substr(5)));
}
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc
index 887dd097..af9f063e 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -125,31 +125,30 @@ inline std::tm* local_time(const std::time_t* timep, std::tm* result) {
#endif
}
-// Converts a civil second and "dst" flag into a time_t and UTC offset.
+// Converts a civil second and "dst" flag into a time_t and a struct tm.
// Returns false if time_t cannot represent the requested civil second.
// Caller must have already checked that cs.year() will fit into a tm_year.
-bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) {
- std::tm tm;
- tm.tm_year = static_cast<int>(cs.year() - year_t{1900});
- tm.tm_mon = cs.month() - 1;
- tm.tm_mday = cs.day();
- tm.tm_hour = cs.hour();
- tm.tm_min = cs.minute();
- tm.tm_sec = cs.second();
- tm.tm_isdst = is_dst;
- *t = std::mktime(&tm);
+bool make_time(const civil_second& cs, int is_dst, std::time_t* t,
+ std::tm* tm) {
+ tm->tm_year = static_cast<int>(cs.year() - year_t{1900});
+ tm->tm_mon = cs.month() - 1;
+ tm->tm_mday = cs.day();
+ tm->tm_hour = cs.hour();
+ tm->tm_min = cs.minute();
+ tm->tm_sec = cs.second();
+ tm->tm_isdst = is_dst;
+ *t = std::mktime(tm);
if (*t == std::time_t{-1}) {
std::tm tm2;
const std::tm* tmp = local_time(t, &tm2);
- if (tmp == nullptr || tmp->tm_year != tm.tm_year ||
- tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday ||
- tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min ||
- tmp->tm_sec != tm.tm_sec) {
+ if (tmp == nullptr || tmp->tm_year != tm->tm_year ||
+ tmp->tm_mon != tm->tm_mon || tmp->tm_mday != tm->tm_mday ||
+ tmp->tm_hour != tm->tm_hour || tmp->tm_min != tm->tm_min ||
+ tmp->tm_sec != tm->tm_sec) {
// A true error (not just one second before the epoch).
return false;
}
}
- *off = static_cast<int>(tm_gmtoff(tm));
return true;
}
@@ -254,33 +253,37 @@ time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
// We probe with "is_dst" values of 0 and 1 to try to distinguish unique
// civil seconds from skipped or repeated ones. This is not always possible
// however, as the "dst" flag does not change over some offset transitions.
- // We are also subject to the vagaries of mktime() implementations.
+ // We are also subject to the vagaries of mktime() implementations. For
+ // example, some implementations treat "tm_isdst" as a demand (useless),
+ // and some as a disambiguator (useful).
std::time_t t0, t1;
- int offset0, offset1;
- if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) {
- if (t0 == t1) {
+ std::tm tm0, tm1;
+ if (make_time(cs, 0, &t0, &tm0) && make_time(cs, 1, &t1, &tm1)) {
+ if (tm0.tm_isdst == tm1.tm_isdst) {
// The civil time was singular (pre == trans == post).
- const time_point<seconds> tp = FromUnixSeconds(t0);
+ const time_point<seconds> tp = FromUnixSeconds(tm0.tm_isdst ? t1 : t0);
return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
}
- if (t0 > t1) {
+ int offset = tm_gmtoff(tm0);
+ if (t0 < t1) { // negative DST
std::swap(t0, t1);
- std::swap(offset0, offset1);
+ offset = tm_gmtoff(tm1);
}
- const std::time_t tt = find_trans(t0, t1, offset1);
+
+ const std::time_t tt = find_trans(t1, t0, offset);
const time_point<seconds> trans = FromUnixSeconds(tt);
- if (offset0 < offset1) {
+ if (tm0.tm_isdst) {
// The civil time did not exist (pre >= trans > post).
- const time_point<seconds> pre = FromUnixSeconds(t1);
- const time_point<seconds> post = FromUnixSeconds(t0);
+ const time_point<seconds> pre = FromUnixSeconds(t0);
+ const time_point<seconds> post = FromUnixSeconds(t1);
return {time_zone::civil_lookup::SKIPPED, pre, trans, post};
}
// The civil time was ambiguous (pre < trans <= post).
- const time_point<seconds> pre = FromUnixSeconds(t0);
- const time_point<seconds> post = FromUnixSeconds(t1);
+ const time_point<seconds> pre = FromUnixSeconds(t1);
+ const time_point<seconds> post = FromUnixSeconds(t0);
return {time_zone::civil_lookup::REPEATED, pre, trans, post};
}
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc
index 68084ce2..9a30ba5e 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -148,11 +148,12 @@ std::string win32_local_time_zone(const HMODULE combase) {
UINT32 wlen;
const PCWSTR tz_wstr = windows_get_string_raw_buffer(tz_hstr, &wlen);
if (tz_wstr) {
- const int size = WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, nullptr,
- 0, nullptr, nullptr);
- result.resize(size);
- WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, &result[0], size, nullptr,
- nullptr);
+ const int size =
+ WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen),
+ nullptr, 0, nullptr, nullptr);
+ result.resize(static_cast<size_t>(size));
+ WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen),
+ &result[0], size, nullptr, nullptr);
}
windows_delete_string(tz_hstr);
}
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index 4b093b37..38f10f48 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -1034,16 +1034,16 @@ TEST(MakeTime, SysSecondsLimits) {
const time_zone cut = LoadZone("libc:UTC");
const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900;
tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), cut);
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
- // The BSD gmtime_r() fails on extreme positive tm_year values.
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
+ // Some gmtime_r() impls fail on extreme positive values.
#else
EXPECT_EQ("2147485547-12-31T23:59:59+00:00",
absl::time_internal::cctz::format(RFC3339, tp, cut));
#endif
const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut);
-#if defined(__Fuchsia__)
- // Fuchsia's gmtime_r() fails on extreme negative values (fxbug.dev/78527).
+#if defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
+ // Some gmtime_r() impls fail on extreme negative values (fxbug.dev/78527).
#else
EXPECT_EQ("-2147481748-01-01T00:00:00+00:00",
absl::time_internal::cctz::format(RFC3339, tp, cut));
@@ -1072,7 +1072,7 @@ TEST(MakeTime, LocalTimeLibC) {
tp = zi.lookup(transition.to).trans) {
const auto fcl = zi.lookup(transition.from);
const auto tcl = zi.lookup(transition.to);
- civil_second cs; // compare cs in zi and lc
+ civil_second cs, us; // compare cs and us in zi and lc
if (fcl.kind == time_zone::civil_lookup::UNIQUE) {
if (tcl.kind == time_zone::civil_lookup::UNIQUE) {
// Both unique; must be an is_dst or abbr change.
@@ -1088,12 +1088,14 @@ TEST(MakeTime, LocalTimeLibC) {
}
ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind);
cs = transition.to;
+ us = transition.from;
} else {
ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind);
ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind);
cs = transition.from;
+ us = transition.to;
}
- if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t)
+ if (us.year() > 2037) break; // limit test time (and to 32-bit time_t)
const auto cl_zi = zi.lookup(cs);
if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) {
// The "libc" implementation cannot correctly classify transitions
@@ -1125,6 +1127,13 @@ TEST(MakeTime, LocalTimeLibC) {
EXPECT_EQ(cl_zi.pre, cl_lc.pre);
EXPECT_EQ(cl_zi.trans, cl_lc.trans);
EXPECT_EQ(cl_zi.post, cl_lc.post);
+ const auto ucl_zi = zi.lookup(us);
+ const auto ucl_lc = lc.lookup(us);
+ SCOPED_TRACE(testing::Message() << "For " << us << " in " << *np);
+ EXPECT_EQ(ucl_zi.kind, ucl_lc.kind);
+ EXPECT_EQ(ucl_zi.pre, ucl_lc.pre);
+ EXPECT_EQ(ucl_zi.trans, ucl_lc.trans);
+ EXPECT_EQ(ucl_zi.post, ucl_lc.post);
}
}
if (ep == nullptr) {