summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt12
-rw-r--r--absl/base/BUILD.bazel28
-rw-r--r--absl/base/internal/spinlock.h4
-rw-r--r--absl/base/internal/spinlock_benchmark.cc52
-rw-r--r--absl/container/CMakeLists.txt2
-rw-r--r--absl/container/flat_hash_set.h6
-rw-r--r--absl/container/inlined_vector.h94
-rw-r--r--absl/container/internal/layout.h4
-rw-r--r--absl/container/internal/raw_hash_set.cc3
-rw-r--r--absl/container/node_hash_set.h6
-rw-r--r--absl/debugging/CMakeLists.txt413
-rw-r--r--absl/debugging/internal/demangle.cc9
-rw-r--r--absl/hash/CMakeLists.txt116
-rw-r--r--absl/memory/CMakeLists.txt76
-rw-r--r--absl/memory/memory_test.cc39
-rw-r--r--absl/strings/BUILD.bazel23
-rw-r--r--absl/strings/CMakeLists.txt23
-rw-r--r--absl/strings/charconv_test.cc14
-rw-r--r--absl/strings/internal/pow10_helper.cc120
-rw-r--r--absl/strings/internal/pow10_helper.h36
-rw-r--r--absl/strings/internal/pow10_helper_test.cc120
-rw-r--r--absl/strings/numbers_test.cc3
-rw-r--r--absl/synchronization/BUILD.bazel24
-rw-r--r--absl/synchronization/mutex_benchmark.cc151
-rw-r--r--absl/synchronization/notification.h1
-rw-r--r--absl/time/duration.cc8
-rw-r--r--absl/time/duration_test.cc34
-rw-r--r--absl/time/time.h5
-rw-r--r--absl/types/internal/variant.h31
-rw-r--r--absl/types/variant.h8
30 files changed, 1104 insertions, 361 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 77ae631d..1eafa407 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,6 +17,12 @@
# We require 3.0 for modern, target-based CMake. We require 3.1 for the use of
# CXX_STANDARD in our targets.
cmake_minimum_required(VERSION 3.1)
+
+# Compiler id for Apple Clang is now AppleClang.
+if (POLICY CMP0025)
+ cmake_policy(SET CMP0025 NEW)
+endif()
+
project(absl)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/CMake)
@@ -68,6 +74,12 @@ set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}")
# -fexceptions
set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")
+if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+ set(ABSL_USING_CLANG ON)
+else()
+ set(ABSL_USING_CLANG OFF)
+endif()
+
# find dependencies
## pthread
find_package(Threads REQUIRED)
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 44de05e3..4566c697 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -107,6 +107,7 @@ cc_library(
"internal/identity.h",
"internal/inline_variable.h",
"internal/invoke.h",
+ "internal/scheduling_mode.h",
],
copts = ABSL_DEFAULT_COPTS,
visibility = [
@@ -314,6 +315,33 @@ cc_test(
)
cc_library(
+ name = "spinlock_benchmark_common",
+ testonly = 1,
+ srcs = ["internal/spinlock_benchmark.cc"],
+ copts = ABSL_DEFAULT_COPTS,
+ visibility = [
+ "//absl/base:__pkg__",
+ ],
+ deps = [
+ ":base",
+ ":base_internal",
+ "//absl/synchronization",
+ "@com_github_google_benchmark//:benchmark_main",
+ ],
+ alwayslink = 1,
+)
+
+cc_binary(
+ name = "spinlock_benchmark",
+ testonly = 1,
+ copts = ABSL_DEFAULT_COPTS,
+ visibility = ["//visibility:private"],
+ deps = [
+ ":spinlock_benchmark_common",
+ ],
+)
+
+cc_library(
name = "endian",
hdrs = [
"internal/endian.h",
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
index dcce0109..eb3eec9c 100644
--- a/absl/base/internal/spinlock.h
+++ b/absl/base/internal/spinlock.h
@@ -101,8 +101,8 @@ class LOCKABLE SpinLock {
inline void Unlock() UNLOCK_FUNCTION() {
ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
- lockword_.store(lock_value & kSpinLockCooperative,
- std::memory_order_release);
+ lock_value = lockword_.exchange(lock_value & kSpinLockCooperative,
+ std::memory_order_release);
if ((lock_value & kSpinLockDisabledScheduling) != 0) {
base_internal::SchedulingGuard::EnableRescheduling(true);
diff --git a/absl/base/internal/spinlock_benchmark.cc b/absl/base/internal/spinlock_benchmark.cc
new file mode 100644
index 00000000..907d3e27
--- /dev/null
+++ b/absl/base/internal/spinlock_benchmark.cc
@@ -0,0 +1,52 @@
+// 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
+//
+// http://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.
+
+// See also //absl/synchronization:mutex_benchmark for a comparison of SpinLock
+// and Mutex performance under varying levels of contention.
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/synchronization/internal/create_thread_identity.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+template <absl::base_internal::SchedulingMode scheduling_mode>
+static void BM_SpinLock(benchmark::State& state) {
+ // Ensure a ThreadIdentity is installed.
+ ABSL_INTERNAL_CHECK(
+ absl::synchronization_internal::GetOrCreateCurrentThreadIdentity() !=
+ nullptr,
+ "GetOrCreateCurrentThreadIdentity() failed");
+
+ static auto* spinlock = new absl::base_internal::SpinLock(scheduling_mode);
+ for (auto _ : state) {
+ absl::base_internal::SpinLockHolder holder(spinlock);
+ }
+}
+
+BENCHMARK_TEMPLATE(BM_SpinLock,
+ absl::base_internal::SCHEDULE_KERNEL_ONLY)
+ ->UseRealTime()
+ ->Threads(1)
+ ->ThreadPerCpu();
+
+BENCHMARK_TEMPLATE(BM_SpinLock,
+ absl::base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL)
+ ->UseRealTime()
+ ->Threads(1)
+ ->ThreadPerCpu();
+
+} // namespace
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 7cddd84b..8605facc 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -30,7 +30,7 @@ absl_cc_library(
absl_cc_library(
NAME
compressed_tuple
- SRCS
+ HDRS
"internal/compressed_tuple.h"
DEPS
absl::utility
diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h
index 5ea6a816..84984cc4 100644
--- a/absl/container/flat_hash_set.h
+++ b/absl/container/flat_hash_set.h
@@ -279,8 +279,7 @@ class flat_hash_set
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
- // destroyed immediately. Prefer `try_emplace()` unless your key is not
- // copyable or moveable.
+ // destroyed immediately.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace;
@@ -294,8 +293,7 @@ class flat_hash_set
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
- // destroyed immediately. Prefer `try_emplace()` unless your key is not
- // copyable or moveable.
+ // destroyed immediately.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace_hint;
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index 642dae6c..5f3f0095 100644
--- a/absl/container/inlined_vector.h
+++ b/absl/container/inlined_vector.h
@@ -66,12 +66,11 @@ namespace absl {
// designed to cover the same API footprint as covered by `std::vector`.
template <typename T, size_t N, typename A = std::allocator<T>>
class InlinedVector {
+ static_assert(N > 0, "InlinedVector requires inline capacity greater than 0");
constexpr static typename A::size_type inlined_capacity() {
return static_cast<typename A::size_type>(N);
}
- static_assert(inlined_capacity() > 0, "InlinedVector needs inlined capacity");
-
template <typename Iterator>
using DisableIfIntegral =
absl::enable_if_t<!std::is_integral<Iterator>::value>;
@@ -131,7 +130,8 @@ class InlinedVector {
InlinedVector(std::initializer_list<value_type> init_list,
const allocator_type& alloc = allocator_type())
: allocator_and_tag_(alloc) {
- AppendRange(init_list.begin(), init_list.end());
+ AppendRange(init_list.begin(), init_list.end(),
+ IteratorCategory<decltype(init_list.begin())>{});
}
// Creates an inlined vector with elements constructed from the provided
@@ -144,7 +144,7 @@ class InlinedVector {
InlinedVector(InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type())
: allocator_and_tag_(alloc) {
- AppendRange(first, last);
+ AppendRange(first, last, IteratorCategory<InputIterator>{});
}
// Creates a copy of `other` using `other`'s allocator.
@@ -366,7 +366,6 @@ class InlinedVector {
// Returns a copy of the allocator of the inlined vector.
allocator_type get_allocator() const { return allocator(); }
-
// ---------------------------------------------------------------------------
// InlinedVector Member Mutators
// ---------------------------------------------------------------------------
@@ -376,7 +375,8 @@ class InlinedVector {
// Replaces the contents of the inlined vector with copies of the elements in
// the provided `std::initializer_list`.
InlinedVector& operator=(std::initializer_list<value_type> init_list) {
- AssignRange(init_list.begin(), init_list.end());
+ AssignRange(init_list.begin(), init_list.end(),
+ IteratorCategory<decltype(init_list.begin())>{});
return *this;
}
@@ -453,14 +453,15 @@ class InlinedVector {
// inlined vector with copies of the values in the provided
// `std::initializer_list`.
void assign(std::initializer_list<value_type> init_list) {
- AssignRange(init_list.begin(), init_list.end());
+ AssignRange(init_list.begin(), init_list.end(),
+ IteratorCategory<decltype(init_list.begin())>{});
}
// Overload of `InlinedVector::assign()` to replace the contents of the
// inlined vector with values constructed from the range [`first`, `last`).
template <typename InputIterator, DisableIfIntegral<InputIterator>* = nullptr>
void assign(InputIterator first, InputIterator last) {
- AssignRange(first, last);
+ AssignRange(first, last, IteratorCategory<InputIterator>{});
}
// `InlinedVector::resize()`
@@ -845,40 +846,28 @@ class InlinedVector {
void Destroy(pointer from, pointer to);
template <typename Iterator>
- void AppendRange(Iterator first, Iterator last, std::input_iterator_tag) {
- std::copy(first, last, std::back_inserter(*this));
- }
-
- template <typename Iterator>
void AppendRange(Iterator first, Iterator last, std::forward_iterator_tag);
template <typename Iterator>
- void AppendRange(Iterator first, Iterator last) {
- AppendRange(first, last, IteratorCategory<Iterator>());
- }
-
- template <typename Iterator>
- void AssignRange(Iterator first, Iterator last, std::input_iterator_tag);
+ void AppendRange(Iterator first, Iterator last, std::input_iterator_tag);
template <typename Iterator>
void AssignRange(Iterator first, Iterator last, std::forward_iterator_tag);
template <typename Iterator>
- void AssignRange(Iterator first, Iterator last) {
- AssignRange(first, last, IteratorCategory<Iterator>());
- }
+ void AssignRange(Iterator first, Iterator last, std::input_iterator_tag);
iterator InsertWithCount(const_iterator position, size_type n,
const_reference v);
- template <typename InputIterator>
- iterator InsertWithRange(const_iterator position, InputIterator first,
- InputIterator last, std::input_iterator_tag);
-
template <typename ForwardIterator>
iterator InsertWithRange(const_iterator position, ForwardIterator first,
ForwardIterator last, std::forward_iterator_tag);
+ template <typename InputIterator>
+ iterator InsertWithRange(const_iterator position, InputIterator first,
+ InputIterator last, std::input_iterator_tag);
+
// Stores either the inlined or allocated representation
union Rep {
using ValueTypeBuffer =
@@ -889,7 +878,7 @@ class InlinedVector {
// Structs wrap the buffers to perform indirection that solves a bizarre
// compilation error on Visual Studio (all known versions).
struct InlinedRep {
- ValueTypeBuffer inlined[inlined_capacity()];
+ ValueTypeBuffer inlined[N];
};
struct AllocatedRep {
AllocationBuffer allocation;
@@ -1364,15 +1353,8 @@ void InlinedVector<T, N, A>::AppendRange(Iterator first, Iterator last,
template <typename T, size_t N, typename A>
template <typename Iterator>
-void InlinedVector<T, N, A>::AssignRange(Iterator first, Iterator last,
+void InlinedVector<T, N, A>::AppendRange(Iterator first, Iterator last,
std::input_iterator_tag) {
- // Optimized to avoid reallocation.
- // Prefer reassignment to copy construction for elements.
- iterator out = begin();
- for (; first != last && out != end(); ++first, ++out) {
- *out = *first;
- }
- erase(out, end());
std::copy(first, last, std::back_inserter(*this));
}
@@ -1399,6 +1381,20 @@ void InlinedVector<T, N, A>::AssignRange(Iterator first, Iterator last,
}
template <typename T, size_t N, typename A>
+template <typename Iterator>
+void InlinedVector<T, N, A>::AssignRange(Iterator first, Iterator last,
+ std::input_iterator_tag) {
+ // Optimized to avoid reallocation.
+ // Prefer reassignment to copy construction for elements.
+ iterator out = begin();
+ for (; first != last && out != end(); ++first, ++out) {
+ *out = *first;
+ }
+ erase(out, end());
+ std::copy(first, last, std::back_inserter(*this));
+}
+
+template <typename T, size_t N, typename A>
auto InlinedVector<T, N, A>::InsertWithCount(const_iterator position,
size_type n, const_reference v)
-> iterator {
@@ -1414,20 +1410,6 @@ auto InlinedVector<T, N, A>::InsertWithCount(const_iterator position,
}
template <typename T, size_t N, typename A>
-template <typename InputIterator>
-auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
- InputIterator first,
- InputIterator last,
- std::input_iterator_tag)
- -> iterator {
- assert(position >= begin() && position <= end());
- size_type index = position - cbegin();
- size_type i = index;
- while (first != last) insert(begin() + i++, *first++);
- return begin() + index;
-}
-
-template <typename T, size_t N, typename A>
template <typename ForwardIterator>
auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
ForwardIterator first,
@@ -1446,6 +1428,20 @@ auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
return it_pair.first;
}
+template <typename T, size_t N, typename A>
+template <typename InputIterator>
+auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
+ InputIterator first,
+ InputIterator last,
+ std::input_iterator_tag)
+ -> iterator {
+ assert(position >= begin() && position <= end());
+ size_type index = position - cbegin();
+ size_type i = index;
+ while (first != last) insert(begin() + i++, *first++);
+ return begin() + index;
+}
+
} // namespace absl
#endif // ABSL_CONTAINER_INLINED_VECTOR_H_
diff --git a/absl/container/internal/layout.h b/absl/container/internal/layout.h
index a9c1244a..3d21ac96 100644
--- a/absl/container/internal/layout.h
+++ b/absl/container/internal/layout.h
@@ -253,8 +253,10 @@ template <class From, class To>
using CopyConst =
typename std::conditional<std::is_const<From>::value, const To, To>::type;
+// Note: We're not qualifying this with absl:: because it doesn't compile under
+// MSVC.
template <class T>
-using SliceType = absl::Span<T>;
+using SliceType = Span<T>;
// This namespace contains no types. It prevents functions defined in it from
// being found by ADL.
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc
index 10153129..180d3fe5 100644
--- a/absl/container/internal/raw_hash_set.cc
+++ b/absl/container/internal/raw_hash_set.cc
@@ -14,6 +14,7 @@
#include "absl/container/internal/raw_hash_set.h"
+#include <atomic>
#include <cstddef>
#include "absl/base/config.h"
@@ -29,7 +30,7 @@ inline size_t RandomSeed() {
static thread_local size_t counter = 0;
size_t value = ++counter;
#else // ABSL_HAVE_THREAD_LOCAL
- static std::atomic<size_t> counter;
+ static std::atomic<size_t> counter(0);
size_t value = counter.fetch_add(1, std::memory_order_relaxed);
#endif // ABSL_HAVE_THREAD_LOCAL
return value ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(&counter));
diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h
index e4034461..843b11aa 100644
--- a/absl/container/node_hash_set.h
+++ b/absl/container/node_hash_set.h
@@ -273,8 +273,7 @@ class node_hash_set
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
- // destroyed immediately. Prefer `try_emplace()` unless your key is not
- // copyable or moveable.
+ // destroyed immediately.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace;
@@ -288,8 +287,7 @@ class node_hash_set
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
- // destroyed immediately. Prefer `try_emplace()` unless your key is not
- // copyable or moveable.
+ // destroyed immediately.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace_hint;
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index c28eb14b..f66688ba 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -14,204 +14,297 @@
# limitations under the License.
#
-list(APPEND DEBUGGING_PUBLIC_HEADERS
- "failure_signal_handler.h"
- "leak_check.h"
- "stacktrace.h"
- "symbolize.h"
-)
-
-# TODO(cohenjon) The below is all kinds of wrong. Make this match what we do in
-# Bazel
-list(APPEND DEBUGGING_INTERNAL_HEADERS
- "internal/address_is_readable.h"
- "internal/demangle.h"
- "internal/elf_mem_image.h"
- "internal/examine_stack.h"
- "internal/stacktrace_config.h"
- "internal/symbolize.h"
- "internal/vdso_support.h"
-)
-
-list(APPEND DEBUGGING_INTERNAL_SRC
- "internal/address_is_readable.cc"
- "internal/elf_mem_image.cc"
- "internal/vdso_support.cc"
-)
-
-
-list(APPEND STACKTRACE_SRC
- "stacktrace.cc"
- ${DEBUGGING_INTERNAL_SRC}
- ${DEBUGGING_PUBLIC_HEADERS}
- ${DEBUGGING_INTERNAL_HEADERS}
+absl_cc_library(
+ NAME
+ stacktrace
+ HDRS
+ "stacktrace.h"
+ SRCS
+ "stacktrace.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::debugging_internal
+ absl::base
+ absl::core_headers
+ PUBLIC
)
-list(APPEND SYMBOLIZE_SRC
- "symbolize.cc"
- "symbolize_elf.inc"
- "symbolize_unimplemented.inc"
- "symbolize_win32.inc"
- "internal/demangle.cc"
- ${DEBUGGING_PUBLIC_HEADERS}
- ${DEBUGGING_INTERNAL_HEADERS}
- ${DEBUGGING_INTERNAL_SRC}
+absl_cc_library(
+ NAME
+ symbolize
+ HDRS
+ "symbolize.h"
+ "internal/symbolize.h"
+ SRCS
+ "symbolize.cc"
+ "symbolize_elf.inc"
+ "symbolize_unimplemented.inc"
+ "symbolize_win32.inc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::debugging_internal
+ absl::demangle_internal
+ absl::base
+ absl::core_headers
+ absl::malloc_internal
+ PUBLIC
)
-list(APPEND FAILURE_SIGNAL_HANDLER_SRC
- "failure_signal_handler.cc"
- ${DEBUGGING_PUBLIC_HEADERS}
+absl_cc_test(
+ NAME
+ symbolize_test
+ SRCS
+ "symbolize_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::stack_consumption
+ absl::symbolize
+ absl::base
+ absl::core_headers
+ absl::memory
+ gmock
)
-list(APPEND EXAMINE_STACK_SRC
- "internal/examine_stack.cc"
- ${DEBUGGING_PUBLIC_HEADERS}
- ${DEBUGGING_INTERNAL_HEADERS}
+absl_cc_library(
+ NAME
+ examine_stack
+ HDRS
+ "internal/examine_stack.h"
+ SRCS
+ "internal/examine_stack.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::stacktrace
+ absl::symbolize
+ absl::base
+ absl::core_headers
)
-absl_library(
- TARGET
- absl_stacktrace
- SOURCES
- ${STACKTRACE_SRC}
- EXPORT_NAME
- stacktrace
+absl_cc_library(
+ NAME
+ failure_signal_handler
+ HDRS
+ "failure_signal_handler.h"
+ SRCS
+ "failure_signal_handler.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::examine_stack
+ absl::stacktrace
+ absl::base
+ absl::config
+ absl::core_headers
+ PUBLIC
)
-absl_library(
- TARGET
- absl_symbolize
- SOURCES
- ${SYMBOLIZE_SRC}
- PUBLIC_LIBRARIES
+absl_cc_test(
+ NAME
+ failure_signal_handler_test
+ SRCS
+ "failure_signal_handler_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::failure_signal_handler
+ absl::stacktrace
+ absl::symbolize
absl::base
- absl::malloc_internal
- EXPORT_NAME
- symbolize
+ absl::strings
+ Threads::Threads
+ gmock
)
-absl_library(
- TARGET
- absl_failure_signal_handler
- SOURCES
- ${FAILURE_SIGNAL_HANDLER_SRC}
- PUBLIC_LIBRARIES
- absl_base absl::examine_stack absl::stacktrace absl_synchronization
- EXPORT_NAME
- failure_signal_handler
+absl_cc_library(
+ NAME
+ debugging_internal
+ HDRS
+ "internal/address_is_readable.h"
+ "internal/elf_mem_image.h"
+ "internal/stacktrace_aarch64-inl.inc"
+ "internal/stacktrace_arm-inl.inc"
+ "internal/stacktrace_config.h"
+ "internal/stacktrace_generic-inl.inc"
+ "internal/stacktrace_powerpc-inl.inc"
+ "internal/stacktrace_unimplemented-inl.inc"
+ "internal/stacktrace_win32-inl.inc"
+ "internal/stacktrace_x86-inl.inc"
+ "internal/vdso_support.h"
+ SRCS
+ "internal/address_is_readable.cc"
+ "internal/elf_mem_image.cc"
+ "internal/vdso_support.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::dynamic_annotations
)
-# Internal-only. Projects external to Abseil should not depend
-# directly on this library.
-absl_library(
- TARGET
- absl_examine_stack
- SOURCES
- ${EXAMINE_STACK_SRC}
- EXPORT_NAME
- examine_stack
+absl_cc_library(
+ NAME
+ demangle_internal
+ HDRS
+ "internal/demangle.h"
+ SRCS
+ "internal/demangle.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ PUBLIC
)
-list(APPEND LEAK_CHECK_SRC
- "leak_check.cc"
+absl_cc_test(
+ NAME
+ demangle_test
+ SRCS
+ "internal/demangle_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::demangle_internal
+ absl::stack_consumption
+ absl::base
+ absl::core_headers
+ absl::memory
+ gmock_main
)
-
-# leak_check library
-absl_library(
- TARGET
- absl_leak_check
- SOURCES
- ${LEAK_CHECK_SRC}
- PUBLIC_LIBRARIES
- absl_base
- EXPORT_NAME
+absl_cc_library(
+ NAME
leak_check
+ HDRS
+ "$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:leak_check.h>"
+ SRCS
+ "$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:leak_check.cc>"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ PUBLIC
)
-
-# component target
-absl_header_library(
- TARGET
- absl_debugging
- PUBLIC_LIBRARIES
- absl_stacktrace absl_leak_check
- EXPORT_NAME
- debugging
+absl_cc_library(
+ NAME
+ leak_check_disable
+ SRCS
+ "leak_check_disable.cc"
+ PUBLIC
)
-#
-## TESTS
-#
+# TODO(cohenjon) Move into the copts code.
+if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ set(ABSL_LSAN_LINKOPTS "-fsanitize=leak")
+endif()
-list(APPEND STACK_CONSUMPTION_SRC
- "internal/stack_consumption.cc"
- "internal/stack_consumption.h"
+absl_cc_library(
+ NAME
+ leak_check_api_enabled_for_testing
+ HDRS
+ "leak_check.h"
+ SRCS
+ "leak_check.cc"
+ COPTS
+ $<$<BOOL:${ABSL_USING_CLANG}>:-DLEAK_SANITIZER>
+ TESTONLY
)
-absl_library(
- TARGET
- absl_stack_consumption
- SOURCES
- ${STACK_CONSUMPTION_SRC}
+absl_cc_library(
+ NAME
+ leak_check_api_disabled_for_testing
+ HDRS
+ "leak_check.h"
+ SRCS
+ "leak_check.cc"
+ COPTS
+ "-ULEAK_SANITIZER"
+ TESTONLY
)
-absl_test(
- TARGET
- absl_stack_consumption_test
- SOURCES
- "internal/stack_consumption_test.cc"
- PUBLIC_LIBRARIES
- absl_stack_consumption
+absl_cc_test(
+ NAME
+ leak_check_test
+ SRCS
+ "leak_check_test.cc"
+ COPTS
+ "$<$<CXX_COMPILER_ID:Clang>:-DABSL_EXPECT_LEAK_SANITIZER>"
+ LINKOPTS
+ "${ABSL_LSAN_LINKOPTS}"
+ DEPS
+ absl::leak_check_api_enabled_for_testing
absl::base
+ gmock_main
)
-list(APPEND DEMANGLE_TEST_SRC "internal/demangle_test.cc")
-
-absl_test(
- TARGET
- demangle_test
- SOURCES
- ${DEMANGLE_TEST_SRC}
- PUBLIC_LIBRARIES
- absl_symbolize absl_stack_consumption
+absl_cc_test(
+ NAME
+ leak_check_no_lsan_test
+ SRCS
+ "leak_check_test.cc"
+ COPTS
+ "-UABSL_EXPECT_LEAK_SANITIZER"
+ DEPS
+ absl::leak_check_api_disabled_for_testing
+ absl::base
+ gmock_main
)
-list(APPEND SYMBOLIZE_TEST_SRC "symbolize_test.cc")
-
-absl_test(
- TARGET
- symbolize_test
- SOURCES
- ${SYMBOLIZE_TEST_SRC}
- PUBLIC_LIBRARIES
- absl::base absl::memory absl_symbolize absl_stack_consumption
+absl_cc_test(
+ NAME
+ disabled_leak_check_test
+ SRCS
+ "leak_check_fail_test.cc"
+ LINKOPTS
+ "${ABSL_LSAN_LINKOPTS}"
+ DEPS
+ absl::leak_check_api_enabled_for_testing
+ absl::leak_check_disable
+ absl::base
+ gmock_main
)
-list(APPEND FAILURE_SIGNAL_HANDLER_TEST_SRC "failure_signal_handler_test.cc")
-
-absl_test(
- TARGET
- failure_signal_handler_test
- SOURCES
- ${FAILURE_SIGNAL_HANDLER_TEST_SRC}
- PUBLIC_LIBRARIES
- absl_examine_stack
- absl_failure_signal_handler
- absl_stacktrace
- absl_symbolize
+absl_cc_library(
+ NAME
+ stack_consumption
+ HDRS
+ "internal/stack_consumption.h"
+ SRCS
+ "internal/stack_consumption.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
absl::base
- absl::strings
+ absl::core_headers
+ TESTONLY
)
-# test leak_check_test
-list(APPEND LEAK_CHECK_TEST_SRC "leak_check_test.cc")
+absl_cc_test(
+ NAME
+ stack_consumption_test
+ SRCS
+ "internal/stack_consumption_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::stack_consumption
+ absl::base
+ absl::core_headers
+ gmock_main
+)
-absl_test(
- TARGET
- leak_check_test
- SOURCES
- ${LEAK_CHECK_TEST_SRC}
- PUBLIC_LIBRARIES
- absl_leak_check
+# component target
+absl_cc_library(
+ NAME
+ debugging
+ DEPS
+ absl::stacktrace
+ absl::leak_check
+ PUBLIC
)
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
index 48354459..3ee3df51 100644
--- a/absl/debugging/internal/demangle.cc
+++ b/absl/debugging/internal/demangle.cc
@@ -1636,6 +1636,15 @@ static bool ParseExpression(State *state) {
}
state->parse_state = copy;
+ // Pointer-to-member access expressions. This parses the same as a binary
+ // operator, but it's implemented separately because "ds" shouldn't be
+ // accepted in other contexts that parse an operator name.
+ if (ParseTwoCharToken(state, "ds") && ParseExpression(state) &&
+ ParseExpression(state)) {
+ return true;
+ }
+ state->parse_state = copy;
+
// Parameter pack expansion
if (ParseTwoCharToken(state, "sp") && ParseExpression(state)) {
return true;
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt
index a0d59b0b..8f97d7cc 100644
--- a/absl/hash/CMakeLists.txt
+++ b/absl/hash/CMakeLists.txt
@@ -14,40 +14,30 @@
# limitations under the License.
#
-list(APPEND HASH_PUBLIC_HEADERS
- "hash.h"
-)
-
-list(APPEND HASH_INTERNAL_HEADERS
- "internal/city.h"
- "internal/hash.h"
-)
-
-# absl_hash library
-list(APPEND HASH_SRC
- "internal/city.cc"
- "internal/hash.cc"
- ${HASH_PUBLIC_HEADERS}
- ${HASH_INTERNAL_HEADERS}
-)
-
-set(HASH_PUBLIC_LIBRARIES absl::hash absl::fixed_array absl::strings absl::str_format absl::utility)
-
-absl_library(
- TARGET
- absl_hash
- SOURCES
- ${HASH_SRC}
- PUBLIC_LIBRARIES
- ${HASH_PUBLIC_LIBRARIES}
- EXPORT_NAME
+absl_cc_library(
+ NAME
hash
+ HDRS
+ "hash.h"
+ SRCS
+ "internal/hash.cc"
+ "internal/hash.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ absl::endian
+ absl::fixed_array
+ absl::meta
+ absl::int128
+ absl::strings
+ absl::optional
+ absl::variant
+ absl::utility
+ absl::city
+ PUBLIC
)
-#
-## TESTS
-#
-
absl_cc_library(
NAME
hash_testing
@@ -62,11 +52,29 @@ absl_cc_library(
TESTONLY
)
+absl_cc_test(
+ NAME
+ hash_test
+ SRCS
+ "hash_test.cc"
+ DEPS
+ absl::hash
+ absl::hash_testing
+ absl::core_headers
+ absl::flat_hash_set
+ absl::spy_hash_state
+ absl::meta
+ absl::int128
+ gmock_main
+)
+
absl_cc_library(
NAME
spy_hash_state
HDRS
"internal/spy_hash_state.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
DEPS
absl::hash
absl::strings
@@ -74,32 +82,30 @@ absl_cc_library(
TESTONLY
)
-# testing support
-set(HASH_TEST_HEADERS hash_testing.h internal/spy_hash_state.h)
-set(HASH_TEST_PUBLIC_LIBRARIES absl::hash absl::flat_hash_set absl::numeric absl::strings absl::str_format)
-
-# hash_test
-set(HASH_TEST_SRC "hash_test.cc" ${HASH_TEST_HEADERS})
-
-absl_test(
- TARGET
- hash_test
- SOURCES
- ${HASH_TEST_SRC}
- PUBLIC_LIBRARIES
- ${HASH_TEST_PUBLIC_LIBRARIES}
+absl_cc_library(
+ NAME
+ city
+ HDRS
+ "internal/city.h"
+ SRCS
+ "internal/city.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ absl::core_headers
+ absl::endian
)
-# hash_test
-set(CITY_TEST_SRC "internal/city_test.cc")
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
city_test
- SOURCES
- ${CITY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${HASH_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/city_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::city
+ gmock_main
)
-
diff --git a/absl/memory/CMakeLists.txt b/absl/memory/CMakeLists.txt
index 8f9e731f..4b494dc0 100644
--- a/absl/memory/CMakeLists.txt
+++ b/absl/memory/CMakeLists.txt
@@ -14,55 +14,45 @@
# limitations under the License.
#
-list(APPEND MEMORY_PUBLIC_HEADERS
- "memory.h"
-)
-
-
-absl_header_library(
- TARGET
- absl_memory
- EXPORT_NAME
+absl_cc_library(
+ NAME
memory
+ HDRS
+ "memory.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ absl::meta
+ PUBLIC
)
-#
-## TESTS
-#
-
-# test memory_test
-list(APPEND MEMORY_TEST_SRC
- "memory_test.cc"
- ${MEMORY_PUBLIC_HEADERS}
-)
-set(MEMORY_TEST_PUBLIC_LIBRARIES absl::base absl::memory)
-
-
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
memory_test
- SOURCES
- ${MEMORY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${MEMORY_TEST_PUBLIC_LIBRARIES}
-)
-
-
-# test memory_exception_safety_test
-set(MEMORY_EXCEPTION_SAFETY_TEST_SRC "memory_exception_safety_test.cc")
-set(MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
- absl::memory
- absl_internal_exception_safety_testing
+ SRCS
+ "memory_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::memory
+ absl::base
+ absl::core_headers
+ gmock_main
)
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
memory_exception_safety_test
- SOURCES
- ${MEMORY_EXCEPTION_SAFETY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+ SRCS
+ "memory_exception_safety_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::memory
+ absl::exception_safety_testing
+ gmock_main
)
diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc
index 54f920b5..21fe32f9 100644
--- a/absl/memory/memory_test.cc
+++ b/absl/memory/memory_test.cc
@@ -69,6 +69,45 @@ TEST(MakeUniqueTest, Basic) {
EXPECT_EQ("hi", *p);
}
+// InitializationVerifier fills in a pattern when allocated so we can
+// distinguish between its default and value initialized states (without
+// accessing truly uninitialized memory).
+struct InitializationVerifier {
+ static constexpr int kDefaultScalar = 0x43;
+ static constexpr int kDefaultArray = 0x4B;
+
+ static void* operator new(size_t n) {
+ void* ret = ::operator new(n);
+ memset(ret, kDefaultScalar, n);
+ return ret;
+ }
+
+ static void* operator new[](size_t n) {
+ void* ret = ::operator new[](n);
+ memset(ret, kDefaultArray, n);
+ return ret;
+ }
+
+ int a;
+ int b;
+};
+
+TEST(Initialization, MakeUnique) {
+ auto p = absl::make_unique<InitializationVerifier>();
+
+ EXPECT_EQ(0, p->a);
+ EXPECT_EQ(0, p->b);
+}
+
+TEST(Initialization, MakeUniqueArray) {
+ auto p = absl::make_unique<InitializationVerifier[]>(2);
+
+ EXPECT_EQ(0, p[0].a);
+ EXPECT_EQ(0, p[0].b);
+ EXPECT_EQ(0, p[1].a);
+ EXPECT_EQ(0, p[1].b);
+}
+
struct MoveOnly {
MoveOnly() = default;
explicit MoveOnly(int i1) : ip1{new int{i1}} {}
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index 6d7c2619..3b85f1b4 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -413,6 +413,7 @@ cc_test(
copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"],
deps = [
+ ":pow10_helper",
":strings",
"//absl/base",
"//absl/base:core_headers",
@@ -471,6 +472,8 @@ cc_test(
srcs = ["charconv_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
+ ":pow10_helper",
+ ":str_format",
":strings",
"//absl/base",
"@com_google_googletest//:gtest_main",
@@ -659,3 +662,23 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
+
+cc_library(
+ name = "pow10_helper",
+ testonly = True,
+ srcs = ["internal/pow10_helper.cc"],
+ hdrs = ["internal/pow10_helper.h"],
+ visibility = ["//visibility:private"],
+)
+
+cc_test(
+ name = "pow10_helper_test",
+ srcs = ["internal/pow10_helper_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ visibility = ["//visibility:private"],
+ deps = [
+ ":pow10_helper",
+ ":str_format",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index a6574c17..5b877ad1 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -131,6 +131,15 @@ absl_library(
absl::strings
)
+# pow10_helper
+absl_library(
+ TARGET
+ pow10_helper
+ SOURCES
+ "internal/pow10_helper.cc"
+ "internal/pow10_helper.h"
+)
+
#
## TESTS
#
@@ -316,7 +325,7 @@ absl_test(
# test numbers_test
set(NUMBERS_TEST_SRC "numbers_test.cc")
-set(NUMBERS_TEST_PUBLIC_LIBRARIES absl::strings)
+set(NUMBERS_TEST_PUBLIC_LIBRARIES absl::strings pow10_helper)
absl_test(
TARGET
@@ -358,7 +367,7 @@ absl_test(
# test charconv_test
set(CHARCONV_TEST_SRC "charconv_test.cc")
-set(CHARCONV_TEST_PUBLIC_LIBRARIES absl::strings)
+set(CHARCONV_TEST_PUBLIC_LIBRARIES absl::strings absl::str_format pow10_helper)
absl_test(
TARGET
@@ -460,3 +469,13 @@ absl_test(
absl::base
)
+# test pow10_helper_test
+absl_test(
+ TARGET
+ pow10_helper_test
+ SOURCES
+ "internal/pow10_helper_test.cc"
+ PUBLIC_LIBRARIES
+ pow10_helper
+ absl::str_format
+)
diff --git a/absl/strings/charconv_test.cc b/absl/strings/charconv_test.cc
index 89418fe9..d07537eb 100644
--- a/absl/strings/charconv_test.cc
+++ b/absl/strings/charconv_test.cc
@@ -19,7 +19,9 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/strings/internal/pow10_helper.h"
#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
#ifdef _MSC_FULL_VER
#define ABSL_COMPILER_DOES_EXACT_ROUNDING 0
@@ -31,6 +33,8 @@
namespace {
+using absl::strings_internal::Pow10;
+
#if ABSL_COMPILER_DOES_EXACT_ROUNDING
// Tests that the given string is accepted by absl::from_chars, and that it
@@ -678,7 +682,8 @@ void TestOverflowAndUnderflow(
auto result =
absl::from_chars(input.data(), input.data() + input.size(), actual);
EXPECT_EQ(result.ec, std::errc());
- EXPECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual)
+ << absl::StrFormat("%a vs %a", expected, actual);
}
// test legal values near upper_bound
for (index = upper_bound, step = 1; index > lower_bound;
@@ -690,7 +695,8 @@ void TestOverflowAndUnderflow(
auto result =
absl::from_chars(input.data(), input.data() + input.size(), actual);
EXPECT_EQ(result.ec, std::errc());
- EXPECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual)
+ << absl::StrFormat("%a vs %a", expected, actual);
}
// Test underflow values below lower_bound
for (index = lower_bound - 1, step = 1; index > -1000000;
@@ -747,7 +753,7 @@ TEST(FromChars, HexdecimalFloatLimits) {
// acceptable exponents in this test.
TEST(FromChars, DecimalDoubleLimits) {
auto input_gen = [](int index) { return absl::StrCat("1.0e", index); };
- auto expected_gen = [](int index) { return std::pow(10.0, index); };
+ auto expected_gen = [](int index) { return Pow10(index); };
TestOverflowAndUnderflow<double>(input_gen, expected_gen, -323, 308);
}
@@ -759,7 +765,7 @@ TEST(FromChars, DecimalDoubleLimits) {
// acceptable exponents in this test.
TEST(FromChars, DecimalFloatLimits) {
auto input_gen = [](int index) { return absl::StrCat("1.0e", index); };
- auto expected_gen = [](int index) { return std::pow(10.0, index); };
+ auto expected_gen = [](int index) { return Pow10(index); };
TestOverflowAndUnderflow<float>(input_gen, expected_gen, -45, 38);
}
diff --git a/absl/strings/internal/pow10_helper.cc b/absl/strings/internal/pow10_helper.cc
new file mode 100644
index 00000000..66be163f
--- /dev/null
+++ b/absl/strings/internal/pow10_helper.cc
@@ -0,0 +1,120 @@
+// 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
+//
+// http://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/strings/internal/pow10_helper.h"
+
+#include <cmath>
+
+namespace absl {
+namespace strings_internal {
+
+namespace {
+
+// The exact value of 1e23 falls precisely halfway between two representable
+// doubles. Furthermore, the rounding rules we prefer (break ties by rounding
+// to the nearest even) dictate in this case that the number should be rounded
+// down, but this is not completely specified for floating-point literals in
+// C++. (It just says to use the default rounding mode of the standard
+// library.) We ensure the result we want by using a number that has an
+// unambiguous correctly rounded answer.
+constexpr double k1e23 = 9999999999999999e7;
+
+constexpr double kPowersOfTen[] = {
+ 0.0, 1e-323, 1e-322, 1e-321, 1e-320, 1e-319, 1e-318, 1e-317, 1e-316,
+ 1e-315, 1e-314, 1e-313, 1e-312, 1e-311, 1e-310, 1e-309, 1e-308, 1e-307,
+ 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301, 1e-300, 1e-299, 1e-298,
+ 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291, 1e-290, 1e-289,
+ 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281, 1e-280,
+ 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271,
+ 1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262,
+ 1e-261, 1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253,
+ 1e-252, 1e-251, 1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244,
+ 1e-243, 1e-242, 1e-241, 1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235,
+ 1e-234, 1e-233, 1e-232, 1e-231, 1e-230, 1e-229, 1e-228, 1e-227, 1e-226,
+ 1e-225, 1e-224, 1e-223, 1e-222, 1e-221, 1e-220, 1e-219, 1e-218, 1e-217,
+ 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211, 1e-210, 1e-209, 1e-208,
+ 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201, 1e-200, 1e-199,
+ 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191, 1e-190,
+ 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181,
+ 1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172,
+ 1e-171, 1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163,
+ 1e-162, 1e-161, 1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154,
+ 1e-153, 1e-152, 1e-151, 1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145,
+ 1e-144, 1e-143, 1e-142, 1e-141, 1e-140, 1e-139, 1e-138, 1e-137, 1e-136,
+ 1e-135, 1e-134, 1e-133, 1e-132, 1e-131, 1e-130, 1e-129, 1e-128, 1e-127,
+ 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121, 1e-120, 1e-119, 1e-118,
+ 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111, 1e-110, 1e-109,
+ 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101, 1e-100,
+ 1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91,
+ 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82,
+ 1e-81, 1e-80, 1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73,
+ 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64,
+ 1e-63, 1e-62, 1e-61, 1e-60, 1e-59, 1e-58, 1e-57, 1e-56, 1e-55,
+ 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46,
+ 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40, 1e-39, 1e-38, 1e-37,
+ 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28,
+ 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20, 1e-19,
+ 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10,
+ 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
+ 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8,
+ 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17,
+ 1e+18, 1e+19, 1e+20, 1e+21, 1e+22, k1e23, 1e+24, 1e+25, 1e+26,
+ 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35,
+ 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 1e+41, 1e+42, 1e+43, 1e+44,
+ 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53,
+ 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 1e+61, 1e+62,
+ 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71,
+ 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+ 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89,
+ 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98,
+ 1e+99, 1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107,
+ 1e+108, 1e+109, 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116,
+ 1e+117, 1e+118, 1e+119, 1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125,
+ 1e+126, 1e+127, 1e+128, 1e+129, 1e+130, 1e+131, 1e+132, 1e+133, 1e+134,
+ 1e+135, 1e+136, 1e+137, 1e+138, 1e+139, 1e+140, 1e+141, 1e+142, 1e+143,
+ 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149, 1e+150, 1e+151, 1e+152,
+ 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159, 1e+160, 1e+161,
+ 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169, 1e+170,
+ 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179,
+ 1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188,
+ 1e+189, 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197,
+ 1e+198, 1e+199, 1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206,
+ 1e+207, 1e+208, 1e+209, 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215,
+ 1e+216, 1e+217, 1e+218, 1e+219, 1e+220, 1e+221, 1e+222, 1e+223, 1e+224,
+ 1e+225, 1e+226, 1e+227, 1e+228, 1e+229, 1e+230, 1e+231, 1e+232, 1e+233,
+ 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239, 1e+240, 1e+241, 1e+242,
+ 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249, 1e+250, 1e+251,
+ 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259, 1e+260,
+ 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269,
+ 1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278,
+ 1e+279, 1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287,
+ 1e+288, 1e+289, 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296,
+ 1e+297, 1e+298, 1e+299, 1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305,
+ 1e+306, 1e+307, 1e+308,
+};
+
+} // namespace
+
+double Pow10(int exp) {
+ if (exp < -324) {
+ return 0.0;
+ } else if (exp > 308) {
+ return INFINITY;
+ } else {
+ return kPowersOfTen[exp + 324];
+ }
+}
+
+} // namespace strings_internal
+} // namespace absl
diff --git a/absl/strings/internal/pow10_helper.h b/absl/strings/internal/pow10_helper.h
new file mode 100644
index 00000000..39c15392
--- /dev/null
+++ b/absl/strings/internal/pow10_helper.h
@@ -0,0 +1,36 @@
+//
+// 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
+//
+// http://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 test helper library contains a table of powers of 10, to guarantee
+// precise values are computed across the full range of doubles. We can't rely
+// on the pow() function, because not all standard libraries ship a version
+// that is precise.
+#ifndef ABSL_STRINGS_POW10_HELPER_H_
+#define ABSL_STRINGS_POW10_HELPER_H_
+
+#include <vector>
+
+namespace absl {
+namespace strings_internal {
+
+// Computes the precise value of 10^exp. (I.e. the nearest representable
+// double to the exact value, rounding to nearest-even in the (single) case of
+// being exactly halfway between.)
+double Pow10(int exp);
+
+} // namespace strings_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_POW10_HELPER_H_
diff --git a/absl/strings/internal/pow10_helper_test.cc b/absl/strings/internal/pow10_helper_test.cc
new file mode 100644
index 00000000..9a13d524
--- /dev/null
+++ b/absl/strings/internal/pow10_helper_test.cc
@@ -0,0 +1,120 @@
+// 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
+//
+// http://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/strings/internal/pow10_helper.h"
+
+#include <cmath>
+
+#include "gtest/gtest.h"
+#include "absl/strings/str_format.h"
+
+namespace absl {
+namespace strings_internal {
+
+namespace {
+
+struct TestCase {
+ int power; // Testing Pow10(power)
+ uint64_t significand; // Raw bits of the expected value
+ int radix; // significand is adjusted by 2^radix
+};
+
+TEST(Pow10HelperTest, Works) {
+ // The logic in pow10_helper.cc is so simple that theoretically we don't even
+ // need a test. However, we're paranoid and believe that there may be
+ // compilers that don't round floating-point literals correctly, even though
+ // it is specified by the standard. We check various edge cases, just to be
+ // sure.
+ constexpr TestCase kTestCases[] = {
+ // Subnormals
+ {-323, 0x2, -1074},
+ {-322, 0x14, -1074},
+ {-321, 0xca, -1074},
+ {-320, 0x7e8, -1074},
+ {-319, 0x4f10, -1074},
+ {-318, 0x316a2, -1074},
+ {-317, 0x1ee257, -1074},
+ {-316, 0x134d761, -1074},
+ {-315, 0xc1069cd, -1074},
+ {-314, 0x78a42205, -1074},
+ {-313, 0x4b6695433, -1074},
+ {-312, 0x2f201d49fb, -1074},
+ {-311, 0x1d74124e3d1, -1074},
+ {-310, 0x12688b70e62b, -1074},
+ {-309, 0xb8157268fdaf, -1074},
+ {-308, 0x730d67819e8d2, -1074},
+ // Values that are very close to rounding the other way.
+ // Comment shows difference of significand from the true value.
+ {-307, 0x11fa182c40c60d, -1072}, // -.4588
+ {-290, 0x18f2b061aea072, -1016}, // .4854
+ {-276, 0x11BA03F5B21000, -969}, // .4709
+ {-259, 0x1899C2F6732210, -913}, // .4830
+ {-252, 0x1D53844EE47DD1, -890}, // -.4743
+ {-227, 0x1E5297287C2F45, -807}, // -.4708
+ {-198, 0x1322E220A5B17E, -710}, // -.4714
+ {-195, 0x12B010D3E1CF56, -700}, // .4928
+ {-192, 0x123FF06EEA847A, -690}, // .4968
+ {-163, 0x1708D0F84D3DE7, -594}, // -.4977
+ {-145, 0x13FAAC3E3FA1F3, -534}, // -.4785
+ {-111, 0x133D4032C2C7F5, -421}, // .4774
+ {-106, 0x1D5B561574765B, -405}, // -.4869
+ {-104, 0x16EF5B40C2FC77, -398}, // -.4741
+ {-88, 0x197683DF2F268D, -345}, // -.4738
+ {-86, 0x13E497065CD61F, -338}, // .4736
+ {-76, 0x17288E1271F513, -305}, // -.4761
+ {-63, 0x1A53FC9631D10D, -262}, // .4929
+ {-30, 0x14484BFEEBC2A0, -152}, // .4758
+ {-21, 0x12E3B40A0E9B4F, -122}, // -.4916
+ {-5, 0x14F8B588E368F1, -69}, // .4829
+ {23, 0x152D02C7E14AF6, 24}, // -.5000 (exactly, round-to-even)
+ {29, 0x1431E0FAE6D721, 44}, // -.4870
+ {34, 0x1ED09BEAD87C03, 60}, // -.4721
+ {70, 0x172EBAD6DDC73D, 180}, // .4733
+ {105, 0x1BE7ABD3781ECA, 296}, // -.4850
+ {126, 0x17A2ECC414A03F, 366}, // -.4999
+ {130, 0x1CDA62055B2D9E, 379}, // .4855
+ {165, 0x115D847AD00087, 496}, // -.4913
+ {172, 0x14B378469B6732, 519}, // .4818
+ {187, 0x1262DFEEBBB0F9, 569}, // -.4805
+ {210, 0x18557F31326BBB, 645}, // -.4992
+ {212, 0x1302CB5E6F642A, 652}, // -.4838
+ {215, 0x1290BA9A38C7D1, 662}, // -.4881
+ {236, 0x1F736F9B3494E9, 731}, // .4707
+ {244, 0x176EC98994F489, 758}, // .4924
+ {250, 0x1658E3AB795204, 778}, // -.4963
+ {252, 0x117571DDF6C814, 785}, // .4873
+ {254, 0x1B4781EAD1989E, 791}, // -.4887
+ {260, 0x1A03FDE214CAF1, 811}, // .4784
+ {284, 0x1585041B2C477F, 891}, // .4798
+ {304, 0x1D2A1BE4048F90, 957}, // -.4987
+ // Out-of-range values
+ {-324, 0x0, 0},
+ {-325, 0x0, 0},
+ {-326, 0x0, 0},
+ {309, 1, 2000},
+ {310, 1, 2000},
+ {311, 1, 2000},
+ };
+ for (const TestCase& test_case : kTestCases) {
+ EXPECT_EQ(Pow10(test_case.power),
+ std::ldexp(test_case.significand, test_case.radix))
+ << absl::StrFormat("Failure for Pow10(%d): %a vs %a", test_case.power,
+ Pow10(test_case.power),
+ std::ldexp(test_case.significand, test_case.radix));
+ }
+}
+
+} // namespace
+} // namespace strings_internal
+} // namespace absl
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
index 36fc0d64..099326c2 100644
--- a/absl/strings/numbers_test.cc
+++ b/absl/strings/numbers_test.cc
@@ -39,6 +39,7 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/internal/numbers_test_common.h"
+#include "absl/strings/internal/pow10_helper.h"
namespace {
@@ -871,7 +872,7 @@ TEST_F(SimpleDtoaTest, ExhaustiveDoubleToSixDigits) {
}
for (int exponent = -324; exponent <= 308; ++exponent) {
- double powten = pow(10.0, exponent);
+ double powten = absl::strings_internal::Pow10(exponent);
if (powten == 0) powten = 5e-324;
if (kFloatNumCases >= 1e9) {
// The exhaustive test takes a very long time, so log progress.
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel
index f52e9d41..e63b1d16 100644
--- a/absl/synchronization/BUILD.bazel
+++ b/absl/synchronization/BUILD.bazel
@@ -170,18 +170,32 @@ cc_test(
],
)
-cc_test(
- name = "mutex_benchmark",
+cc_library(
+ name = "mutex_benchmark_common",
+ testonly = 1,
srcs = ["mutex_benchmark.cc"],
- copts = ABSL_TEST_COPTS,
- tags = ["benchmark"],
- visibility = ["//visibility:private"],
+ copts = ABSL_DEFAULT_COPTS,
+ visibility = [
+ "//absl/synchronization:__pkg__",
+ ],
deps = [
":synchronization",
":thread_pool",
"//absl/base",
+ "//absl/base:base_internal",
"@com_github_google_benchmark//:benchmark_main",
],
+ alwayslink = 1,
+)
+
+cc_binary(
+ name = "mutex_benchmark",
+ testonly = 1,
+ copts = ABSL_DEFAULT_COPTS,
+ visibility = ["//visibility:private"],
+ deps = [
+ ":mutex_benchmark_common",
+ ],
)
cc_test(
diff --git a/absl/synchronization/mutex_benchmark.cc b/absl/synchronization/mutex_benchmark.cc
index 1e019e00..2652bb97 100644
--- a/absl/synchronization/mutex_benchmark.cc
+++ b/absl/synchronization/mutex_benchmark.cc
@@ -12,16 +12,154 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <cstdint>
+#include <mutex> // NOLINT(build/c++11)
#include <vector>
-#include "benchmark/benchmark.h"
-#include "absl/base/internal/sysinfo.h"
+#include "absl/base/internal/cycleclock.h"
+#include "absl/base/internal/spinlock.h"
#include "absl/synchronization/blocking_counter.h"
#include "absl/synchronization/internal/thread_pool.h"
#include "absl/synchronization/mutex.h"
+#include "benchmark/benchmark.h"
namespace {
+void BM_Mutex(benchmark::State& state) {
+ static absl::Mutex* mu = new absl::Mutex;
+ for (auto _ : state) {
+ absl::MutexLock lock(mu);
+ }
+}
+BENCHMARK(BM_Mutex)->UseRealTime()->Threads(1)->ThreadPerCpu();
+
+static void DelayNs(int64_t ns, int* data) {
+ int64_t end = absl::base_internal::CycleClock::Now() +
+ ns * absl::base_internal::CycleClock::Frequency() / 1e9;
+ while (absl::base_internal::CycleClock::Now() < end) {
+ ++(*data);
+ benchmark::DoNotOptimize(*data);
+ }
+}
+
+template <typename MutexType>
+class RaiiLocker {
+ public:
+ explicit RaiiLocker(MutexType* mu) : mu_(mu) { mu_->Lock(); }
+ ~RaiiLocker() { mu_->Unlock(); }
+ private:
+ MutexType* mu_;
+};
+
+template <>
+class RaiiLocker<std::mutex> {
+ public:
+ explicit RaiiLocker(std::mutex* mu) : mu_(mu) { mu_->lock(); }
+ ~RaiiLocker() { mu_->unlock(); }
+ private:
+ std::mutex* mu_;
+};
+
+template <typename MutexType>
+void BM_Contended(benchmark::State& state) {
+ struct Shared {
+ MutexType mu;
+ int data = 0;
+ };
+ static auto* shared = new Shared;
+ int local = 0;
+ for (auto _ : state) {
+ // Here we model both local work outside of the critical section as well as
+ // some work inside of the critical section. The idea is to capture some
+ // more or less realisitic contention levels.
+ // If contention is too low, the benchmark won't measure anything useful.
+ // If contention is unrealistically high, the benchmark will favor
+ // bad mutex implementations that block and otherwise distract threads
+ // from the mutex and shared state for as much as possible.
+ // To achieve this amount of local work is multiplied by number of threads
+ // to keep ratio between local work and critical section approximately
+ // equal regardless of number of threads.
+ DelayNs(100 * state.threads, &local);
+ RaiiLocker<MutexType> locker(&shared->mu);
+ DelayNs(state.range(0), &shared->data);
+ }
+}
+
+BENCHMARK_TEMPLATE(BM_Contended, absl::Mutex)
+ ->UseRealTime()
+ // ThreadPerCpu poorly handles non-power-of-two CPU counts.
+ ->Threads(1)
+ ->Threads(2)
+ ->Threads(4)
+ ->Threads(6)
+ ->Threads(8)
+ ->Threads(12)
+ ->Threads(16)
+ ->Threads(24)
+ ->Threads(32)
+ ->Threads(48)
+ ->Threads(64)
+ ->Threads(96)
+ ->Threads(128)
+ ->Threads(192)
+ ->Threads(256)
+ // Some empirically chosen amounts of work in critical section.
+ // 1 is low contention, 200 is high contention and few values in between.
+ ->Arg(1)
+ ->Arg(20)
+ ->Arg(50)
+ ->Arg(200);
+
+BENCHMARK_TEMPLATE(BM_Contended, absl::base_internal::SpinLock)
+ ->UseRealTime()
+ // ThreadPerCpu poorly handles non-power-of-two CPU counts.
+ ->Threads(1)
+ ->Threads(2)
+ ->Threads(4)
+ ->Threads(6)
+ ->Threads(8)
+ ->Threads(12)
+ ->Threads(16)
+ ->Threads(24)
+ ->Threads(32)
+ ->Threads(48)
+ ->Threads(64)
+ ->Threads(96)
+ ->Threads(128)
+ ->Threads(192)
+ ->Threads(256)
+ // Some empirically chosen amounts of work in critical section.
+ // 1 is low contention, 200 is high contention and few values in between.
+ ->Arg(1)
+ ->Arg(20)
+ ->Arg(50)
+ ->Arg(200);
+
+BENCHMARK_TEMPLATE(BM_Contended, std::mutex)
+ ->UseRealTime()
+ // ThreadPerCpu poorly handles non-power-of-two CPU counts.
+ ->Threads(1)
+ ->Threads(2)
+ ->Threads(4)
+ ->Threads(6)
+ ->Threads(8)
+ ->Threads(12)
+ ->Threads(16)
+ ->Threads(24)
+ ->Threads(32)
+ ->Threads(48)
+ ->Threads(64)
+ ->Threads(96)
+ ->Threads(128)
+ ->Threads(192)
+ ->Threads(256)
+ // Some empirically chosen amounts of work in critical section.
+ // 1 is low contention, 200 is high contention and few values in between.
+ ->Arg(1)
+ ->Arg(20)
+ ->Arg(50)
+ ->Arg(200);
+
// Measure the overhead of conditions on mutex release (when they must be
// evaluated). Mutex has (some) support for equivalence classes allowing
// Conditions with the same function/argument to potentially not be multiply
@@ -82,13 +220,4 @@ constexpr int kMaxConditionWaiters = 1024;
#endif
BENCHMARK(BM_ConditionWaiters)->RangePair(0, 2, 1, kMaxConditionWaiters);
-void BM_ContendedMutex(benchmark::State& state) {
- static absl::Mutex* mu = new absl::Mutex;
- for (auto _ : state) {
- absl::MutexLock lock(mu);
- }
-}
-BENCHMARK(BM_ContendedMutex)->Threads(1);
-BENCHMARK(BM_ContendedMutex)->ThreadPerCpu();
-
} // namespace
diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h
index 107932f2..f95f4d14 100644
--- a/absl/synchronization/notification.h
+++ b/absl/synchronization/notification.h
@@ -52,6 +52,7 @@
#include <atomic>
+#include "absl/base/macros.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
index 2950c7cd..b77d5ec9 100644
--- a/absl/time/duration.cc
+++ b/absl/time/duration.cc
@@ -78,10 +78,16 @@ constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
// Can't use std::isinfinite() because it doesn't exist on windows.
inline bool IsFinite(double d) {
+ if (std::isnan(d)) return false;
return d != std::numeric_limits<double>::infinity() &&
d != -std::numeric_limits<double>::infinity();
}
+inline bool IsValidDivisor(double d) {
+ if (std::isnan(d)) return false;
+ return d != 0.0;
+}
+
// Can't use std::round() because it is only available in C++11.
// Note that we ignore the possibility of floating-point over/underflow.
template <typename Double>
@@ -455,7 +461,7 @@ Duration& Duration::operator/=(int64_t r) {
}
Duration& Duration::operator/=(double r) {
- if (time_internal::IsInfiniteDuration(*this) || r == 0.0) {
+ if (time_internal::IsInfiniteDuration(*this) || !IsValidDivisor(r)) {
const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
}
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
index 775da91e..61f3c5c0 100644
--- a/absl/time/duration_test.cc
+++ b/absl/time/duration_test.cc
@@ -803,6 +803,40 @@ TEST(Duration, DivisionByZero) {
EXPECT_EQ(-dbl_inf, absl::FDivDuration(-any_dur, zero));
}
+TEST(Duration, NaN) {
+ // Note that IEEE 754 does not define the behavior of a nan's sign when it is
+ // copied, so the code below allows for either + or - InfiniteDuration.
+#define TEST_NAN_HANDLING(NAME, NAN) \
+ do { \
+ const auto inf = absl::InfiniteDuration(); \
+ auto x = NAME(NAN); \
+ EXPECT_TRUE(x == inf || x == -inf); \
+ auto y = NAME(42); \
+ y *= NAN; \
+ EXPECT_TRUE(y == inf || y == -inf); \
+ auto z = NAME(42); \
+ z /= NAN; \
+ EXPECT_TRUE(z == inf || z == -inf); \
+ } while (0)
+
+ const double nan = std::numeric_limits<double>::quiet_NaN();
+ TEST_NAN_HANDLING(absl::Nanoseconds, nan);
+ TEST_NAN_HANDLING(absl::Microseconds, nan);
+ TEST_NAN_HANDLING(absl::Milliseconds, nan);
+ TEST_NAN_HANDLING(absl::Seconds, nan);
+ TEST_NAN_HANDLING(absl::Minutes, nan);
+ TEST_NAN_HANDLING(absl::Hours, nan);
+
+ TEST_NAN_HANDLING(absl::Nanoseconds, -nan);
+ TEST_NAN_HANDLING(absl::Microseconds, -nan);
+ TEST_NAN_HANDLING(absl::Milliseconds, -nan);
+ TEST_NAN_HANDLING(absl::Seconds, -nan);
+ TEST_NAN_HANDLING(absl::Minutes, -nan);
+ TEST_NAN_HANDLING(absl::Hours, -nan);
+
+#undef TEST_NAN_HANDLING
+}
+
TEST(Duration, Range) {
const absl::Duration range = ApproxYears(100 * 1e9);
const absl::Duration range_future = range;
diff --git a/absl/time/time.h b/absl/time/time.h
index 3fa9378f..b86abf27 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -69,6 +69,7 @@
#include <winsock2.h>
#endif
#include <chrono> // NOLINT(build/c++11)
+#include <cmath>
#include <cstdint>
#include <ctime>
#include <ostream>
@@ -411,10 +412,12 @@ Duration Milliseconds(T n) {
}
template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Seconds(T n) {
- if (n >= 0) {
+ if (n >= 0) { // Note: `NaN >= 0` is false.
if (n >= (std::numeric_limits<int64_t>::max)()) return InfiniteDuration();
return time_internal::MakePosDoubleDuration(n);
} else {
+ if (std::isnan(n))
+ return std::signbit(n) ? -InfiniteDuration() : InfiniteDuration();
if (n <= (std::numeric_limits<int64_t>::min)()) return -InfiniteDuration();
return -time_internal::MakePosDoubleDuration(-n);
}
diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h
index eff4fefe..477e5895 100644
--- a/absl/types/internal/variant.h
+++ b/absl/types/internal/variant.h
@@ -15,6 +15,7 @@
// Implementation details of absl/types/variant.h, pulled into a
// separate file to avoid cluttering the top of the API header with
// implementation details.
+//
#ifndef ABSL_TYPES_variant_internal_H_
#define ABSL_TYPES_variant_internal_H_
@@ -1234,23 +1235,29 @@ using VariantCopyBase = absl::conditional_t<
// Base that is dependent on whether or not the move-assign can be trivial.
template <class... T>
using VariantMoveAssignBase = absl::conditional_t<
- absl::disjunction<absl::conjunction<absl::is_move_assignable<Union<T...>>,
- std::is_move_constructible<Union<T...>>,
- std::is_destructible<Union<T...>>>,
- absl::negation<absl::conjunction<
- std::is_move_constructible<T>...,
- absl::is_move_assignable<T>...>>>::value,
+ absl::disjunction<
+ absl::conjunction<absl::is_move_assignable<Union<T...>>,
+ std::is_move_constructible<Union<T...>>,
+ std::is_destructible<Union<T...>>>,
+ absl::negation<absl::conjunction<std::is_move_constructible<T>...,
+ // Note: We're not qualifying this with
+ // absl:: because it doesn't compile
+ // under MSVC.
+ is_move_assignable<T>...>>>::value,
VariantCopyBase<T...>, VariantMoveAssignBaseNontrivial<T...>>;
// Base that is dependent on whether or not the copy-assign can be trivial.
template <class... T>
using VariantCopyAssignBase = absl::conditional_t<
- absl::disjunction<absl::conjunction<absl::is_copy_assignable<Union<T...>>,
- std::is_copy_constructible<Union<T...>>,
- std::is_destructible<Union<T...>>>,
- absl::negation<absl::conjunction<
- std::is_copy_constructible<T>...,
- absl::is_copy_assignable<T>...>>>::value,
+ absl::disjunction<
+ absl::conjunction<absl::is_copy_assignable<Union<T...>>,
+ std::is_copy_constructible<Union<T...>>,
+ std::is_destructible<Union<T...>>>,
+ absl::negation<absl::conjunction<std::is_copy_constructible<T>...,
+ // Note: We're not qualifying this with
+ // absl:: because it doesn't compile
+ // under MSVC.
+ is_copy_assignable<T>...>>>::value,
VariantMoveAssignBase<T...>, VariantCopyAssignBaseNontrivial<T...>>;
template <class... T>
diff --git a/absl/types/variant.h b/absl/types/variant.h
index 28aaef4f..48c5d7bf 100644
--- a/absl/types/variant.h
+++ b/absl/types/variant.h
@@ -82,7 +82,7 @@ namespace absl {
// absl::variant
// -----------------------------------------------------------------------------
//
-// An 'absl::variant` type is a form of type-safe union. An `absl::variant` --
+// An `absl::variant` type is a form of type-safe union. An `absl::variant` --
// except in exceptional cases -- always holds a value of one of its alternative
// types.
//
@@ -136,7 +136,7 @@ void swap(variant<Ts...>& v, variant<Ts...>& w) noexcept(noexcept(v.swap(w))) {
// variant_size
//
-// Returns the number of alterative types available for a given `absl::variant`
+// Returns the number of alternative types available for a given `absl::variant`
// type as a compile-time constant expression. As this is a class template, it
// is not generally useful for accessing the number of alternative types of
// any given `absl::variant` instance.
@@ -454,7 +454,7 @@ class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> {
std::is_object<Tn>...>::value,
"Attempted to instantiate a variant containing a non-object "
"type.");
- // Intentionally not qualifing `negation` with `absl::` to work around a bug
+ // Intentionally not qualifying `negation` with `absl::` to work around a bug
// in MSVC 2015 with inline namespace and variadic template.
static_assert(absl::conjunction<negation<std::is_array<T0> >,
negation<std::is_array<Tn> >...>::value,
@@ -562,7 +562,7 @@ class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> {
// Assignment Operators
- // Copy assignement operator
+ // Copy assignment operator
variant& operator=(const variant& other) = default;
// Move assignment operator