Commit 4b2fbb4a by Abseil Team Committed by Derek Mauro

Export of internal Abseil changes

--
a5af5874c1c5cc02bd2a748d455321f82b6f2a93 by Andy Getzendanner <durandal@google.com>:

fix compile fails with asan and -Wredundant-decls

Import of https://github.com/abseil/abseil-cpp/pull/801

PiperOrigin-RevId: 336693223

--
ed9df42ab2b742386c6692c2bed015374c919d9c by Derek Mauro <dmauro@google.com>:

Fix integer conversion warning

Fixes #814

PiperOrigin-RevId: 336651814

--
0ab4c23884e72dce17b67c1eb520f9dbb802565d by Derek Mauro <dmauro@google.com>:

Internal change

PiperOrigin-RevId: 336585378

--
eba0e3dccd52a6e91bcff84075bef0affc650b74 by Matt Kulukundis <kfm@google.com>:

Add bitset operations to Futex helper.

PiperOrigin-RevId: 336409368

--
8b0709a8b4500bf5f0af4b602d76a298d81645e8 by Abseil Team <absl-team@google.com>:

Fix code indentation in a comment.

PiperOrigin-RevId: 336368167

--
bc3961c87a7e7760c10319a5b0349c279f7ae3ad by Samuel Benzaquen <sbenza@google.com>:

Improve performance of the registry:
 - Reduce contention
 - Reduce memory usage for each flag by `6*sizeof(void*)`.
 - Replace one immortal allocation per-flag with a single one for all the flags
 - Slightly improve single-threaded performance by avoiding the std::map indirections.

PiperOrigin-RevId: 336365904

--
264ad9f28f935aad8b6b1437f8bf804fa9104346 by Abseil Team <absl-team@google.com>:

Fix typo in comment on absl::Condition.

PiperOrigin-RevId: 336311680

--
b5b808a8c75ca0df7b09eff9a423ec171d80f771 by Derek Mauro <dmauro@google.com>:

Add missing Apache license headers

PiperOrigin-RevId: 336294980

--
89446c3a4793df8b95060385cf3e219357c3db1d by Andy Soffer <asoffer@google.com>:

Internal changes

PiperOrigin-RevId: 336287465

--
57c8be4e294881bc79a6a44b8e4bf7ecbb19b9b9 by Matt Kulukundis <kfm@google.com>:

Extract Futex from an implementation detail of Wait to a private interface.

PiperOrigin-RevId: 336123209
GitOrigin-RevId: a5af5874c1c5cc02bd2a748d455321f82b6f2a93
Change-Id: Ie5a0ebe28e571814e3e11d4c05ca308523ccf311
parent e493d6ac
...@@ -250,6 +250,7 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -250,6 +250,7 @@ set(ABSL_INTERNAL_DLL_FILES
"synchronization/notification.h" "synchronization/notification.h"
"synchronization/internal/create_thread_identity.cc" "synchronization/internal/create_thread_identity.cc"
"synchronization/internal/create_thread_identity.h" "synchronization/internal/create_thread_identity.h"
"synchronization/internal/futex.h"
"synchronization/internal/graphcycles.cc" "synchronization/internal/graphcycles.cc"
"synchronization/internal/graphcycles.h" "synchronization/internal/graphcycles.h"
"synchronization/internal/kernel_timeout.h" "synchronization/internal/kernel_timeout.h"
......
...@@ -123,9 +123,7 @@ double UnscaledCycleClock::Frequency() { ...@@ -123,9 +123,7 @@ double UnscaledCycleClock::Frequency() {
#pragma intrinsic(__rdtsc) #pragma intrinsic(__rdtsc)
int64_t UnscaledCycleClock::Now() { int64_t UnscaledCycleClock::Now() { return __rdtsc(); }
return __rdtsc();
}
double UnscaledCycleClock::Frequency() { double UnscaledCycleClock::Frequency() {
return base_internal::NominalCPUFrequency(); return base_internal::NominalCPUFrequency();
......
...@@ -128,8 +128,10 @@ TEST(Layout, ElementTypes) { ...@@ -128,8 +128,10 @@ TEST(Layout, ElementTypes) {
{ {
using L = Layout<int32_t, int32_t>; using L = Layout<int32_t, int32_t>;
SameType<std::tuple<int32_t, int32_t>, L::ElementTypes>(); SameType<std::tuple<int32_t, int32_t>, L::ElementTypes>();
SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial())::ElementTypes>(); SameType<std::tuple<int32_t, int32_t>,
SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial(0))::ElementTypes>(); decltype(L::Partial())::ElementTypes>();
SameType<std::tuple<int32_t, int32_t>,
decltype(L::Partial(0))::ElementTypes>();
} }
{ {
using L = Layout<int8_t, int32_t, Int128>; using L = Layout<int8_t, int32_t, Int128>;
...@@ -368,18 +370,21 @@ TEST(Layout, PointerByIndex) { ...@@ -368,18 +370,21 @@ TEST(Layout, PointerByIndex) {
{ {
using L = Layout<int32_t>; using L = Layout<int32_t>;
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p)))); EXPECT_EQ(0,
Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<0>(p))));
} }
{ {
using L = Layout<int32_t, int32_t>; using L = Layout<int32_t, int32_t>;
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
EXPECT_EQ(0, EXPECT_EQ(0,
Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p)))); Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
EXPECT_EQ(12, EXPECT_EQ(12,
Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p)))); Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
EXPECT_EQ(
0, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
EXPECT_EQ(
12, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<0>(p))));
EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<1>(p)))); EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<1>(p))));
} }
...@@ -387,39 +392,44 @@ TEST(Layout, PointerByIndex) { ...@@ -387,39 +392,44 @@ TEST(Layout, PointerByIndex) {
using L = Layout<int8_t, int32_t, Int128>; using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p)))); EXPECT_EQ(0,
Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<0>(p))));
EXPECT_EQ(4, Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p)))); EXPECT_EQ(4,
Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<0>(p))));
EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p)))); EXPECT_EQ(8,
Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p))));
EXPECT_EQ(0, EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<0>(p)))); Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<0>(p))));
EXPECT_EQ(0, EXPECT_EQ(
Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p)))); 0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
EXPECT_EQ(0, EXPECT_EQ(0,
Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<2>(p)))); Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<2>(p))));
EXPECT_EQ(0, EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<0>(p)))); Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<0>(p))));
EXPECT_EQ(4, EXPECT_EQ(
Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p)))); 4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
EXPECT_EQ(8, EXPECT_EQ(8,
Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<2>(p)))); Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<2>(p))));
EXPECT_EQ(0, EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<0>(p)))); Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<0>(p))));
EXPECT_EQ(8, EXPECT_EQ(
Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p)))); 8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
EXPECT_EQ(24, EXPECT_EQ(24,
Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<2>(p)))); Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<2>(p))));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p)))); 0, Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p)))); 0,
Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<const Int128*>(L::Partial(0, 0, 0).Pointer<2>(p)))); 0, Distance(p, Type<const Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p)))); 0, Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
EXPECT_EQ( EXPECT_EQ(
4, Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p)))); 4,
Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
EXPECT_EQ( EXPECT_EQ(
8, Distance(p, Type<const Int128*>(L::Partial(1, 0, 0).Pointer<2>(p)))); 8, Distance(p, Type<const Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
EXPECT_EQ( EXPECT_EQ(
...@@ -428,7 +438,8 @@ TEST(Layout, PointerByIndex) { ...@@ -428,7 +438,8 @@ TEST(Layout, PointerByIndex) {
24, 24,
Distance(p, Type<const Int128*>(L::Partial(5, 3, 1).Pointer<2>(p)))); Distance(p, Type<const Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
EXPECT_EQ( EXPECT_EQ(
8, Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p)))); 8,
Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L(5, 3, 1).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L(5, 3, 1).Pointer<0>(p))));
EXPECT_EQ(24, Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<2>(p)))); EXPECT_EQ(24, Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<2>(p))));
EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<1>(p)))); EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<1>(p))));
...@@ -439,75 +450,78 @@ TEST(Layout, PointerByType) { ...@@ -439,75 +450,78 @@ TEST(Layout, PointerByType) {
alignas(max_align_t) const unsigned char p[100] = {}; alignas(max_align_t) const unsigned char p[100] = {};
{ {
using L = Layout<int32_t>; using L = Layout<int32_t>;
EXPECT_EQ(0, EXPECT_EQ(
Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p)))); 0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p))));
EXPECT_EQ(0, EXPECT_EQ(
0,
Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p)))); Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<int32_t>(p)))); EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<int32_t>(p))));
} }
{ {
using L = Layout<int8_t, int32_t, Int128>; using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p)))); EXPECT_EQ(
EXPECT_EQ(0, 0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p))));
Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p)))); EXPECT_EQ(
EXPECT_EQ(0, 0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
EXPECT_EQ(
0,
Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p)))); Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
EXPECT_EQ(0, EXPECT_EQ(
Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p)))); 0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
EXPECT_EQ(4, EXPECT_EQ(
4,
Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p)))); Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
EXPECT_EQ(8,
Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p)))); 0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p)))); 8,
Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<Int128>(p)))); Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
L::Partial(0, 0).Pointer<int32_t>(p))));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p)))); 0,
Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
EXPECT_EQ( EXPECT_EQ(
4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p)))); 0,
Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
L::Partial(1, 0).Pointer<int32_t>(p))));
EXPECT_EQ( EXPECT_EQ(
8, 8,
Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<Int128>(p)))); Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p)))); 0,
EXPECT_EQ( Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p)))); EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
L::Partial(5, 3).Pointer<int32_t>(p))));
EXPECT_EQ( EXPECT_EQ(
24, 24,
Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<Int128>(p)))); Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
EXPECT_EQ( EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
0, L::Partial(0, 0, 0).Pointer<int8_t>(p))));
Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p)))); EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
EXPECT_EQ( L::Partial(0, 0, 0).Pointer<int32_t>(p))));
0,
Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<const Int128*>( EXPECT_EQ(0, Distance(p, Type<const Int128*>(
L::Partial(0, 0, 0).Pointer<Int128>(p)))); L::Partial(0, 0, 0).Pointer<Int128>(p))));
EXPECT_EQ( EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
0, L::Partial(1, 0, 0).Pointer<int8_t>(p))));
Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p)))); EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
EXPECT_EQ( L::Partial(1, 0, 0).Pointer<int32_t>(p))));
4,
Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(8, Distance(p, Type<const Int128*>( EXPECT_EQ(8, Distance(p, Type<const Int128*>(
L::Partial(1, 0, 0).Pointer<Int128>(p)))); L::Partial(1, 0, 0).Pointer<Int128>(p))));
EXPECT_EQ( EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
0, L::Partial(5, 3, 1).Pointer<int8_t>(p))));
Distance(p, Type<const int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
EXPECT_EQ(24, Distance(p, Type<const Int128*>( EXPECT_EQ(24, Distance(p, Type<const Int128*>(
L::Partial(5, 3, 1).Pointer<Int128>(p)))); L::Partial(5, 3, 1).Pointer<Int128>(p))));
EXPECT_EQ( EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
8, L::Partial(5, 3, 1).Pointer<int32_t>(p))));
Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
EXPECT_EQ(24, EXPECT_EQ(24,
Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<Int128>(p)))); Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p)))); EXPECT_EQ(
8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
} }
} }
...@@ -548,15 +562,18 @@ TEST(Layout, MutablePointerByIndex) { ...@@ -548,15 +562,18 @@ TEST(Layout, MutablePointerByIndex) {
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<1>(p)))); EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
EXPECT_EQ(24, Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<2>(p)))); EXPECT_EQ(24, Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<2>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p)))); EXPECT_EQ(0,
Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<2>(p)))); EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p)))); EXPECT_EQ(4,
Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<2>(p)))); EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p))));
EXPECT_EQ(24, EXPECT_EQ(24,
Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<2>(p)))); Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p)))); EXPECT_EQ(8,
Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<0>(p))));
EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<2>(p)))); EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<2>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<1>(p)))); EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<1>(p))));
...@@ -568,47 +585,60 @@ TEST(Layout, MutablePointerByType) { ...@@ -568,47 +585,60 @@ TEST(Layout, MutablePointerByType) {
{ {
using L = Layout<int32_t>; using L = Layout<int32_t>;
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<int32_t>(p)))); EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p)))); EXPECT_EQ(0,
Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<int32_t>(p)))); EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<int32_t>(p))));
} }
{ {
using L = Layout<int8_t, int32_t, Int128>; using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<int8_t>(p)))); EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<int8_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<int8_t>(p)))); EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p)))); EXPECT_EQ(0,
Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<int8_t>(p)))); EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p)))); EXPECT_EQ(4,
Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<int8_t>(p)))); EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p)))); EXPECT_EQ(8,
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p)))); Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p)))); EXPECT_EQ(0,
Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
EXPECT_EQ(
0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(0, EXPECT_EQ(0,
Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<Int128>(p)))); Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p)))); EXPECT_EQ(0,
EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p)))); Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
EXPECT_EQ(
4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
EXPECT_EQ(8, EXPECT_EQ(8,
Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<Int128>(p)))); Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p)))); EXPECT_EQ(0,
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p)))); Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
EXPECT_EQ(
8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
EXPECT_EQ(24, EXPECT_EQ(24,
Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<Int128>(p)))); Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
EXPECT_EQ(0, EXPECT_EQ(
Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p)))); 0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
EXPECT_EQ(0, EXPECT_EQ(
0,
Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p)))); Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<Int128>(p)))); 0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<Int128>(p))));
EXPECT_EQ(0, EXPECT_EQ(
Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p)))); 0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
EXPECT_EQ(4, EXPECT_EQ(
4,
Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p)))); Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ( EXPECT_EQ(
8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<Int128>(p)))); 8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<Int128>(p))));
EXPECT_EQ(0, EXPECT_EQ(
Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p)))); 0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
EXPECT_EQ( EXPECT_EQ(
24, Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<Int128>(p)))); 24, Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<Int128>(p))));
EXPECT_EQ(8, EXPECT_EQ(
8,
Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p)))); Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<int8_t>(p)))); EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<int8_t>(p))));
EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<Int128>(p)))); EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
...@@ -790,67 +820,72 @@ TEST(Layout, SliceByIndexData) { ...@@ -790,67 +820,72 @@ TEST(Layout, SliceByIndexData) {
{ {
using L = Layout<int32_t>; using L = Layout<int32_t>;
EXPECT_EQ( EXPECT_EQ(
0, 0, Distance(
Distance(p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data())); p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0, Distance(
Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data())); p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data())); EXPECT_EQ(0,
Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data()));
} }
{ {
using L = Layout<int32_t, int32_t>; using L = Layout<int32_t, int32_t>;
EXPECT_EQ( EXPECT_EQ(
0, 0, Distance(
Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data())); p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance(p, Distance(
Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data())); p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
12, 12,
Distance(p, Distance(
Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data())); p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
EXPECT_EQ(0, EXPECT_EQ(
Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data())); 0, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data()));
EXPECT_EQ(12, EXPECT_EQ(
Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data())); 12, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data()));
} }
{ {
using L = Layout<int8_t, int32_t, Int128>; using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ( EXPECT_EQ(
0, 0, Distance(
Distance(p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data())); p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0, Distance(
Distance(p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data())); p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance( 0, Distance(
p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(
p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data())); p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance(p, Distance(
Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data())); p, Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance( 0,
Distance(
p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data())); p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
4, 4,
Distance(p, Distance(
Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data())); p, Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance( 0,
Distance(
p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data())); p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
8, 8,
Distance(p, Distance(
Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data())); p, Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(
p, Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data())); p,
Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(
...@@ -864,7 +899,8 @@ TEST(Layout, SliceByIndexData) { ...@@ -864,7 +899,8 @@ TEST(Layout, SliceByIndexData) {
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(
p, Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data())); p,
Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
4, 4,
Distance( Distance(
...@@ -878,7 +914,8 @@ TEST(Layout, SliceByIndexData) { ...@@ -878,7 +914,8 @@ TEST(Layout, SliceByIndexData) {
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(
p, Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data())); p,
Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
24, 24,
Distance( Distance(
...@@ -890,12 +927,14 @@ TEST(Layout, SliceByIndexData) { ...@@ -890,12 +927,14 @@ TEST(Layout, SliceByIndexData) {
p, p,
Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data())); Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data())); 0,
Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
24, 24,
Distance(p, Type<Span<const Int128>>(L(5, 3, 1).Slice<2>(p)).data())); Distance(p, Type<Span<const Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
8, Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data())); 8,
Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
} }
} }
...@@ -906,97 +945,93 @@ TEST(Layout, SliceByTypeData) { ...@@ -906,97 +945,93 @@ TEST(Layout, SliceByTypeData) {
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(
p, Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data())); p,
Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(
p, Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data())); p,
Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data())); 0,
Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data()));
} }
{ {
using L = Layout<int8_t, int32_t, Int128>; using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ( EXPECT_EQ(
0, Distance(
p, Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0, 0,
Distance( Distance(
p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data())); p,
Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(
p, p,
Type<Span<const int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data())); Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(
p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
4,
Distance(
p, p,
Type<Span<const int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data())); Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p))
p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data())); .data()));
EXPECT_EQ( EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
8, L::Partial(0, 0).Slice<int32_t>(p))
Distance( .data()));
p,
Type<Span<const int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p))
p, .data()));
Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data())); EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
L::Partial(1, 0).Slice<int32_t>(p))
.data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance(p, Type<Span<const int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)) Distance(p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p))
.data()));
EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
L::Partial(5, 3).Slice<int32_t>(p))
.data()));
EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
L::Partial(0, 0, 0).Slice<int8_t>(p))
.data()));
EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
L::Partial(0, 0, 0).Slice<int32_t>(p))
.data())); .data()));
EXPECT_EQ(0, Distance(p, Type<Span<const Int128>>( EXPECT_EQ(0, Distance(p, Type<Span<const Int128>>(
L::Partial(0, 0, 0).Slice<Int128>(p)) L::Partial(0, 0, 0).Slice<Int128>(p))
.data())); .data()));
EXPECT_EQ( EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
0, L::Partial(1, 0, 0).Slice<int8_t>(p))
Distance( .data()));
p, EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data())); L::Partial(1, 0, 0).Slice<int32_t>(p))
EXPECT_EQ(
4,
Distance(p, Type<Span<const int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p))
.data())); .data()));
EXPECT_EQ(8, Distance(p, Type<Span<const Int128>>( EXPECT_EQ(8, Distance(p, Type<Span<const Int128>>(
L::Partial(1, 0, 0).Slice<Int128>(p)) L::Partial(1, 0, 0).Slice<Int128>(p))
.data())); .data()));
EXPECT_EQ( EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
0, L::Partial(5, 3, 1).Slice<int8_t>(p))
Distance( .data()));
p,
Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
EXPECT_EQ(24, Distance(p, Type<Span<const Int128>>( EXPECT_EQ(24, Distance(p, Type<Span<const Int128>>(
L::Partial(5, 3, 1).Slice<Int128>(p)) L::Partial(5, 3, 1).Slice<Int128>(p))
.data())); .data()));
EXPECT_EQ( EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
8, L::Partial(5, 3, 1).Slice<int32_t>(p))
Distance(p, Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p))
.data())); .data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data())); Distance(p,
Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
24, 24,
Distance(p, Distance(p,
Type<Span<const Int128>>(L(5, 3, 1).Slice<Int128>(p)).data())); Type<Span<const Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
8, Distance( 8,
Distance(
p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data())); p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
} }
} }
...@@ -1005,18 +1040,19 @@ TEST(Layout, MutableSliceByIndexData) { ...@@ -1005,18 +1040,19 @@ TEST(Layout, MutableSliceByIndexData) {
alignas(max_align_t) unsigned char p[100]; alignas(max_align_t) unsigned char p[100];
{ {
using L = Layout<int32_t>; using L = Layout<int32_t>;
EXPECT_EQ(0, EXPECT_EQ(
Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data())); 0, Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ(0, EXPECT_EQ(
Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data())); 0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<0>(p)).data())); EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<0>(p)).data()));
} }
{ {
using L = Layout<int32_t, int32_t>; using L = Layout<int32_t, int32_t>;
EXPECT_EQ(0,
Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data())); 0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
12, 12,
Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<1>(p)).data())); Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
...@@ -1025,55 +1061,63 @@ TEST(Layout, MutableSliceByIndexData) { ...@@ -1025,55 +1061,63 @@ TEST(Layout, MutableSliceByIndexData) {
} }
{ {
using L = Layout<int8_t, int32_t, Int128>; using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0,
Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ(0,
Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
EXPECT_EQ(0,
Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data())); 0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data())); 0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
4, Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data())); 0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data())); 0,
Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
8, Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data())); 0,
Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance(p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data())); Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
EXPECT_EQ(
4,
Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance(p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data())); Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
EXPECT_EQ(
8,
Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance( 0, Distance(
p, Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data())); p, Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0, Distance(
Distance(p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data())); p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
4, 4, Distance(
Distance(p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data())); p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
8, Distance( 8, Distance(
p, Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data())); p, Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0, Distance(
Distance(p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data())); p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
24, Distance( 24, Distance(
p, Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data())); p, Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
8, 8, Distance(
Distance(p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data())); p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
EXPECT_EQ(0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data())); EXPECT_EQ(0,
Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ(24, EXPECT_EQ(24,
Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<2>(p)).data())); Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
EXPECT_EQ(8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data())); EXPECT_EQ(8,
Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
} }
} }
...@@ -1082,66 +1126,84 @@ TEST(Layout, MutableSliceByTypeData) { ...@@ -1082,66 +1126,84 @@ TEST(Layout, MutableSliceByTypeData) {
{ {
using L = Layout<int32_t>; using L = Layout<int32_t>;
EXPECT_EQ( EXPECT_EQ(
0, 0, Distance(
Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data())); p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0, Distance(
Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data())); p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data())); EXPECT_EQ(0,
Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data()));
} }
{ {
using L = Layout<int8_t, int32_t, Int128>; using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data())); 0,
Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data())); 0,
Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data())); 0,
Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data())); Distance(p,
Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance( 0,
Distance(
p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data())); p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data())); Distance(p,
Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
4, Distance( 4,
Distance(
p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data())); p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data())); Distance(p,
Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
8, Distance( 8,
Distance(
p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data())); p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance( 0,
p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data())); Distance(
p,
Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(
p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data())); p,
Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, 0,
Distance( Distance(
p, p,
Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<Int128>(p)).data())); Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<Int128>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance( 0,
p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data())); Distance(
p,
Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
4, 4,
Distance( Distance(
p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data())); p,
Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
8, 8,
Distance( Distance(
p, p,
Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<Int128>(p)).data())); Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<Int128>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
0, Distance( 0,
p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data())); Distance(
p,
Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
24, 24,
Distance( Distance(
...@@ -1150,14 +1212,16 @@ TEST(Layout, MutableSliceByTypeData) { ...@@ -1150,14 +1212,16 @@ TEST(Layout, MutableSliceByTypeData) {
EXPECT_EQ( EXPECT_EQ(
8, 8,
Distance( Distance(
p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data())); p,
EXPECT_EQ(0, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data()));
Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data())); EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
24, 24,
Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<Int128>(p)).data())); Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
EXPECT_EQ( EXPECT_EQ(
8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data())); 8,
Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
} }
} }
...@@ -1256,15 +1320,15 @@ TEST(Layout, MutableSlices) { ...@@ -1256,15 +1320,15 @@ TEST(Layout, MutableSlices) {
} }
{ {
const auto x = L::Partial(1, 2, 3); const auto x = L::Partial(1, 2, 3);
EXPECT_THAT( EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
(Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))), x.Slices(p))),
Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
IsSameSlice(x.Slice<2>(p)))); IsSameSlice(x.Slice<2>(p))));
} }
{ {
const L x(1, 2, 3); const L x(1, 2, 3);
EXPECT_THAT( EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
(Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))), x.Slices(p))),
Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
IsSameSlice(x.Slice<2>(p)))); IsSameSlice(x.Slice<2>(p))));
} }
...@@ -1398,7 +1462,8 @@ TEST(Layout, DebugString) { ...@@ -1398,7 +1462,8 @@ TEST(Layout, DebugString) {
x.DebugString()); x.DebugString());
} }
{ {
constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3); constexpr auto x =
Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
EXPECT_EQ( EXPECT_EQ(
"@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; " "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
"@16" + "@16" +
...@@ -1406,7 +1471,8 @@ TEST(Layout, DebugString) { ...@@ -1406,7 +1471,8 @@ TEST(Layout, DebugString) {
x.DebugString()); x.DebugString());
} }
{ {
constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4); constexpr auto x =
Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
EXPECT_EQ( EXPECT_EQ(
"@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; " "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
"@16" + "@16" +
......
...@@ -847,7 +847,8 @@ TEST(Table, EraseMaintainsValidIterator) { ...@@ -847,7 +847,8 @@ TEST(Table, EraseMaintainsValidIterator) {
std::vector<int64_t> CollectBadMergeKeys(size_t N) { std::vector<int64_t> CollectBadMergeKeys(size_t N) {
static constexpr int kGroupSize = Group::kWidth - 1; static constexpr int kGroupSize = Group::kWidth - 1;
auto topk_range = [](size_t b, size_t e, IntTable* t) -> std::vector<int64_t> { auto topk_range = [](size_t b, size_t e,
IntTable* t) -> std::vector<int64_t> {
for (size_t i = b; i != e; ++i) { for (size_t i = b; i != e; ++i) {
t->emplace(i); t->emplace(i);
} }
...@@ -1001,8 +1002,8 @@ using ProbeStatsPerSize = std::map<size_t, ProbeStats>; ...@@ -1001,8 +1002,8 @@ using ProbeStatsPerSize = std::map<size_t, ProbeStats>;
// 1. Create new table and reserve it to keys.size() * 2 // 1. Create new table and reserve it to keys.size() * 2
// 2. Insert all keys xored with seed // 2. Insert all keys xored with seed
// 3. Collect ProbeStats from final table. // 3. Collect ProbeStats from final table.
ProbeStats CollectProbeStatsOnKeysXoredWithSeed(const std::vector<int64_t>& keys, ProbeStats CollectProbeStatsOnKeysXoredWithSeed(
size_t num_iters) { const std::vector<int64_t>& keys, size_t num_iters) {
const size_t reserve_size = keys.size() * 2; const size_t reserve_size = keys.size() * 2;
ProbeStats stats; ProbeStats stats;
......
...@@ -118,16 +118,14 @@ bool RemoveAllSymbolDecorators(void); ...@@ -118,16 +118,14 @@ bool RemoveAllSymbolDecorators(void);
// filename != nullptr // filename != nullptr
// //
// Returns true if the file was successfully registered. // Returns true if the file was successfully registered.
bool RegisterFileMappingHint( bool RegisterFileMappingHint(const void* start, const void* end,
const void* start, const void* end, uint64_t offset, const char* filename); uint64_t offset, const char* filename);
// Looks up the file mapping registered by RegisterFileMappingHint for an // Looks up the file mapping registered by RegisterFileMappingHint for an
// address range. If there is one, the file name is stored in *filename and // address range. If there is one, the file name is stored in *filename and
// *start and *end are modified to reflect the registered mapping. Returns // *start and *end are modified to reflect the registered mapping. Returns
// whether any hint was found. // whether any hint was found.
bool GetFileMappingHint(const void** start, bool GetFileMappingHint(const void** start, const void** end, uint64_t* offset,
const void** end,
uint64_t * offset,
const char** filename); const char** filename);
} // namespace debugging_internal } // namespace debugging_internal
......
...@@ -381,6 +381,8 @@ cc_binary( ...@@ -381,6 +381,8 @@ cc_binary(
deps = [ deps = [
":flag", ":flag",
":marshalling", ":marshalling",
":parse",
":reflection",
"//absl/strings", "//absl/strings",
"//absl/time", "//absl/time",
"//absl/types:optional", "//absl/types:optional",
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include "absl/flags/flag.h" #include "absl/flags/flag.h"
#include "absl/flags/marshalling.h" #include "absl/flags/marshalling.h"
#include "absl/flags/parse.h"
#include "absl/flags/reflection.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/time/time.h" #include "absl/time/time.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
...@@ -103,6 +105,23 @@ std::string AbslUnparseFlag(const UDT&) { return ""; } ...@@ -103,6 +105,23 @@ std::string AbslUnparseFlag(const UDT&) { return ""; }
BENCHMARKED_TYPES(FLAG_DEF) BENCHMARKED_TYPES(FLAG_DEF)
// Register thousands of flags to bloat up the size of the registry.
// This mimics real life production binaries.
#define DEFINE_FLAG_0(name) ABSL_FLAG(int, name, 0, "");
#define DEFINE_FLAG_1(name) DEFINE_FLAG_0(name##0) DEFINE_FLAG_0(name##1)
#define DEFINE_FLAG_2(name) DEFINE_FLAG_1(name##0) DEFINE_FLAG_1(name##1)
#define DEFINE_FLAG_3(name) DEFINE_FLAG_2(name##0) DEFINE_FLAG_2(name##1)
#define DEFINE_FLAG_4(name) DEFINE_FLAG_3(name##0) DEFINE_FLAG_3(name##1)
#define DEFINE_FLAG_5(name) DEFINE_FLAG_4(name##0) DEFINE_FLAG_4(name##1)
#define DEFINE_FLAG_6(name) DEFINE_FLAG_5(name##0) DEFINE_FLAG_5(name##1)
#define DEFINE_FLAG_7(name) DEFINE_FLAG_6(name##0) DEFINE_FLAG_6(name##1)
#define DEFINE_FLAG_8(name) DEFINE_FLAG_7(name##0) DEFINE_FLAG_7(name##1)
#define DEFINE_FLAG_9(name) DEFINE_FLAG_8(name##0) DEFINE_FLAG_8(name##1)
#define DEFINE_FLAG_10(name) DEFINE_FLAG_9(name##0) DEFINE_FLAG_9(name##1)
#define DEFINE_FLAG_11(name) DEFINE_FLAG_10(name##0) DEFINE_FLAG_10(name##1)
#define DEFINE_FLAG_12(name) DEFINE_FLAG_11(name##0) DEFINE_FLAG_11(name##1)
DEFINE_FLAG_12(bloat_flag_);
namespace { namespace {
#define BM_GetFlag(T) \ #define BM_GetFlag(T) \
...@@ -115,6 +134,20 @@ namespace { ...@@ -115,6 +134,20 @@ namespace {
BENCHMARKED_TYPES(BM_GetFlag) BENCHMARKED_TYPES(BM_GetFlag)
void BM_ThreadedFindCommandLineFlag(benchmark::State& state) {
char dummy[] = "dummy";
char* argv[] = {dummy};
// We need to ensure that flags have been parsed. That is where the registry
// is finalized.
absl::ParseCommandLine(1, argv);
for (auto s : state) {
benchmark::DoNotOptimize(
absl::FindCommandLineFlag("bloat_flag_010101010101"));
}
}
BENCHMARK(BM_ThreadedFindCommandLineFlag)->ThreadRange(1, 16);
} // namespace } // namespace
#define InvokeGetFlag(T) \ #define InvokeGetFlag(T) \
......
...@@ -30,9 +30,6 @@ namespace absl { ...@@ -30,9 +30,6 @@ namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace flags_internal { namespace flags_internal {
// Executes specified visitor for each non-retired flag in the registry.
// Requires the caller hold the registry lock.
void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor);
// Executes specified visitor for each non-retired flag in the registry. While // Executes specified visitor for each non-retired flag in the registry. While
// callback are executed, the registry is locked and can't be changed. // callback are executed, the registry is locked and can't be changed.
void ForEachFlag(std::function<void(CommandLineFlag&)> visitor); void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
...@@ -41,6 +38,8 @@ void ForEachFlag(std::function<void(CommandLineFlag&)> visitor); ...@@ -41,6 +38,8 @@ void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
bool RegisterCommandLineFlag(CommandLineFlag&); bool RegisterCommandLineFlag(CommandLineFlag&);
void FinalizeRegistry();
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Retired registrations: // Retired registrations:
// //
......
...@@ -611,6 +611,11 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], ...@@ -611,6 +611,11 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
OnUndefinedFlag on_undef_flag) { OnUndefinedFlag on_undef_flag) {
ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]"); ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
// Once parsing has started we will not have more flag registrations.
// If we did, they would be missing during parsing, which is a problem on
// itself.
flags_internal::FinalizeRegistry();
// This routine does not return anything since we abort on failure. // This routine does not return anything since we abort on failure.
CheckDefaultValuesParsingRoundtrip(); CheckDefaultValuesParsingRoundtrip();
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <assert.h> #include <assert.h>
#include <atomic>
#include <map> #include <map>
#include <string> #include <string>
...@@ -56,21 +57,23 @@ class FlagRegistry { ...@@ -56,21 +57,23 @@ class FlagRegistry {
// Returns the flag object for the specified name, or nullptr if not found. // Returns the flag object for the specified name, or nullptr if not found.
// Will emit a warning if a 'retired' flag is specified. // Will emit a warning if a 'retired' flag is specified.
CommandLineFlag* FindFlagLocked(absl::string_view name); CommandLineFlag* FindFlag(absl::string_view name);
static FlagRegistry& GlobalRegistry(); // returns a singleton registry static FlagRegistry& GlobalRegistry(); // returns a singleton registry
private: private:
friend class flags_internal::FlagSaverImpl; // reads all the flags in order friend class flags_internal::FlagSaverImpl; // reads all the flags in order
// to copy them // to copy them
friend void ForEachFlagUnlocked( friend void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
std::function<void(CommandLineFlag&)> visitor); friend void FinalizeRegistry();
// The map from name to flag, for FindFlagLocked(). // The map from name to flag, for FindFlag().
using FlagMap = std::map<absl::string_view, CommandLineFlag*>; using FlagMap = std::map<absl::string_view, CommandLineFlag*>;
using FlagIterator = FlagMap::iterator; using FlagIterator = FlagMap::iterator;
using FlagConstIterator = FlagMap::const_iterator; using FlagConstIterator = FlagMap::const_iterator;
FlagMap flags_; FlagMap flags_;
std::vector<CommandLineFlag*> flat_flags_;
std::atomic<bool> finalized_flags_{false};
absl::Mutex lock_; absl::Mutex lock_;
...@@ -79,15 +82,6 @@ class FlagRegistry { ...@@ -79,15 +82,6 @@ class FlagRegistry {
FlagRegistry& operator=(const FlagRegistry&); FlagRegistry& operator=(const FlagRegistry&);
}; };
CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
FlagConstIterator i = flags_.find(name);
if (i == flags_.end()) {
return nullptr;
}
return i->second;
}
namespace { namespace {
class FlagRegistryLock { class FlagRegistryLock {
...@@ -101,8 +95,24 @@ class FlagRegistryLock { ...@@ -101,8 +95,24 @@ class FlagRegistryLock {
} // namespace } // namespace
CommandLineFlag* FlagRegistry::FindFlag(absl::string_view name) {
if (finalized_flags_.load(std::memory_order_acquire)) {
// We could save some gcus here if we make `Name()` be non-virtual.
// We could move the `const char*` name to the base class.
auto it = std::partition_point(
flat_flags_.begin(), flat_flags_.end(),
[=](CommandLineFlag* f) { return f->Name() < name; });
if (it != flat_flags_.end() && (*it)->Name() == name) return *it;
}
FlagRegistryLock frl(*this);
auto it = flags_.find(name);
return it != flags_.end() ? it->second : nullptr;
}
void FlagRegistry::RegisterFlag(CommandLineFlag& flag) { void FlagRegistry::RegisterFlag(CommandLineFlag& flag) {
FlagRegistryLock registry_lock(*this); FlagRegistryLock registry_lock(*this);
std::pair<FlagIterator, bool> ins = std::pair<FlagIterator, bool> ins =
flags_.insert(FlagMap::value_type(flag.Name(), &flag)); flags_.insert(FlagMap::value_type(flag.Name(), &flag));
if (ins.second == false) { // means the name was already in the map if (ins.second == false) { // means the name was already in the map
...@@ -152,18 +162,15 @@ FlagRegistry& FlagRegistry::GlobalRegistry() { ...@@ -152,18 +162,15 @@ FlagRegistry& FlagRegistry::GlobalRegistry() {
// -------------------------------------------------------------------- // --------------------------------------------------------------------
void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor) { void ForEachFlag(std::function<void(CommandLineFlag&)> visitor) {
FlagRegistry& registry = FlagRegistry::GlobalRegistry(); FlagRegistry& registry = FlagRegistry::GlobalRegistry();
for (FlagRegistry::FlagConstIterator i = registry.flags_.begin();
i != registry.flags_.end(); ++i) { if (registry.finalized_flags_.load(std::memory_order_acquire)) {
visitor(*i->second); for (const auto& i : registry.flat_flags_) visitor(*i);
} }
}
void ForEachFlag(std::function<void(CommandLineFlag&)> visitor) {
FlagRegistry& registry = FlagRegistry::GlobalRegistry();
FlagRegistryLock frl(registry); FlagRegistryLock frl(registry);
ForEachFlagUnlocked(visitor); for (const auto& i : registry.flags_) visitor(*i.second);
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
...@@ -173,6 +180,21 @@ bool RegisterCommandLineFlag(CommandLineFlag& flag) { ...@@ -173,6 +180,21 @@ bool RegisterCommandLineFlag(CommandLineFlag& flag) {
return true; return true;
} }
void FinalizeRegistry() {
auto& registry = FlagRegistry::GlobalRegistry();
FlagRegistryLock frl(registry);
if (registry.finalized_flags_.load(std::memory_order_relaxed)) {
// Was already finalized. Ignore the second time.
return;
}
registry.flat_flags_.reserve(registry.flags_.size());
for (const auto& f : registry.flags_) {
registry.flat_flags_.push_back(f.second);
}
registry.flags_.clear();
registry.finalized_flags_.store(true, std::memory_order_release);
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
namespace { namespace {
...@@ -298,9 +320,7 @@ CommandLineFlag* FindCommandLineFlag(absl::string_view name) { ...@@ -298,9 +320,7 @@ CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
if (name.empty()) return nullptr; if (name.empty()) return nullptr;
flags_internal::FlagRegistry& registry = flags_internal::FlagRegistry& registry =
flags_internal::FlagRegistry::GlobalRegistry(); flags_internal::FlagRegistry::GlobalRegistry();
flags_internal::FlagRegistryLock frl(registry); return registry.FindFlag(name);
return registry.FindFlagLocked(name);
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
......
...@@ -82,8 +82,8 @@ TYPED_TEST_P(HashValueIntTest, FastPath) { ...@@ -82,8 +82,8 @@ TYPED_TEST_P(HashValueIntTest, FastPath) {
} }
REGISTER_TYPED_TEST_CASE_P(HashValueIntTest, BasicUsage, FastPath); REGISTER_TYPED_TEST_CASE_P(HashValueIntTest, BasicUsage, FastPath);
using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t, using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
uint64_t, size_t>; uint32_t, uint64_t, size_t>;
INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes); INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes);
enum LegacyEnum { kValue1, kValue2, kValue3 }; enum LegacyEnum { kValue1, kValue2, kValue3 };
...@@ -819,8 +819,8 @@ TYPED_TEST_P(HashIntTest, BasicUsage) { ...@@ -819,8 +819,8 @@ TYPED_TEST_P(HashIntTest, BasicUsage) {
} }
REGISTER_TYPED_TEST_CASE_P(HashIntTest, BasicUsage); REGISTER_TYPED_TEST_CASE_P(HashIntTest, BasicUsage);
using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t, using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
uint64_t, size_t>; uint32_t, uint64_t, size_t>;
INSTANTIATE_TYPED_TEST_CASE_P(My, HashIntTest, IntTypes); INSTANTIATE_TYPED_TEST_CASE_P(My, HashIntTest, IntTypes);
struct StructWithPadding { struct StructWithPadding {
......
...@@ -253,9 +253,8 @@ static uint64_t HashLen17to32(const char *s, size_t len) { ...@@ -253,9 +253,8 @@ static uint64_t HashLen17to32(const char *s, size_t len) {
// Return a 16-byte hash for 48 bytes. Quick and dirty. // Return a 16-byte hash for 48 bytes. Quick and dirty.
// Callers do best to use "random-looking" values for a and b. // Callers do best to use "random-looking" values for a and b.
static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(uint64_t w, uint64_t x, static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
uint64_t y, uint64_t z, uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) {
uint64_t a, uint64_t b) {
a += w; a += w;
b = Rotate(b + a + z, 21); b = Rotate(b + a + z, 21);
uint64_t c = a; uint64_t c = a;
...@@ -266,7 +265,8 @@ static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(uint64_t w, uint64_t ...@@ -266,7 +265,8 @@ static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(uint64_t w, uint64_t
} }
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s, uint64_t a, static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s,
uint64_t a,
uint64_t b) { uint64_t b) {
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16),
Fetch64(s + 24), a, b); Fetch64(s + 24), a, b);
...@@ -310,8 +310,10 @@ uint64_t CityHash64(const char *s, size_t len) { ...@@ -310,8 +310,10 @@ uint64_t CityHash64(const char *s, size_t len) {
uint64_t x = Fetch64(s + len - 40); uint64_t x = Fetch64(s + len - 40);
uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56); uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24)); uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
std::pair<uint64_t, uint64_t> v = WeakHashLen32WithSeeds(s + len - 64, len, z); std::pair<uint64_t, uint64_t> v =
std::pair<uint64_t, uint64_t> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x); WeakHashLen32WithSeeds(s + len - 64, len, z);
std::pair<uint64_t, uint64_t> w =
WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
x = x * k1 + Fetch64(s); x = x * k1 + Fetch64(s);
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
......
...@@ -419,8 +419,8 @@ TEST(GenerateRealTest, ExhaustiveFloat) { ...@@ -419,8 +419,8 @@ TEST(GenerateRealTest, ExhaustiveFloat) {
}; };
// Rely on RandU64ToFloat generating values from greatest to least when // Rely on RandU64ToFloat generating values from greatest to least when
// supplied with uint64_t values from greatest (0xfff...) to least (0x0). Thus, // supplied with uint64_t values from greatest (0xfff...) to least (0x0).
// this algorithm stores the previous value, and if the new value is at // Thus, this algorithm stores the previous value, and if the new value is at
// greater than or equal to the previous value, then there is a collision in // greater than or equal to the previous value, then there is a collision in
// the generation algorithm. // the generation algorithm.
// //
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/strings/cord.h" #include "absl/strings/cord.h"
#include <algorithm> #include <algorithm>
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// //
// POSIX spec: // POSIX spec:
// http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html // http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/strings/internal/str_format/bind.h" #include "absl/strings/internal/str_format/bind.h"
#include <cerrno> #include <cerrno>
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/strings/internal/str_format/bind.h" #include "absl/strings/internal/str_format/bind.h"
#include <string.h> #include <string.h>
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string> #include <string>
#include "gmock/gmock.h" #include "gmock/gmock.h"
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/strings/internal/str_format/float_conversion.h" #include "absl/strings/internal/str_format/float_conversion.h"
#include <string.h> #include <string.h>
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/strings/internal/str_format/parser.h" #include "absl/strings/internal/str_format/parser.h"
#include <assert.h> #include <assert.h>
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/strings/internal/str_format/parser.h" #include "absl/strings/internal/str_format/parser.h"
#include <string.h> #include <string.h>
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
......
...@@ -80,6 +80,7 @@ cc_library( ...@@ -80,6 +80,7 @@ cc_library(
"barrier.h", "barrier.h",
"blocking_counter.h", "blocking_counter.h",
"internal/create_thread_identity.h", "internal/create_thread_identity.h",
"internal/futex.h",
"internal/per_thread_sem.h", "internal/per_thread_sem.h",
"internal/waiter.h", "internal/waiter.h",
"mutex.h", "mutex.h",
......
...@@ -52,6 +52,7 @@ absl_cc_library( ...@@ -52,6 +52,7 @@ absl_cc_library(
"barrier.h" "barrier.h"
"blocking_counter.h" "blocking_counter.h"
"internal/create_thread_identity.h" "internal/create_thread_identity.h"
"internal/futex.h"
"internal/per_thread_sem.h" "internal/per_thread_sem.h"
"internal/waiter.h" "internal/waiter.h"
"mutex.h" "mutex.h"
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
#define ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
#include "absl/base/config.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#include <unistd.h>
#endif
#ifdef __linux__
#include <linux/futex.h>
#include <sys/syscall.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <atomic>
#include <cstdint>
#include "absl/base/optimization.h"
#include "absl/synchronization/internal/kernel_timeout.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
// Some Android headers are missing these definitions even though they
// support these futex operations.
#ifdef __BIONIC__
#ifndef SYS_futex
#define SYS_futex __NR_futex
#endif
#ifndef FUTEX_WAIT_BITSET
#define FUTEX_WAIT_BITSET 9
#endif
#ifndef FUTEX_PRIVATE_FLAG
#define FUTEX_PRIVATE_FLAG 128
#endif
#ifndef FUTEX_CLOCK_REALTIME
#define FUTEX_CLOCK_REALTIME 256
#endif
#ifndef FUTEX_BITSET_MATCH_ANY
#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
#endif
#endif
#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
#define SYS_futex_time64 __NR_futex_time64
#endif
#if defined(SYS_futex_time64) && !defined(SYS_futex)
#define SYS_futex SYS_futex_time64
#endif
class FutexImpl {
public:
static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
KernelTimeout t) {
int err = 0;
if (t.has_timeout()) {
// https://locklessinc.com/articles/futex_cheat_sheet/
// Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
struct timespec abs_timeout = t.MakeAbsTimespec();
// Atomically check that the futex value is still 0, and if it
// is, sleep until abs_timeout or until woken by FUTEX_WAKE.
err = syscall(
SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
&abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
} else {
// Atomically check that the futex value is still 0, and if it
// is, sleep until woken by FUTEX_WAKE.
err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
}
if (ABSL_PREDICT_FALSE(err != 0)) {
err = -errno;
}
return err;
}
static int WaitBitsetAbsoluteTimeout(std::atomic<int32_t> *v, int32_t val,
int32_t bits,
const struct timespec *abstime) {
int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, val, abstime,
nullptr, bits);
if (ABSL_PREDICT_FALSE(err != 0)) {
err = -errno;
}
return err;
}
static int Wake(std::atomic<int32_t> *v, int32_t count) {
int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
if (ABSL_PREDICT_FALSE(err < 0)) {
err = -errno;
}
return err;
}
// FUTEX_WAKE_BITSET
static int WakeBitset(std::atomic<int32_t> *v, int32_t count, int32_t bits) {
int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG, count, nullptr,
nullptr, bits);
if (ABSL_PREDICT_FALSE(err < 0)) {
err = -errno;
}
return err;
}
};
class Futex : public FutexImpl {};
} // namespace synchronization_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ #define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
#include <time.h> #include <time.h>
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
......
...@@ -48,6 +48,11 @@ ...@@ -48,6 +48,11 @@
#include "absl/base/optimization.h" #include "absl/base/optimization.h"
#include "absl/synchronization/internal/kernel_timeout.h" #include "absl/synchronization/internal/kernel_timeout.h"
#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
#include "absl/synchronization/internal/futex.h"
#endif
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace synchronization_internal { namespace synchronization_internal {
...@@ -66,71 +71,6 @@ static void MaybeBecomeIdle() { ...@@ -66,71 +71,6 @@ static void MaybeBecomeIdle() {
#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
// Some Android headers are missing these definitions even though they
// support these futex operations.
#ifdef __BIONIC__
#ifndef SYS_futex
#define SYS_futex __NR_futex
#endif
#ifndef FUTEX_WAIT_BITSET
#define FUTEX_WAIT_BITSET 9
#endif
#ifndef FUTEX_PRIVATE_FLAG
#define FUTEX_PRIVATE_FLAG 128
#endif
#ifndef FUTEX_CLOCK_REALTIME
#define FUTEX_CLOCK_REALTIME 256
#endif
#ifndef FUTEX_BITSET_MATCH_ANY
#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
#endif
#endif
#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
#define SYS_futex_time64 __NR_futex_time64
#endif
#if defined(SYS_futex_time64) && !defined(SYS_futex)
#define SYS_futex SYS_futex_time64
#endif
class Futex {
public:
static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
KernelTimeout t) {
int err = 0;
if (t.has_timeout()) {
// https://locklessinc.com/articles/futex_cheat_sheet/
// Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
struct timespec abs_timeout = t.MakeAbsTimespec();
// Atomically check that the futex value is still 0, and if it
// is, sleep until abs_timeout or until woken by FUTEX_WAKE.
err = syscall(
SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
&abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
} else {
// Atomically check that the futex value is still 0, and if it
// is, sleep until woken by FUTEX_WAKE.
err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
}
if (err != 0) {
err = -errno;
}
return err;
}
static int Wake(std::atomic<int32_t> *v, int32_t count) {
int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
if (ABSL_PREDICT_FALSE(err < 0)) {
err = -errno;
}
return err;
}
};
Waiter::Waiter() { Waiter::Waiter() {
futex_.store(0, std::memory_order_relaxed); futex_.store(0, std::memory_order_relaxed);
} }
......
...@@ -88,7 +88,7 @@ ABSL_CONST_INIT std::atomic<OnDeadlockCycle> synch_deadlock_detection( ...@@ -88,7 +88,7 @@ ABSL_CONST_INIT std::atomic<OnDeadlockCycle> synch_deadlock_detection(
ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false); ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false);
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)> absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)>
submit_profile_data; submit_profile_data;
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<void (*)( ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<void (*)(
const char *msg, const void *obj, int64_t wait_cycles)> const char *msg, const void *obj, int64_t wait_cycles)>
...@@ -2311,7 +2311,8 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { ...@@ -2311,7 +2311,8 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) {
if (!cond_waiter) { if (!cond_waiter) {
// Sample lock contention events only if the (first) waiter was trying to // Sample lock contention events only if the (first) waiter was trying to
// acquire the lock, not waiting on a condition variable or Condition. // acquire the lock, not waiting on a condition variable or Condition.
int64_t wait_cycles = base_internal::CycleClock::Now() - enqueue_timestamp; int64_t wait_cycles =
base_internal::CycleClock::Now() - enqueue_timestamp;
mutex_tracer("slow release", this, wait_cycles); mutex_tracer("slow release", this, wait_cycles);
ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0); ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
submit_profile_data(enqueue_timestamp); submit_profile_data(enqueue_timestamp);
......
...@@ -667,10 +667,10 @@ class Condition { ...@@ -667,10 +667,10 @@ class Condition {
// }; // };
// mu_.Await(Condition(&reached)); // mu_.Await(Condition(&reached));
// //
// NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReadHeld()" in the // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReaderHeld()" in
// lambda as it may be called when the mutex is being unlocked from a scope // the lambda as it may be called when the mutex is being unlocked from a
// holding only a reader lock, which will make the assertion not fulfilled and // scope holding only a reader lock, which will make the assertion not
// crash the binary. // fulfilled and crash the binary.
// See class comment for performance advice. In particular, if there // See class comment for performance advice. In particular, if there
// might be more than one waiter for the same condition, make sure // might be more than one waiter for the same condition, make sure
......
...@@ -74,9 +74,7 @@ ABSL_NAMESPACE_END ...@@ -74,9 +74,7 @@ ABSL_NAMESPACE_END
#if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS #if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
int64_t GetCurrentTimeNanos() { int64_t GetCurrentTimeNanos() { return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); }
return GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
}
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
#else // Use the cyclecounter-based implementation below. #else // Use the cyclecounter-based implementation below.
......
...@@ -60,9 +60,10 @@ inline cctz::time_point<cctz::seconds> unix_epoch() { ...@@ -60,9 +60,10 @@ inline cctz::time_point<cctz::seconds> unix_epoch() {
inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) { inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
absl::Duration rem; absl::Duration rem;
int64_t q = absl::IDivDuration(d, unit, &rem); int64_t q = absl::IDivDuration(d, unit, &rem);
return (q > 0 || return (q > 0 || rem >= ZeroDuration() ||
rem >= ZeroDuration() || q == std::numeric_limits<int64_t>::min())
q == std::numeric_limits<int64_t>::min()) ? q : q - 1; ? q
: q - 1;
} }
inline absl::Time::Breakdown InfiniteFutureBreakdown() { inline absl::Time::Breakdown InfiniteFutureBreakdown() {
......
...@@ -1494,12 +1494,10 @@ constexpr Duration Hours(int64_t n) { ...@@ -1494,12 +1494,10 @@ constexpr Duration Hours(int64_t n) {
constexpr bool operator<(Duration lhs, Duration rhs) { constexpr bool operator<(Duration lhs, Duration rhs) {
return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs) return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs) ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs)
: time_internal::GetRepHi(lhs) == : time_internal::GetRepHi(lhs) == (std::numeric_limits<int64_t>::min)()
(std::numeric_limits<int64_t>::min)()
? time_internal::GetRepLo(lhs) + 1 < ? time_internal::GetRepLo(lhs) + 1 <
time_internal::GetRepLo(rhs) + 1 time_internal::GetRepLo(rhs) + 1
: time_internal::GetRepLo(lhs) < : time_internal::GetRepLo(lhs) < time_internal::GetRepLo(rhs);
time_internal::GetRepLo(rhs);
} }
constexpr bool operator==(Duration lhs, Duration rhs) { constexpr bool operator==(Duration lhs, Duration rhs) {
......
...@@ -1070,7 +1070,8 @@ TEST(Time, ConversionSaturation) { ...@@ -1070,7 +1070,8 @@ TEST(Time, ConversionSaturation) {
EXPECT_EQ("292277026596-12-04T15:30:07+00:00", EXPECT_EQ("292277026596-12-04T15:30:07+00:00",
absl::FormatTime(absl::RFC3339_full, t, utc)); absl::FormatTime(absl::RFC3339_full, t, utc));
EXPECT_EQ( EXPECT_EQ(
absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t); absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()),
t);
// Checks that we can also get the maximal Time value for a far-east zone. // Checks that we can also get the maximal Time value for a far-east zone.
const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60); const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60);
...@@ -1078,7 +1079,8 @@ TEST(Time, ConversionSaturation) { ...@@ -1078,7 +1079,8 @@ TEST(Time, ConversionSaturation) {
EXPECT_EQ("292277026596-12-05T05:30:07+14:00", EXPECT_EQ("292277026596-12-05T05:30:07+14:00",
absl::FormatTime(absl::RFC3339_full, t, plus14)); absl::FormatTime(absl::RFC3339_full, t, plus14));
EXPECT_EQ( EXPECT_EQ(
absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t); absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()),
t);
// One second later should push us to infinity. // One second later should push us to infinity.
t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc); t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc);
...@@ -1092,7 +1094,8 @@ TEST(Time, ConversionSaturation) { ...@@ -1092,7 +1094,8 @@ TEST(Time, ConversionSaturation) {
EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", EXPECT_EQ("-292277022657-01-27T08:29:52+00:00",
absl::FormatTime(absl::RFC3339_full, t, utc)); absl::FormatTime(absl::RFC3339_full, t, utc));
EXPECT_EQ( EXPECT_EQ(
absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t); absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()),
t);
// Checks that we can also get the minimal Time value for a far-west zone. // Checks that we can also get the minimal Time value for a far-west zone.
const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60); const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60);
...@@ -1101,7 +1104,8 @@ TEST(Time, ConversionSaturation) { ...@@ -1101,7 +1104,8 @@ TEST(Time, ConversionSaturation) {
EXPECT_EQ("-292277022657-01-26T20:29:52-12:00", EXPECT_EQ("-292277022657-01-26T20:29:52-12:00",
absl::FormatTime(absl::RFC3339_full, t, minus12)); absl::FormatTime(absl::RFC3339_full, t, minus12));
EXPECT_EQ( EXPECT_EQ(
absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t); absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()),
t);
// One second before should push us to -infinity. // One second before should push us to -infinity.
t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc); t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc);
......
...@@ -45,7 +45,7 @@ ABSL_NAMESPACE_BEGIN ...@@ -45,7 +45,7 @@ ABSL_NAMESPACE_BEGIN
template <class... Types> template <class... Types>
class variant; class variant;
ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1); ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, static_cast<size_t>(-1));
template <class T> template <class T>
struct variant_size; struct variant_size;
......
...@@ -2311,7 +2311,8 @@ TEST(VariantTest, TestRvalueConversion) { ...@@ -2311,7 +2311,8 @@ TEST(VariantTest, TestRvalueConversion) {
ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2)); ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
EXPECT_EQ(42, absl::get<int32_t>(variant2)); EXPECT_EQ(42, absl::get<int32_t>(variant2));
variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42)); variant2 =
ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2)); ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
EXPECT_EQ(42, absl::get<uint32_t>(variant2)); EXPECT_EQ(42, absl::get<uint32_t>(variant2));
#endif // !ABSL_USES_STD_VARIANT #endif // !ABSL_USES_STD_VARIANT
...@@ -2453,7 +2454,8 @@ TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) { ...@@ -2453,7 +2454,8 @@ TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) {
ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42))); ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42)); EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42)); variant2 =
ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42)); EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
#endif #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment