wuxing0105 commited on
Commit
00e39c3
·
verified ·
1 Parent(s): 9a0ccd9

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. weight/_dep/abseil-cpp/absl/container/internal/common_policy_traits_test.cc +134 -0
  2. weight/_dep/abseil-cpp/absl/container/internal/compressed_tuple_test.cc +419 -0
  3. weight/_dep/abseil-cpp/absl/container/internal/hash_function_defaults.h +209 -0
  4. weight/_dep/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc +549 -0
  5. weight/_dep/abseil-cpp/absl/container/internal/hash_generator_testing.cc +78 -0
  6. weight/_dep/abseil-cpp/absl/container/internal/hash_generator_testing.h +182 -0
  7. weight/_dep/abseil-cpp/absl/container/internal/hash_policy_testing.h +184 -0
  8. weight/_dep/abseil-cpp/absl/container/internal/hash_policy_traits_test.cc +80 -0
  9. weight/_dep/abseil-cpp/absl/container/internal/hashtablez_sampler.cc +285 -0
  10. weight/_dep/abseil-cpp/absl/container/internal/hashtablez_sampler.h +257 -0
  11. weight/_dep/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc +424 -0
  12. weight/_dep/abseil-cpp/absl/container/internal/layout_benchmark.cc +122 -0
  13. weight/_dep/abseil-cpp/absl/container/internal/layout_test.cc +1646 -0
  14. weight/_dep/abseil-cpp/absl/container/internal/raw_hash_map.h +224 -0
  15. weight/_dep/abseil-cpp/absl/container/internal/raw_hash_set.cc +380 -0
  16. weight/_dep/abseil-cpp/absl/container/internal/raw_hash_set.h +0 -0
  17. weight/_dep/abseil-cpp/absl/container/internal/raw_hash_set_test.cc +2684 -0
  18. weight/_dep/abseil-cpp/absl/container/internal/unordered_map_constructor_test.h +494 -0
  19. weight/_dep/abseil-cpp/absl/container/internal/unordered_map_members_test.h +87 -0
  20. weight/_dep/abseil-cpp/absl/container/internal/unordered_map_test.cc +50 -0
  21. weight/_dep/abseil-cpp/absl/container/internal/unordered_set_constructor_test.h +496 -0
  22. weight/_dep/abseil-cpp/absl/container/internal/unordered_set_lookup_test.h +91 -0
  23. weight/_dep/abseil-cpp/absl/container/internal/unordered_set_modifiers_test.h +221 -0
  24. weight/_dep/abseil-cpp/absl/container/internal/unordered_set_test.cc +41 -0
  25. weight/_dep/abseil-cpp/absl/crc/crc32c.h +190 -0
  26. weight/_dep/abseil-cpp/absl/crc/internal/crc32c.h +39 -0
  27. weight/_dep/abseil-cpp/absl/crc/internal/crc_cord_state.h +159 -0
  28. weight/_dep/abseil-cpp/absl/crc/internal/crc_cord_state_test.cc +124 -0
  29. weight/_dep/abseil-cpp/absl/crc/internal/crc_memcpy.h +122 -0
  30. weight/_dep/abseil-cpp/absl/crc/internal/crc_memcpy_fallback.cc +77 -0
  31. weight/_dep/abseil-cpp/absl/crc/internal/crc_memcpy_test.cc +177 -0
  32. weight/_dep/abseil-cpp/absl/crc/internal/crc_memcpy_x86_arm_combined.cc +450 -0
  33. weight/_dep/abseil-cpp/absl/crc/internal/crc_non_temporal_memcpy.cc +93 -0
  34. weight/_dep/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc +733 -0
  35. weight/_dep/abseil-cpp/absl/crc/internal/non_temporal_arm_intrinsics.h +79 -0
  36. weight/_dep/abseil-cpp/absl/crc/internal/non_temporal_memcpy.h +180 -0
  37. weight/_dep/abseil-cpp/absl/crc/internal/non_temporal_memcpy_test.cc +88 -0
  38. weight/_dep/abseil-cpp/absl/debugging/BUILD.bazel +342 -0
  39. weight/_dep/abseil-cpp/absl/debugging/failure_signal_handler.cc +405 -0
  40. weight/_dep/abseil-cpp/absl/debugging/failure_signal_handler.h +121 -0
  41. weight/_dep/abseil-cpp/absl/debugging/failure_signal_handler_test.cc +166 -0
  42. weight/_dep/abseil-cpp/absl/debugging/internal/demangle.cc +2012 -0
  43. weight/_dep/abseil-cpp/absl/debugging/internal/demangle.h +73 -0
  44. weight/_dep/abseil-cpp/absl/debugging/internal/demangle_test.cc +255 -0
  45. weight/_dep/abseil-cpp/absl/debugging/internal/elf_mem_image.cc +386 -0
  46. weight/_dep/abseil-cpp/absl/debugging/internal/elf_mem_image.h +140 -0
  47. weight/_dep/abseil-cpp/absl/debugging/internal/examine_stack.cc +320 -0
  48. weight/_dep/abseil-cpp/absl/debugging/internal/examine_stack.h +64 -0
  49. weight/_dep/abseil-cpp/absl/debugging/internal/stack_consumption.cc +206 -0
  50. weight/_dep/abseil-cpp/absl/debugging/internal/stack_consumption.h +50 -0
weight/_dep/abseil-cpp/absl/container/internal/common_policy_traits_test.cc ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/container/internal/common_policy_traits.h"
16
+
17
+ #include <functional>
18
+ #include <memory>
19
+ #include <type_traits>
20
+ #include <utility>
21
+
22
+ #include "gmock/gmock.h"
23
+ #include "gtest/gtest.h"
24
+ #include "absl/base/config.h"
25
+
26
+ namespace absl {
27
+ ABSL_NAMESPACE_BEGIN
28
+ namespace container_internal {
29
+ namespace {
30
+
31
+ using ::testing::MockFunction;
32
+ using ::testing::AnyNumber;
33
+ using ::testing::ReturnRef;
34
+
35
+ using Slot = int;
36
+
37
+ struct PolicyWithoutOptionalOps {
38
+ using slot_type = Slot;
39
+ using key_type = Slot;
40
+ using init_type = Slot;
41
+
42
+ static std::function<void(void*, Slot*, Slot)> construct;
43
+ static std::function<void(void*, Slot*)> destroy;
44
+
45
+ static std::function<Slot&(Slot*)> element;
46
+ };
47
+
48
+ std::function<void(void*, Slot*, Slot)> PolicyWithoutOptionalOps::construct;
49
+ std::function<void(void*, Slot*)> PolicyWithoutOptionalOps::destroy;
50
+
51
+ std::function<Slot&(Slot*)> PolicyWithoutOptionalOps::element;
52
+
53
+ struct PolicyWithOptionalOps : PolicyWithoutOptionalOps {
54
+ static std::function<void(void*, Slot*, Slot*)> transfer;
55
+ };
56
+ std::function<void(void*, Slot*, Slot*)> PolicyWithOptionalOps::transfer;
57
+
58
+ struct PolicyWithMemcpyTransfer : PolicyWithoutOptionalOps {
59
+ static std::function<std::true_type(void*, Slot*, Slot*)> transfer;
60
+ };
61
+ std::function<std::true_type(void*, Slot*, Slot*)>
62
+ PolicyWithMemcpyTransfer::transfer;
63
+
64
+ struct Test : ::testing::Test {
65
+ Test() {
66
+ PolicyWithoutOptionalOps::construct = [&](void* a1, Slot* a2, Slot a3) {
67
+ construct.Call(a1, a2, std::move(a3));
68
+ };
69
+ PolicyWithoutOptionalOps::destroy = [&](void* a1, Slot* a2) {
70
+ destroy.Call(a1, a2);
71
+ };
72
+
73
+ PolicyWithoutOptionalOps::element = [&](Slot* a1) -> Slot& {
74
+ return element.Call(a1);
75
+ };
76
+
77
+ PolicyWithOptionalOps::transfer = [&](void* a1, Slot* a2, Slot* a3) {
78
+ return transfer.Call(a1, a2, a3);
79
+ };
80
+ }
81
+
82
+ std::allocator<Slot> alloc;
83
+ int a = 53;
84
+
85
+ MockFunction<void(void*, Slot*, Slot)> construct;
86
+ MockFunction<void(void*, Slot*)> destroy;
87
+
88
+ MockFunction<Slot&(Slot*)> element;
89
+
90
+ MockFunction<void(void*, Slot*, Slot*)> transfer;
91
+ };
92
+
93
+ TEST_F(Test, construct) {
94
+ EXPECT_CALL(construct, Call(&alloc, &a, 53));
95
+ common_policy_traits<PolicyWithoutOptionalOps>::construct(&alloc, &a, 53);
96
+ }
97
+
98
+ TEST_F(Test, destroy) {
99
+ EXPECT_CALL(destroy, Call(&alloc, &a));
100
+ common_policy_traits<PolicyWithoutOptionalOps>::destroy(&alloc, &a);
101
+ }
102
+
103
+ TEST_F(Test, element) {
104
+ int b = 0;
105
+ EXPECT_CALL(element, Call(&a)).WillOnce(ReturnRef(b));
106
+ EXPECT_EQ(&b, &common_policy_traits<PolicyWithoutOptionalOps>::element(&a));
107
+ }
108
+
109
+ TEST_F(Test, without_transfer) {
110
+ int b = 42;
111
+ EXPECT_CALL(element, Call(&a)).Times(AnyNumber()).WillOnce(ReturnRef(a));
112
+ EXPECT_CALL(element, Call(&b)).WillOnce(ReturnRef(b));
113
+ EXPECT_CALL(construct, Call(&alloc, &a, b)).Times(AnyNumber());
114
+ EXPECT_CALL(destroy, Call(&alloc, &b)).Times(AnyNumber());
115
+ common_policy_traits<PolicyWithoutOptionalOps>::transfer(&alloc, &a, &b);
116
+ }
117
+
118
+ TEST_F(Test, with_transfer) {
119
+ int b = 42;
120
+ EXPECT_CALL(transfer, Call(&alloc, &a, &b));
121
+ common_policy_traits<PolicyWithOptionalOps>::transfer(&alloc, &a, &b);
122
+ }
123
+
124
+ TEST(TransferUsesMemcpy, Basic) {
125
+ EXPECT_FALSE(
126
+ common_policy_traits<PolicyWithOptionalOps>::transfer_uses_memcpy());
127
+ EXPECT_TRUE(
128
+ common_policy_traits<PolicyWithMemcpyTransfer>::transfer_uses_memcpy());
129
+ }
130
+
131
+ } // namespace
132
+ } // namespace container_internal
133
+ ABSL_NAMESPACE_END
134
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/compressed_tuple_test.cc ADDED
@@ -0,0 +1,419 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/container/internal/compressed_tuple.h"
16
+
17
+ #include <memory>
18
+ #include <string>
19
+
20
+ #include "gmock/gmock.h"
21
+ #include "gtest/gtest.h"
22
+ #include "absl/container/internal/test_instance_tracker.h"
23
+ #include "absl/memory/memory.h"
24
+ #include "absl/types/any.h"
25
+ #include "absl/types/optional.h"
26
+ #include "absl/utility/utility.h"
27
+
28
+ // These are declared at global scope purely so that error messages
29
+ // are smaller and easier to understand.
30
+ enum class CallType { kConstRef, kConstMove };
31
+
32
+ template <int>
33
+ struct Empty {
34
+ constexpr CallType value() const& { return CallType::kConstRef; }
35
+ constexpr CallType value() const&& { return CallType::kConstMove; }
36
+ };
37
+
38
+ template <typename T>
39
+ struct NotEmpty {
40
+ T value;
41
+ };
42
+
43
+ template <typename T, typename U>
44
+ struct TwoValues {
45
+ T value1;
46
+ U value2;
47
+ };
48
+
49
+
50
+ namespace absl {
51
+ ABSL_NAMESPACE_BEGIN
52
+ namespace container_internal {
53
+ namespace {
54
+
55
+ using absl::test_internal::CopyableMovableInstance;
56
+ using absl::test_internal::InstanceTracker;
57
+
58
+ TEST(CompressedTupleTest, Sizeof) {
59
+ EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int>));
60
+ EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int, Empty<0>>));
61
+ EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int, Empty<0>, Empty<1>>));
62
+ EXPECT_EQ(sizeof(int),
63
+ sizeof(CompressedTuple<int, Empty<0>, Empty<1>, Empty<2>>));
64
+
65
+ EXPECT_EQ(sizeof(TwoValues<int, double>),
66
+ sizeof(CompressedTuple<int, NotEmpty<double>>));
67
+ EXPECT_EQ(sizeof(TwoValues<int, double>),
68
+ sizeof(CompressedTuple<int, Empty<0>, NotEmpty<double>>));
69
+ EXPECT_EQ(sizeof(TwoValues<int, double>),
70
+ sizeof(CompressedTuple<int, Empty<0>, NotEmpty<double>, Empty<1>>));
71
+ }
72
+
73
+ TEST(CompressedTupleTest, OneMoveOnRValueConstructionTemp) {
74
+ InstanceTracker tracker;
75
+ CompressedTuple<CopyableMovableInstance> x1(CopyableMovableInstance(1));
76
+ EXPECT_EQ(tracker.instances(), 1);
77
+ EXPECT_EQ(tracker.copies(), 0);
78
+ EXPECT_LE(tracker.moves(), 1);
79
+ EXPECT_EQ(x1.get<0>().value(), 1);
80
+ }
81
+
82
+ TEST(CompressedTupleTest, OneMoveOnRValueConstructionMove) {
83
+ InstanceTracker tracker;
84
+
85
+ CopyableMovableInstance i1(1);
86
+ CompressedTuple<CopyableMovableInstance> x1(std::move(i1));
87
+ EXPECT_EQ(tracker.instances(), 2);
88
+ EXPECT_EQ(tracker.copies(), 0);
89
+ EXPECT_LE(tracker.moves(), 1);
90
+ EXPECT_EQ(x1.get<0>().value(), 1);
91
+ }
92
+
93
+ TEST(CompressedTupleTest, OneMoveOnRValueConstructionMixedTypes) {
94
+ InstanceTracker tracker;
95
+ CopyableMovableInstance i1(1);
96
+ CopyableMovableInstance i2(2);
97
+ Empty<0> empty;
98
+ CompressedTuple<CopyableMovableInstance, CopyableMovableInstance&, Empty<0>>
99
+ x1(std::move(i1), i2, empty);
100
+ EXPECT_EQ(x1.get<0>().value(), 1);
101
+ EXPECT_EQ(x1.get<1>().value(), 2);
102
+ EXPECT_EQ(tracker.copies(), 0);
103
+ EXPECT_EQ(tracker.moves(), 1);
104
+ }
105
+
106
+ struct IncompleteType;
107
+ CompressedTuple<CopyableMovableInstance, IncompleteType&, Empty<0>>
108
+ MakeWithIncomplete(CopyableMovableInstance i1,
109
+ IncompleteType& t, // NOLINT
110
+ Empty<0> empty) {
111
+ return CompressedTuple<CopyableMovableInstance, IncompleteType&, Empty<0>>{
112
+ std::move(i1), t, empty};
113
+ }
114
+
115
+ struct IncompleteType {};
116
+ TEST(CompressedTupleTest, OneMoveOnRValueConstructionWithIncompleteType) {
117
+ InstanceTracker tracker;
118
+ CopyableMovableInstance i1(1);
119
+ Empty<0> empty;
120
+ struct DerivedType : IncompleteType {int value = 0;};
121
+ DerivedType fd;
122
+ fd.value = 7;
123
+
124
+ CompressedTuple<CopyableMovableInstance, IncompleteType&, Empty<0>> x1 =
125
+ MakeWithIncomplete(std::move(i1), fd, empty);
126
+
127
+ EXPECT_EQ(x1.get<0>().value(), 1);
128
+ EXPECT_EQ(static_cast<DerivedType&>(x1.get<1>()).value, 7);
129
+
130
+ EXPECT_EQ(tracker.copies(), 0);
131
+ EXPECT_EQ(tracker.moves(), 2);
132
+ }
133
+
134
+ TEST(CompressedTupleTest,
135
+ OneMoveOnRValueConstructionMixedTypes_BraceInitPoisonPillExpected) {
136
+ InstanceTracker tracker;
137
+ CopyableMovableInstance i1(1);
138
+ CopyableMovableInstance i2(2);
139
+ CompressedTuple<CopyableMovableInstance, CopyableMovableInstance&, Empty<0>>
140
+ x1(std::move(i1), i2, {}); // NOLINT
141
+ EXPECT_EQ(x1.get<0>().value(), 1);
142
+ EXPECT_EQ(x1.get<1>().value(), 2);
143
+ EXPECT_EQ(tracker.instances(), 3);
144
+ // We are forced into the `const Ts&...` constructor (invoking copies)
145
+ // because we need it to deduce the type of `{}`.
146
+ // std::tuple also has this behavior.
147
+ // Note, this test is proof that this is expected behavior, but it is not
148
+ // _desired_ behavior.
149
+ EXPECT_EQ(tracker.copies(), 1);
150
+ EXPECT_EQ(tracker.moves(), 0);
151
+ }
152
+
153
+ TEST(CompressedTupleTest, OneCopyOnLValueConstruction) {
154
+ InstanceTracker tracker;
155
+ CopyableMovableInstance i1(1);
156
+
157
+ CompressedTuple<CopyableMovableInstance> x1(i1);
158
+ EXPECT_EQ(tracker.copies(), 1);
159
+ EXPECT_EQ(tracker.moves(), 0);
160
+
161
+ tracker.ResetCopiesMovesSwaps();
162
+
163
+ CopyableMovableInstance i2(2);
164
+ const CopyableMovableInstance& i2_ref = i2;
165
+ CompressedTuple<CopyableMovableInstance> x2(i2_ref);
166
+ EXPECT_EQ(tracker.copies(), 1);
167
+ EXPECT_EQ(tracker.moves(), 0);
168
+ }
169
+
170
+ TEST(CompressedTupleTest, OneMoveOnRValueAccess) {
171
+ InstanceTracker tracker;
172
+ CopyableMovableInstance i1(1);
173
+ CompressedTuple<CopyableMovableInstance> x(std::move(i1));
174
+ tracker.ResetCopiesMovesSwaps();
175
+
176
+ CopyableMovableInstance i2 = std::move(x).get<0>();
177
+ EXPECT_EQ(tracker.copies(), 0);
178
+ EXPECT_EQ(tracker.moves(), 1);
179
+ }
180
+
181
+ TEST(CompressedTupleTest, OneCopyOnLValueAccess) {
182
+ InstanceTracker tracker;
183
+
184
+ CompressedTuple<CopyableMovableInstance> x(CopyableMovableInstance(0));
185
+ EXPECT_EQ(tracker.copies(), 0);
186
+ EXPECT_EQ(tracker.moves(), 1);
187
+
188
+ CopyableMovableInstance t = x.get<0>();
189
+ EXPECT_EQ(tracker.copies(), 1);
190
+ EXPECT_EQ(tracker.moves(), 1);
191
+ }
192
+
193
+ TEST(CompressedTupleTest, ZeroCopyOnRefAccess) {
194
+ InstanceTracker tracker;
195
+
196
+ CompressedTuple<CopyableMovableInstance> x(CopyableMovableInstance(0));
197
+ EXPECT_EQ(tracker.copies(), 0);
198
+ EXPECT_EQ(tracker.moves(), 1);
199
+
200
+ CopyableMovableInstance& t1 = x.get<0>();
201
+ const CopyableMovableInstance& t2 = x.get<0>();
202
+ EXPECT_EQ(tracker.copies(), 0);
203
+ EXPECT_EQ(tracker.moves(), 1);
204
+ EXPECT_EQ(t1.value(), 0);
205
+ EXPECT_EQ(t2.value(), 0);
206
+ }
207
+
208
+ TEST(CompressedTupleTest, Access) {
209
+ struct S {
210
+ std::string x;
211
+ };
212
+ CompressedTuple<int, Empty<0>, S> x(7, {}, S{"ABC"});
213
+ EXPECT_EQ(sizeof(x), sizeof(TwoValues<int, S>));
214
+ EXPECT_EQ(7, x.get<0>());
215
+ EXPECT_EQ("ABC", x.get<2>().x);
216
+ }
217
+
218
+ TEST(CompressedTupleTest, NonClasses) {
219
+ CompressedTuple<int, const char*> x(7, "ABC");
220
+ EXPECT_EQ(7, x.get<0>());
221
+ EXPECT_STREQ("ABC", x.get<1>());
222
+ }
223
+
224
+ TEST(CompressedTupleTest, MixClassAndNonClass) {
225
+ CompressedTuple<int, const char*, Empty<0>, NotEmpty<double>> x(7, "ABC", {},
226
+ {1.25});
227
+ struct Mock {
228
+ int v;
229
+ const char* p;
230
+ double d;
231
+ };
232
+ EXPECT_EQ(sizeof(x), sizeof(Mock));
233
+ EXPECT_EQ(7, x.get<0>());
234
+ EXPECT_STREQ("ABC", x.get<1>());
235
+ EXPECT_EQ(1.25, x.get<3>().value);
236
+ }
237
+
238
+ TEST(CompressedTupleTest, Nested) {
239
+ CompressedTuple<int, CompressedTuple<int>,
240
+ CompressedTuple<int, CompressedTuple<int>>>
241
+ x(1, CompressedTuple<int>(2),
242
+ CompressedTuple<int, CompressedTuple<int>>(3, CompressedTuple<int>(4)));
243
+ EXPECT_EQ(1, x.get<0>());
244
+ EXPECT_EQ(2, x.get<1>().get<0>());
245
+ EXPECT_EQ(3, x.get<2>().get<0>());
246
+ EXPECT_EQ(4, x.get<2>().get<1>().get<0>());
247
+
248
+ CompressedTuple<Empty<0>, Empty<0>,
249
+ CompressedTuple<Empty<0>, CompressedTuple<Empty<0>>>>
250
+ y;
251
+ std::set<Empty<0>*> empties{&y.get<0>(), &y.get<1>(), &y.get<2>().get<0>(),
252
+ &y.get<2>().get<1>().get<0>()};
253
+ #ifdef _MSC_VER
254
+ // MSVC has a bug where many instances of the same base class are layed out in
255
+ // the same address when using __declspec(empty_bases).
256
+ // This will be fixed in a future version of MSVC.
257
+ int expected = 1;
258
+ #else
259
+ int expected = 4;
260
+ #endif
261
+ EXPECT_EQ(expected, sizeof(y));
262
+ EXPECT_EQ(expected, empties.size());
263
+ EXPECT_EQ(sizeof(y), sizeof(Empty<0>) * empties.size());
264
+
265
+ EXPECT_EQ(4 * sizeof(char),
266
+ sizeof(CompressedTuple<CompressedTuple<char, char>,
267
+ CompressedTuple<char, char>>));
268
+ EXPECT_TRUE((std::is_empty<CompressedTuple<Empty<0>, Empty<1>>>::value));
269
+
270
+ // Make sure everything still works when things are nested.
271
+ struct CT_Empty : CompressedTuple<Empty<0>> {};
272
+ CompressedTuple<Empty<0>, CT_Empty> nested_empty;
273
+ auto contained = nested_empty.get<0>();
274
+ auto nested = nested_empty.get<1>().get<0>();
275
+ EXPECT_TRUE((std::is_same<decltype(contained), decltype(nested)>::value));
276
+ }
277
+
278
+ TEST(CompressedTupleTest, Reference) {
279
+ int i = 7;
280
+ std::string s = "Very long string that goes in the heap";
281
+ CompressedTuple<int, int&, std::string, std::string&> x(i, i, s, s);
282
+
283
+ // Sanity check. We should have not moved from `s`
284
+ EXPECT_EQ(s, "Very long string that goes in the heap");
285
+
286
+ EXPECT_EQ(x.get<0>(), x.get<1>());
287
+ EXPECT_NE(&x.get<0>(), &x.get<1>());
288
+ EXPECT_EQ(&x.get<1>(), &i);
289
+
290
+ EXPECT_EQ(x.get<2>(), x.get<3>());
291
+ EXPECT_NE(&x.get<2>(), &x.get<3>());
292
+ EXPECT_EQ(&x.get<3>(), &s);
293
+ }
294
+
295
+ TEST(CompressedTupleTest, NoElements) {
296
+ CompressedTuple<> x;
297
+ static_cast<void>(x); // Silence -Wunused-variable.
298
+ EXPECT_TRUE(std::is_empty<CompressedTuple<>>::value);
299
+ }
300
+
301
+ TEST(CompressedTupleTest, MoveOnlyElements) {
302
+ CompressedTuple<std::unique_ptr<std::string>> str_tup(
303
+ absl::make_unique<std::string>("str"));
304
+
305
+ CompressedTuple<CompressedTuple<std::unique_ptr<std::string>>,
306
+ std::unique_ptr<int>>
307
+ x(std::move(str_tup), absl::make_unique<int>(5));
308
+
309
+ EXPECT_EQ(*x.get<0>().get<0>(), "str");
310
+ EXPECT_EQ(*x.get<1>(), 5);
311
+
312
+ std::unique_ptr<std::string> x0 = std::move(x.get<0>()).get<0>();
313
+ std::unique_ptr<int> x1 = std::move(x).get<1>();
314
+
315
+ EXPECT_EQ(*x0, "str");
316
+ EXPECT_EQ(*x1, 5);
317
+ }
318
+
319
+ TEST(CompressedTupleTest, MoveConstructionMoveOnlyElements) {
320
+ CompressedTuple<std::unique_ptr<std::string>> base(
321
+ absl::make_unique<std::string>("str"));
322
+ EXPECT_EQ(*base.get<0>(), "str");
323
+
324
+ CompressedTuple<std::unique_ptr<std::string>> copy(std::move(base));
325
+ EXPECT_EQ(*copy.get<0>(), "str");
326
+ }
327
+
328
+ TEST(CompressedTupleTest, AnyElements) {
329
+ any a(std::string("str"));
330
+ CompressedTuple<any, any&> x(any(5), a);
331
+ EXPECT_EQ(absl::any_cast<int>(x.get<0>()), 5);
332
+ EXPECT_EQ(absl::any_cast<std::string>(x.get<1>()), "str");
333
+
334
+ a = 0.5f;
335
+ EXPECT_EQ(absl::any_cast<float>(x.get<1>()), 0.5);
336
+ }
337
+
338
+ TEST(CompressedTupleTest, Constexpr) {
339
+ struct NonTrivialStruct {
340
+ constexpr NonTrivialStruct() = default;
341
+ constexpr int value() const { return v; }
342
+ int v = 5;
343
+ };
344
+ struct TrivialStruct {
345
+ TrivialStruct() = default;
346
+ constexpr int value() const { return v; }
347
+ int v;
348
+ };
349
+ constexpr CompressedTuple<int, double, CompressedTuple<int>, Empty<0>> x(
350
+ 7, 1.25, CompressedTuple<int>(5), {});
351
+ constexpr int x0 = x.get<0>();
352
+ constexpr double x1 = x.get<1>();
353
+ constexpr int x2 = x.get<2>().get<0>();
354
+ constexpr CallType x3 = x.get<3>().value();
355
+
356
+ EXPECT_EQ(x0, 7);
357
+ EXPECT_EQ(x1, 1.25);
358
+ EXPECT_EQ(x2, 5);
359
+ EXPECT_EQ(x3, CallType::kConstRef);
360
+
361
+ #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4
362
+ constexpr CompressedTuple<Empty<0>, TrivialStruct, int> trivial = {};
363
+ constexpr CallType trivial0 = trivial.get<0>().value();
364
+ constexpr int trivial1 = trivial.get<1>().value();
365
+ constexpr int trivial2 = trivial.get<2>();
366
+
367
+ EXPECT_EQ(trivial0, CallType::kConstRef);
368
+ EXPECT_EQ(trivial1, 0);
369
+ EXPECT_EQ(trivial2, 0);
370
+ #endif
371
+
372
+ constexpr CompressedTuple<Empty<0>, NonTrivialStruct, absl::optional<int>>
373
+ non_trivial = {};
374
+ constexpr CallType non_trivial0 = non_trivial.get<0>().value();
375
+ constexpr int non_trivial1 = non_trivial.get<1>().value();
376
+ constexpr absl::optional<int> non_trivial2 = non_trivial.get<2>();
377
+
378
+ EXPECT_EQ(non_trivial0, CallType::kConstRef);
379
+ EXPECT_EQ(non_trivial1, 5);
380
+ EXPECT_EQ(non_trivial2, absl::nullopt);
381
+
382
+ static constexpr char data[] = "DEF";
383
+ constexpr CompressedTuple<const char*> z(data);
384
+ constexpr const char* z1 = z.get<0>();
385
+ EXPECT_EQ(std::string(z1), std::string(data));
386
+
387
+ #if defined(__clang__)
388
+ // An apparent bug in earlier versions of gcc claims these are ambiguous.
389
+ constexpr int x2m = absl::move(x.get<2>()).get<0>();
390
+ constexpr CallType x3m = absl::move(x).get<3>().value();
391
+ EXPECT_EQ(x2m, 5);
392
+ EXPECT_EQ(x3m, CallType::kConstMove);
393
+ #endif
394
+ }
395
+
396
+ #if defined(__clang__) || defined(__GNUC__)
397
+ TEST(CompressedTupleTest, EmptyFinalClass) {
398
+ struct S final {
399
+ int f() const { return 5; }
400
+ };
401
+ CompressedTuple<S> x;
402
+ EXPECT_EQ(x.get<0>().f(), 5);
403
+ }
404
+ #endif
405
+
406
+ // TODO(b/214288561): enable this test.
407
+ TEST(CompressedTupleTest, DISABLED_NestedEbo) {
408
+ struct Empty1 {};
409
+ struct Empty2 {};
410
+ CompressedTuple<Empty1, CompressedTuple<Empty2>, int> x;
411
+ CompressedTuple<Empty1, Empty2, int> y;
412
+ // Currently fails with sizeof(x) == 8, sizeof(y) == 4.
413
+ EXPECT_EQ(sizeof(x), sizeof(y));
414
+ }
415
+
416
+ } // namespace
417
+ } // namespace container_internal
418
+ ABSL_NAMESPACE_END
419
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/hash_function_defaults.h ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // Define the default Hash and Eq functions for SwissTable containers.
16
+ //
17
+ // std::hash<T> and std::equal_to<T> are not appropriate hash and equal
18
+ // functions for SwissTable containers. There are two reasons for this.
19
+ //
20
+ // SwissTable containers are power of 2 sized containers:
21
+ //
22
+ // This means they use the lower bits of the hash value to find the slot for
23
+ // each entry. The typical hash function for integral types is the identity.
24
+ // This is a very weak hash function for SwissTable and any power of 2 sized
25
+ // hashtable implementation which will lead to excessive collisions. For
26
+ // SwissTable we use murmur3 style mixing to reduce collisions to a minimum.
27
+ //
28
+ // SwissTable containers support heterogeneous lookup:
29
+ //
30
+ // In order to make heterogeneous lookup work, hash and equal functions must be
31
+ // polymorphic. At the same time they have to satisfy the same requirements the
32
+ // C++ standard imposes on hash functions and equality operators. That is:
33
+ //
34
+ // if hash_default_eq<T>(a, b) returns true for any a and b of type T, then
35
+ // hash_default_hash<T>(a) must equal hash_default_hash<T>(b)
36
+ //
37
+ // For SwissTable containers this requirement is relaxed to allow a and b of
38
+ // any and possibly different types. Note that like the standard the hash and
39
+ // equal functions are still bound to T. This is important because some type U
40
+ // can be hashed by/tested for equality differently depending on T. A notable
41
+ // example is `const char*`. `const char*` is treated as a c-style string when
42
+ // the hash function is hash<std::string> but as a pointer when the hash
43
+ // function is hash<void*>.
44
+ //
45
+ #ifndef ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
46
+ #define ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
47
+
48
+ #include <stdint.h>
49
+ #include <cstddef>
50
+ #include <memory>
51
+ #include <string>
52
+ #include <type_traits>
53
+
54
+ #include "absl/base/config.h"
55
+ #include "absl/hash/hash.h"
56
+ #include "absl/strings/cord.h"
57
+ #include "absl/strings/string_view.h"
58
+
59
+ #ifdef ABSL_HAVE_STD_STRING_VIEW
60
+ #include <string_view>
61
+ #endif
62
+
63
+ namespace absl {
64
+ ABSL_NAMESPACE_BEGIN
65
+ namespace container_internal {
66
+
67
+ // The hash of an object of type T is computed by using absl::Hash.
68
+ template <class T, class E = void>
69
+ struct HashEq {
70
+ using Hash = absl::Hash<T>;
71
+ using Eq = std::equal_to<T>;
72
+ };
73
+
74
+ struct StringHash {
75
+ using is_transparent = void;
76
+
77
+ size_t operator()(absl::string_view v) const {
78
+ return absl::Hash<absl::string_view>{}(v);
79
+ }
80
+ size_t operator()(const absl::Cord& v) const {
81
+ return absl::Hash<absl::Cord>{}(v);
82
+ }
83
+ };
84
+
85
+ struct StringEq {
86
+ using is_transparent = void;
87
+ bool operator()(absl::string_view lhs, absl::string_view rhs) const {
88
+ return lhs == rhs;
89
+ }
90
+ bool operator()(const absl::Cord& lhs, const absl::Cord& rhs) const {
91
+ return lhs == rhs;
92
+ }
93
+ bool operator()(const absl::Cord& lhs, absl::string_view rhs) const {
94
+ return lhs == rhs;
95
+ }
96
+ bool operator()(absl::string_view lhs, const absl::Cord& rhs) const {
97
+ return lhs == rhs;
98
+ }
99
+ };
100
+
101
+ // Supports heterogeneous lookup for string-like elements.
102
+ struct StringHashEq {
103
+ using Hash = StringHash;
104
+ using Eq = StringEq;
105
+ };
106
+
107
+ template <>
108
+ struct HashEq<std::string> : StringHashEq {};
109
+ template <>
110
+ struct HashEq<absl::string_view> : StringHashEq {};
111
+ template <>
112
+ struct HashEq<absl::Cord> : StringHashEq {};
113
+
114
+ #ifdef ABSL_HAVE_STD_STRING_VIEW
115
+
116
+ template <typename TChar>
117
+ struct BasicStringHash {
118
+ using is_transparent = void;
119
+
120
+ size_t operator()(std::basic_string_view<TChar> v) const {
121
+ return absl::Hash<std::basic_string_view<TChar>>{}(v);
122
+ }
123
+ };
124
+
125
+ template <typename TChar>
126
+ struct BasicStringEq {
127
+ using is_transparent = void;
128
+ bool operator()(std::basic_string_view<TChar> lhs,
129
+ std::basic_string_view<TChar> rhs) const {
130
+ return lhs == rhs;
131
+ }
132
+ };
133
+
134
+ // Supports heterogeneous lookup for w/u16/u32 string + string_view + char*.
135
+ template <typename TChar>
136
+ struct BasicStringHashEq {
137
+ using Hash = BasicStringHash<TChar>;
138
+ using Eq = BasicStringEq<TChar>;
139
+ };
140
+
141
+ template <>
142
+ struct HashEq<std::wstring> : BasicStringHashEq<wchar_t> {};
143
+ template <>
144
+ struct HashEq<std::wstring_view> : BasicStringHashEq<wchar_t> {};
145
+ template <>
146
+ struct HashEq<std::u16string> : BasicStringHashEq<char16_t> {};
147
+ template <>
148
+ struct HashEq<std::u16string_view> : BasicStringHashEq<char16_t> {};
149
+ template <>
150
+ struct HashEq<std::u32string> : BasicStringHashEq<char32_t> {};
151
+ template <>
152
+ struct HashEq<std::u32string_view> : BasicStringHashEq<char32_t> {};
153
+
154
+ #endif // ABSL_HAVE_STD_STRING_VIEW
155
+
156
+ // Supports heterogeneous lookup for pointers and smart pointers.
157
+ template <class T>
158
+ struct HashEq<T*> {
159
+ struct Hash {
160
+ using is_transparent = void;
161
+ template <class U>
162
+ size_t operator()(const U& ptr) const {
163
+ return absl::Hash<const T*>{}(HashEq::ToPtr(ptr));
164
+ }
165
+ };
166
+ struct Eq {
167
+ using is_transparent = void;
168
+ template <class A, class B>
169
+ bool operator()(const A& a, const B& b) const {
170
+ return HashEq::ToPtr(a) == HashEq::ToPtr(b);
171
+ }
172
+ };
173
+
174
+ private:
175
+ static const T* ToPtr(const T* ptr) { return ptr; }
176
+ template <class U, class D>
177
+ static const T* ToPtr(const std::unique_ptr<U, D>& ptr) {
178
+ return ptr.get();
179
+ }
180
+ template <class U>
181
+ static const T* ToPtr(const std::shared_ptr<U>& ptr) {
182
+ return ptr.get();
183
+ }
184
+ };
185
+
186
+ template <class T, class D>
187
+ struct HashEq<std::unique_ptr<T, D>> : HashEq<T*> {};
188
+ template <class T>
189
+ struct HashEq<std::shared_ptr<T>> : HashEq<T*> {};
190
+
191
+ // This header's visibility is restricted. If you need to access the default
192
+ // hasher please use the container's ::hasher alias instead.
193
+ //
194
+ // Example: typename Hash = typename absl::flat_hash_map<K, V>::hasher
195
+ template <class T>
196
+ using hash_default_hash = typename container_internal::HashEq<T>::Hash;
197
+
198
+ // This header's visibility is restricted. If you need to access the default
199
+ // key equal please use the container's ::key_equal alias instead.
200
+ //
201
+ // Example: typename Eq = typename absl::flat_hash_map<K, V, Hash>::key_equal
202
+ template <class T>
203
+ using hash_default_eq = typename container_internal::HashEq<T>::Eq;
204
+
205
+ } // namespace container_internal
206
+ ABSL_NAMESPACE_END
207
+ } // namespace absl
208
+
209
+ #endif // ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
weight/_dep/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc ADDED
@@ -0,0 +1,549 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/container/internal/hash_function_defaults.h"
16
+
17
+ #include <functional>
18
+ #include <type_traits>
19
+ #include <utility>
20
+
21
+ #include "gtest/gtest.h"
22
+ #include "absl/random/random.h"
23
+ #include "absl/strings/cord.h"
24
+ #include "absl/strings/cord_test_helpers.h"
25
+ #include "absl/strings/string_view.h"
26
+
27
+ #ifdef ABSL_HAVE_STD_STRING_VIEW
28
+ #include <string_view>
29
+ #endif
30
+
31
+ namespace absl {
32
+ ABSL_NAMESPACE_BEGIN
33
+ namespace container_internal {
34
+ namespace {
35
+
36
+ using ::testing::Types;
37
+
38
+ TEST(Eq, Int32) {
39
+ hash_default_eq<int32_t> eq;
40
+ EXPECT_TRUE(eq(1, 1u));
41
+ EXPECT_TRUE(eq(1, char{1}));
42
+ EXPECT_TRUE(eq(1, true));
43
+ EXPECT_TRUE(eq(1, double{1.1}));
44
+ EXPECT_FALSE(eq(1, char{2}));
45
+ EXPECT_FALSE(eq(1, 2u));
46
+ EXPECT_FALSE(eq(1, false));
47
+ EXPECT_FALSE(eq(1, 2.));
48
+ }
49
+
50
+ TEST(Hash, Int32) {
51
+ hash_default_hash<int32_t> hash;
52
+ auto h = hash(1);
53
+ EXPECT_EQ(h, hash(1u));
54
+ EXPECT_EQ(h, hash(char{1}));
55
+ EXPECT_EQ(h, hash(true));
56
+ EXPECT_EQ(h, hash(double{1.1}));
57
+ EXPECT_NE(h, hash(2u));
58
+ EXPECT_NE(h, hash(char{2}));
59
+ EXPECT_NE(h, hash(false));
60
+ EXPECT_NE(h, hash(2.));
61
+ }
62
+
63
+ enum class MyEnum { A, B, C, D };
64
+
65
+ TEST(Eq, Enum) {
66
+ hash_default_eq<MyEnum> eq;
67
+ EXPECT_TRUE(eq(MyEnum::A, MyEnum::A));
68
+ EXPECT_FALSE(eq(MyEnum::A, MyEnum::B));
69
+ }
70
+
71
+ TEST(Hash, Enum) {
72
+ hash_default_hash<MyEnum> hash;
73
+
74
+ for (MyEnum e : {MyEnum::A, MyEnum::B, MyEnum::C}) {
75
+ auto h = hash(e);
76
+ EXPECT_EQ(h, hash_default_hash<int>{}(static_cast<int>(e)));
77
+ EXPECT_NE(h, hash(MyEnum::D));
78
+ }
79
+ }
80
+
81
+ using StringTypes = ::testing::Types<std::string, absl::string_view>;
82
+
83
+ template <class T>
84
+ struct EqString : ::testing::Test {
85
+ hash_default_eq<T> key_eq;
86
+ };
87
+
88
+ TYPED_TEST_SUITE(EqString, StringTypes);
89
+
90
+ template <class T>
91
+ struct HashString : ::testing::Test {
92
+ hash_default_hash<T> hasher;
93
+ };
94
+
95
+ TYPED_TEST_SUITE(HashString, StringTypes);
96
+
97
+ TYPED_TEST(EqString, Works) {
98
+ auto eq = this->key_eq;
99
+ EXPECT_TRUE(eq("a", "a"));
100
+ EXPECT_TRUE(eq("a", absl::string_view("a")));
101
+ EXPECT_TRUE(eq("a", std::string("a")));
102
+ EXPECT_FALSE(eq("a", "b"));
103
+ EXPECT_FALSE(eq("a", absl::string_view("b")));
104
+ EXPECT_FALSE(eq("a", std::string("b")));
105
+ }
106
+
107
+ TYPED_TEST(HashString, Works) {
108
+ auto hash = this->hasher;
109
+ auto h = hash("a");
110
+ EXPECT_EQ(h, hash(absl::string_view("a")));
111
+ EXPECT_EQ(h, hash(std::string("a")));
112
+ EXPECT_NE(h, hash(absl::string_view("b")));
113
+ EXPECT_NE(h, hash(std::string("b")));
114
+ }
115
+
116
+ TEST(BasicStringViewTest, WStringEqWorks) {
117
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
118
+ GTEST_SKIP();
119
+ #else
120
+ hash_default_eq<std::wstring> eq;
121
+ EXPECT_TRUE(eq(L"a", L"a"));
122
+ EXPECT_TRUE(eq(L"a", std::wstring_view(L"a")));
123
+ EXPECT_TRUE(eq(L"a", std::wstring(L"a")));
124
+ EXPECT_FALSE(eq(L"a", L"b"));
125
+ EXPECT_FALSE(eq(L"a", std::wstring_view(L"b")));
126
+ EXPECT_FALSE(eq(L"a", std::wstring(L"b")));
127
+ #endif
128
+ }
129
+
130
+ TEST(BasicStringViewTest, WStringViewEqWorks) {
131
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
132
+ GTEST_SKIP();
133
+ #else
134
+ hash_default_eq<std::wstring_view> eq;
135
+ EXPECT_TRUE(eq(L"a", L"a"));
136
+ EXPECT_TRUE(eq(L"a", std::wstring_view(L"a")));
137
+ EXPECT_TRUE(eq(L"a", std::wstring(L"a")));
138
+ EXPECT_FALSE(eq(L"a", L"b"));
139
+ EXPECT_FALSE(eq(L"a", std::wstring_view(L"b")));
140
+ EXPECT_FALSE(eq(L"a", std::wstring(L"b")));
141
+ #endif
142
+ }
143
+
144
+ TEST(BasicStringViewTest, U16StringEqWorks) {
145
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
146
+ GTEST_SKIP();
147
+ #else
148
+ hash_default_eq<std::u16string> eq;
149
+ EXPECT_TRUE(eq(u"a", u"a"));
150
+ EXPECT_TRUE(eq(u"a", std::u16string_view(u"a")));
151
+ EXPECT_TRUE(eq(u"a", std::u16string(u"a")));
152
+ EXPECT_FALSE(eq(u"a", u"b"));
153
+ EXPECT_FALSE(eq(u"a", std::u16string_view(u"b")));
154
+ EXPECT_FALSE(eq(u"a", std::u16string(u"b")));
155
+ #endif
156
+ }
157
+
158
+ TEST(BasicStringViewTest, U16StringViewEqWorks) {
159
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
160
+ GTEST_SKIP();
161
+ #else
162
+ hash_default_eq<std::u16string_view> eq;
163
+ EXPECT_TRUE(eq(u"a", u"a"));
164
+ EXPECT_TRUE(eq(u"a", std::u16string_view(u"a")));
165
+ EXPECT_TRUE(eq(u"a", std::u16string(u"a")));
166
+ EXPECT_FALSE(eq(u"a", u"b"));
167
+ EXPECT_FALSE(eq(u"a", std::u16string_view(u"b")));
168
+ EXPECT_FALSE(eq(u"a", std::u16string(u"b")));
169
+ #endif
170
+ }
171
+
172
+ TEST(BasicStringViewTest, U32StringEqWorks) {
173
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
174
+ GTEST_SKIP();
175
+ #else
176
+ hash_default_eq<std::u32string> eq;
177
+ EXPECT_TRUE(eq(U"a", U"a"));
178
+ EXPECT_TRUE(eq(U"a", std::u32string_view(U"a")));
179
+ EXPECT_TRUE(eq(U"a", std::u32string(U"a")));
180
+ EXPECT_FALSE(eq(U"a", U"b"));
181
+ EXPECT_FALSE(eq(U"a", std::u32string_view(U"b")));
182
+ EXPECT_FALSE(eq(U"a", std::u32string(U"b")));
183
+ #endif
184
+ }
185
+
186
+ TEST(BasicStringViewTest, U32StringViewEqWorks) {
187
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
188
+ GTEST_SKIP();
189
+ #else
190
+ hash_default_eq<std::u32string_view> eq;
191
+ EXPECT_TRUE(eq(U"a", U"a"));
192
+ EXPECT_TRUE(eq(U"a", std::u32string_view(U"a")));
193
+ EXPECT_TRUE(eq(U"a", std::u32string(U"a")));
194
+ EXPECT_FALSE(eq(U"a", U"b"));
195
+ EXPECT_FALSE(eq(U"a", std::u32string_view(U"b")));
196
+ EXPECT_FALSE(eq(U"a", std::u32string(U"b")));
197
+ #endif
198
+ }
199
+
200
+ TEST(BasicStringViewTest, WStringHashWorks) {
201
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
202
+ GTEST_SKIP();
203
+ #else
204
+ hash_default_hash<std::wstring> hash;
205
+ auto h = hash(L"a");
206
+ EXPECT_EQ(h, hash(std::wstring_view(L"a")));
207
+ EXPECT_EQ(h, hash(std::wstring(L"a")));
208
+ EXPECT_NE(h, hash(std::wstring_view(L"b")));
209
+ EXPECT_NE(h, hash(std::wstring(L"b")));
210
+ #endif
211
+ }
212
+
213
+ TEST(BasicStringViewTest, WStringViewHashWorks) {
214
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
215
+ GTEST_SKIP();
216
+ #else
217
+ hash_default_hash<std::wstring_view> hash;
218
+ auto h = hash(L"a");
219
+ EXPECT_EQ(h, hash(std::wstring_view(L"a")));
220
+ EXPECT_EQ(h, hash(std::wstring(L"a")));
221
+ EXPECT_NE(h, hash(std::wstring_view(L"b")));
222
+ EXPECT_NE(h, hash(std::wstring(L"b")));
223
+ #endif
224
+ }
225
+
226
+ TEST(BasicStringViewTest, U16StringHashWorks) {
227
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
228
+ GTEST_SKIP();
229
+ #else
230
+ hash_default_hash<std::u16string> hash;
231
+ auto h = hash(u"a");
232
+ EXPECT_EQ(h, hash(std::u16string_view(u"a")));
233
+ EXPECT_EQ(h, hash(std::u16string(u"a")));
234
+ EXPECT_NE(h, hash(std::u16string_view(u"b")));
235
+ EXPECT_NE(h, hash(std::u16string(u"b")));
236
+ #endif
237
+ }
238
+
239
+ TEST(BasicStringViewTest, U16StringViewHashWorks) {
240
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
241
+ GTEST_SKIP();
242
+ #else
243
+ hash_default_hash<std::u16string_view> hash;
244
+ auto h = hash(u"a");
245
+ EXPECT_EQ(h, hash(std::u16string_view(u"a")));
246
+ EXPECT_EQ(h, hash(std::u16string(u"a")));
247
+ EXPECT_NE(h, hash(std::u16string_view(u"b")));
248
+ EXPECT_NE(h, hash(std::u16string(u"b")));
249
+ #endif
250
+ }
251
+
252
+ TEST(BasicStringViewTest, U32StringHashWorks) {
253
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
254
+ GTEST_SKIP();
255
+ #else
256
+ hash_default_hash<std::u32string> hash;
257
+ auto h = hash(U"a");
258
+ EXPECT_EQ(h, hash(std::u32string_view(U"a")));
259
+ EXPECT_EQ(h, hash(std::u32string(U"a")));
260
+ EXPECT_NE(h, hash(std::u32string_view(U"b")));
261
+ EXPECT_NE(h, hash(std::u32string(U"b")));
262
+ #endif
263
+ }
264
+
265
+ TEST(BasicStringViewTest, U32StringViewHashWorks) {
266
+ #ifndef ABSL_HAVE_STD_STRING_VIEW
267
+ GTEST_SKIP();
268
+ #else
269
+ hash_default_hash<std::u32string_view> hash;
270
+ auto h = hash(U"a");
271
+ EXPECT_EQ(h, hash(std::u32string_view(U"a")));
272
+ EXPECT_EQ(h, hash(std::u32string(U"a")));
273
+ EXPECT_NE(h, hash(std::u32string_view(U"b")));
274
+ EXPECT_NE(h, hash(std::u32string(U"b")));
275
+ #endif
276
+ }
277
+
278
+ struct NoDeleter {
279
+ template <class T>
280
+ void operator()(const T* ptr) const {}
281
+ };
282
+
283
+ using PointerTypes =
284
+ ::testing::Types<const int*, int*, std::unique_ptr<const int>,
285
+ std::unique_ptr<const int, NoDeleter>,
286
+ std::unique_ptr<int>, std::unique_ptr<int, NoDeleter>,
287
+ std::shared_ptr<const int>, std::shared_ptr<int>>;
288
+
289
+ template <class T>
290
+ struct EqPointer : ::testing::Test {
291
+ hash_default_eq<T> key_eq;
292
+ };
293
+
294
+ TYPED_TEST_SUITE(EqPointer, PointerTypes);
295
+
296
+ template <class T>
297
+ struct HashPointer : ::testing::Test {
298
+ hash_default_hash<T> hasher;
299
+ };
300
+
301
+ TYPED_TEST_SUITE(HashPointer, PointerTypes);
302
+
303
+ TYPED_TEST(EqPointer, Works) {
304
+ int dummy;
305
+ auto eq = this->key_eq;
306
+ auto sptr = std::make_shared<int>();
307
+ std::shared_ptr<const int> csptr = sptr;
308
+ int* ptr = sptr.get();
309
+ const int* cptr = ptr;
310
+ std::unique_ptr<int, NoDeleter> uptr(ptr);
311
+ std::unique_ptr<const int, NoDeleter> cuptr(ptr);
312
+
313
+ EXPECT_TRUE(eq(ptr, cptr));
314
+ EXPECT_TRUE(eq(ptr, sptr));
315
+ EXPECT_TRUE(eq(ptr, uptr));
316
+ EXPECT_TRUE(eq(ptr, csptr));
317
+ EXPECT_TRUE(eq(ptr, cuptr));
318
+ EXPECT_FALSE(eq(&dummy, cptr));
319
+ EXPECT_FALSE(eq(&dummy, sptr));
320
+ EXPECT_FALSE(eq(&dummy, uptr));
321
+ EXPECT_FALSE(eq(&dummy, csptr));
322
+ EXPECT_FALSE(eq(&dummy, cuptr));
323
+ }
324
+
325
+ TEST(Hash, DerivedAndBase) {
326
+ struct Base {};
327
+ struct Derived : Base {};
328
+
329
+ hash_default_hash<Base*> hasher;
330
+
331
+ Base base;
332
+ Derived derived;
333
+ EXPECT_NE(hasher(&base), hasher(&derived));
334
+ EXPECT_EQ(hasher(static_cast<Base*>(&derived)), hasher(&derived));
335
+
336
+ auto dp = std::make_shared<Derived>();
337
+ EXPECT_EQ(hasher(static_cast<Base*>(dp.get())), hasher(dp));
338
+ }
339
+
340
+ TEST(Hash, FunctionPointer) {
341
+ using Func = int (*)();
342
+ hash_default_hash<Func> hasher;
343
+ hash_default_eq<Func> eq;
344
+
345
+ Func p1 = [] { return 1; }, p2 = [] { return 2; };
346
+ EXPECT_EQ(hasher(p1), hasher(p1));
347
+ EXPECT_TRUE(eq(p1, p1));
348
+
349
+ EXPECT_NE(hasher(p1), hasher(p2));
350
+ EXPECT_FALSE(eq(p1, p2));
351
+ }
352
+
353
+ TYPED_TEST(HashPointer, Works) {
354
+ int dummy;
355
+ auto hash = this->hasher;
356
+ auto sptr = std::make_shared<int>();
357
+ std::shared_ptr<const int> csptr = sptr;
358
+ int* ptr = sptr.get();
359
+ const int* cptr = ptr;
360
+ std::unique_ptr<int, NoDeleter> uptr(ptr);
361
+ std::unique_ptr<const int, NoDeleter> cuptr(ptr);
362
+
363
+ EXPECT_EQ(hash(ptr), hash(cptr));
364
+ EXPECT_EQ(hash(ptr), hash(sptr));
365
+ EXPECT_EQ(hash(ptr), hash(uptr));
366
+ EXPECT_EQ(hash(ptr), hash(csptr));
367
+ EXPECT_EQ(hash(ptr), hash(cuptr));
368
+ EXPECT_NE(hash(&dummy), hash(cptr));
369
+ EXPECT_NE(hash(&dummy), hash(sptr));
370
+ EXPECT_NE(hash(&dummy), hash(uptr));
371
+ EXPECT_NE(hash(&dummy), hash(csptr));
372
+ EXPECT_NE(hash(&dummy), hash(cuptr));
373
+ }
374
+
375
+ TEST(EqCord, Works) {
376
+ hash_default_eq<absl::Cord> eq;
377
+ const absl::string_view a_string_view = "a";
378
+ const absl::Cord a_cord(a_string_view);
379
+ const absl::string_view b_string_view = "b";
380
+ const absl::Cord b_cord(b_string_view);
381
+
382
+ EXPECT_TRUE(eq(a_cord, a_cord));
383
+ EXPECT_TRUE(eq(a_cord, a_string_view));
384
+ EXPECT_TRUE(eq(a_string_view, a_cord));
385
+ EXPECT_FALSE(eq(a_cord, b_cord));
386
+ EXPECT_FALSE(eq(a_cord, b_string_view));
387
+ EXPECT_FALSE(eq(b_string_view, a_cord));
388
+ }
389
+
390
+ TEST(HashCord, Works) {
391
+ hash_default_hash<absl::Cord> hash;
392
+ const absl::string_view a_string_view = "a";
393
+ const absl::Cord a_cord(a_string_view);
394
+ const absl::string_view b_string_view = "b";
395
+ const absl::Cord b_cord(b_string_view);
396
+
397
+ EXPECT_EQ(hash(a_cord), hash(a_cord));
398
+ EXPECT_EQ(hash(b_cord), hash(b_cord));
399
+ EXPECT_EQ(hash(a_string_view), hash(a_cord));
400
+ EXPECT_EQ(hash(b_string_view), hash(b_cord));
401
+ EXPECT_EQ(hash(absl::Cord("")), hash(""));
402
+ EXPECT_EQ(hash(absl::Cord()), hash(absl::string_view()));
403
+
404
+ EXPECT_NE(hash(a_cord), hash(b_cord));
405
+ EXPECT_NE(hash(a_cord), hash(b_string_view));
406
+ EXPECT_NE(hash(a_string_view), hash(b_cord));
407
+ EXPECT_NE(hash(a_string_view), hash(b_string_view));
408
+ }
409
+
410
+ void NoOpReleaser(absl::string_view data, void* arg) {}
411
+
412
+ TEST(HashCord, FragmentedCordWorks) {
413
+ hash_default_hash<absl::Cord> hash;
414
+ absl::Cord c = absl::MakeFragmentedCord({"a", "b", "c"});
415
+ EXPECT_FALSE(c.TryFlat().has_value());
416
+ EXPECT_EQ(hash(c), hash("abc"));
417
+ }
418
+
419
+ TEST(HashCord, FragmentedLongCordWorks) {
420
+ hash_default_hash<absl::Cord> hash;
421
+ // Crete some large strings which do not fit on the stack.
422
+ std::string a(65536, 'a');
423
+ std::string b(65536, 'b');
424
+ absl::Cord c = absl::MakeFragmentedCord({a, b});
425
+ EXPECT_FALSE(c.TryFlat().has_value());
426
+ EXPECT_EQ(hash(c), hash(a + b));
427
+ }
428
+
429
+ TEST(HashCord, RandomCord) {
430
+ hash_default_hash<absl::Cord> hash;
431
+ auto bitgen = absl::BitGen();
432
+ for (int i = 0; i < 1000; ++i) {
433
+ const int number_of_segments = absl::Uniform(bitgen, 0, 10);
434
+ std::vector<std::string> pieces;
435
+ for (size_t s = 0; s < number_of_segments; ++s) {
436
+ std::string str;
437
+ str.resize(absl::Uniform(bitgen, 0, 4096));
438
+ // MSVC needed the explicit return type in the lambda.
439
+ std::generate(str.begin(), str.end(), [&]() -> char {
440
+ return static_cast<char>(absl::Uniform<unsigned char>(bitgen));
441
+ });
442
+ pieces.push_back(str);
443
+ }
444
+ absl::Cord c = absl::MakeFragmentedCord(pieces);
445
+ EXPECT_EQ(hash(c), hash(std::string(c)));
446
+ }
447
+ }
448
+
449
+ // Cartesian product of (std::string, absl::string_view)
450
+ // with (std::string, absl::string_view, const char*, absl::Cord).
451
+ using StringTypesCartesianProduct = Types<
452
+ // clang-format off
453
+ std::pair<absl::Cord, std::string>,
454
+ std::pair<absl::Cord, absl::string_view>,
455
+ std::pair<absl::Cord, absl::Cord>,
456
+ std::pair<absl::Cord, const char*>,
457
+
458
+ std::pair<std::string, absl::Cord>,
459
+ std::pair<absl::string_view, absl::Cord>,
460
+
461
+ std::pair<absl::string_view, std::string>,
462
+ std::pair<absl::string_view, absl::string_view>,
463
+ std::pair<absl::string_view, const char*>>;
464
+ // clang-format on
465
+
466
+ constexpr char kFirstString[] = "abc123";
467
+ constexpr char kSecondString[] = "ijk456";
468
+
469
+ template <typename T>
470
+ struct StringLikeTest : public ::testing::Test {
471
+ typename T::first_type a1{kFirstString};
472
+ typename T::second_type b1{kFirstString};
473
+ typename T::first_type a2{kSecondString};
474
+ typename T::second_type b2{kSecondString};
475
+ hash_default_eq<typename T::first_type> eq;
476
+ hash_default_hash<typename T::first_type> hash;
477
+ };
478
+
479
+ TYPED_TEST_SUITE_P(StringLikeTest);
480
+
481
+ TYPED_TEST_P(StringLikeTest, Eq) {
482
+ EXPECT_TRUE(this->eq(this->a1, this->b1));
483
+ EXPECT_TRUE(this->eq(this->b1, this->a1));
484
+ }
485
+
486
+ TYPED_TEST_P(StringLikeTest, NotEq) {
487
+ EXPECT_FALSE(this->eq(this->a1, this->b2));
488
+ EXPECT_FALSE(this->eq(this->b2, this->a1));
489
+ }
490
+
491
+ TYPED_TEST_P(StringLikeTest, HashEq) {
492
+ EXPECT_EQ(this->hash(this->a1), this->hash(this->b1));
493
+ EXPECT_EQ(this->hash(this->a2), this->hash(this->b2));
494
+ // It would be a poor hash function which collides on these strings.
495
+ EXPECT_NE(this->hash(this->a1), this->hash(this->b2));
496
+ }
497
+
498
+ TYPED_TEST_SUITE(StringLikeTest, StringTypesCartesianProduct);
499
+
500
+ } // namespace
501
+ } // namespace container_internal
502
+ ABSL_NAMESPACE_END
503
+ } // namespace absl
504
+
505
+ enum Hash : size_t {
506
+ kStd = 0x1, // std::hash
507
+ #ifdef _MSC_VER
508
+ kExtension = kStd, // In MSVC, std::hash == ::hash
509
+ #else // _MSC_VER
510
+ kExtension = 0x2, // ::hash (GCC extension)
511
+ #endif // _MSC_VER
512
+ };
513
+
514
+ // H is a bitmask of Hash enumerations.
515
+ // Hashable<H> is hashable via all means specified in H.
516
+ template <int H>
517
+ struct Hashable {
518
+ static constexpr bool HashableBy(Hash h) { return h & H; }
519
+ };
520
+
521
+ namespace std {
522
+ template <int H>
523
+ struct hash<Hashable<H>> {
524
+ template <class E = Hashable<H>,
525
+ class = typename std::enable_if<E::HashableBy(kStd)>::type>
526
+ size_t operator()(E) const {
527
+ return kStd;
528
+ }
529
+ };
530
+ } // namespace std
531
+
532
+ namespace absl {
533
+ ABSL_NAMESPACE_BEGIN
534
+ namespace container_internal {
535
+ namespace {
536
+
537
+ template <class T>
538
+ size_t Hash(const T& v) {
539
+ return hash_default_hash<T>()(v);
540
+ }
541
+
542
+ TEST(Delegate, HashDispatch) {
543
+ EXPECT_EQ(Hash(kStd), Hash(Hashable<kStd>()));
544
+ }
545
+
546
+ } // namespace
547
+ } // namespace container_internal
548
+ ABSL_NAMESPACE_END
549
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/hash_generator_testing.cc ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/container/internal/hash_generator_testing.h"
16
+
17
+ #include <deque>
18
+
19
+ #include "absl/base/no_destructor.h"
20
+
21
+ namespace absl {
22
+ ABSL_NAMESPACE_BEGIN
23
+ namespace container_internal {
24
+ namespace hash_internal {
25
+ namespace {
26
+
27
+ class RandomDeviceSeedSeq {
28
+ public:
29
+ using result_type = typename std::random_device::result_type;
30
+
31
+ template <class Iterator>
32
+ void generate(Iterator start, Iterator end) {
33
+ while (start != end) {
34
+ *start = gen_();
35
+ ++start;
36
+ }
37
+ }
38
+
39
+ private:
40
+ std::random_device gen_;
41
+ };
42
+
43
+ } // namespace
44
+
45
+ std::mt19937_64* GetSharedRng() {
46
+ static absl::NoDestructor<std::mt19937_64> rng([] {
47
+ RandomDeviceSeedSeq seed_seq;
48
+ return std::mt19937_64(seed_seq);
49
+ }());
50
+ return rng.get();
51
+ }
52
+
53
+ std::string Generator<std::string>::operator()() const {
54
+ // NOLINTNEXTLINE(runtime/int)
55
+ std::uniform_int_distribution<short> chars(0x20, 0x7E);
56
+ std::string res;
57
+ res.resize(32);
58
+ std::generate(res.begin(), res.end(),
59
+ [&]() { return chars(*GetSharedRng()); });
60
+ return res;
61
+ }
62
+
63
+ absl::string_view Generator<absl::string_view>::operator()() const {
64
+ static absl::NoDestructor<std::deque<std::string>> arena;
65
+ // NOLINTNEXTLINE(runtime/int)
66
+ std::uniform_int_distribution<short> chars(0x20, 0x7E);
67
+ arena->emplace_back();
68
+ auto& res = arena->back();
69
+ res.resize(32);
70
+ std::generate(res.begin(), res.end(),
71
+ [&]() { return chars(*GetSharedRng()); });
72
+ return res;
73
+ }
74
+
75
+ } // namespace hash_internal
76
+ } // namespace container_internal
77
+ ABSL_NAMESPACE_END
78
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/hash_generator_testing.h ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // Generates random values for testing. Specialized only for the few types we
16
+ // care about.
17
+
18
+ #ifndef ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_
19
+ #define ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_
20
+
21
+ #include <stdint.h>
22
+
23
+ #include <algorithm>
24
+ #include <cassert>
25
+ #include <iosfwd>
26
+ #include <random>
27
+ #include <tuple>
28
+ #include <type_traits>
29
+ #include <utility>
30
+ #include <vector>
31
+
32
+ #include "absl/container/internal/hash_policy_testing.h"
33
+ #include "absl/memory/memory.h"
34
+ #include "absl/meta/type_traits.h"
35
+ #include "absl/strings/string_view.h"
36
+
37
+ namespace absl {
38
+ ABSL_NAMESPACE_BEGIN
39
+ namespace container_internal {
40
+ namespace hash_internal {
41
+ namespace generator_internal {
42
+
43
+ template <class Container, class = void>
44
+ struct IsMap : std::false_type {};
45
+
46
+ template <class Map>
47
+ struct IsMap<Map, absl::void_t<typename Map::mapped_type>> : std::true_type {};
48
+
49
+ } // namespace generator_internal
50
+
51
+ std::mt19937_64* GetSharedRng();
52
+
53
+ enum Enum {
54
+ kEnumEmpty,
55
+ kEnumDeleted,
56
+ };
57
+
58
+ enum class EnumClass : uint64_t {
59
+ kEmpty,
60
+ kDeleted,
61
+ };
62
+
63
+ inline std::ostream& operator<<(std::ostream& o, const EnumClass& ec) {
64
+ return o << static_cast<uint64_t>(ec);
65
+ }
66
+
67
+ template <class T, class E = void>
68
+ struct Generator;
69
+
70
+ template <class T>
71
+ struct Generator<T, typename std::enable_if<std::is_integral<T>::value>::type> {
72
+ T operator()() const {
73
+ std::uniform_int_distribution<T> dist;
74
+ return dist(*GetSharedRng());
75
+ }
76
+ };
77
+
78
+ template <>
79
+ struct Generator<Enum> {
80
+ Enum operator()() const {
81
+ std::uniform_int_distribution<typename std::underlying_type<Enum>::type>
82
+ dist;
83
+ while (true) {
84
+ auto variate = dist(*GetSharedRng());
85
+ if (variate != kEnumEmpty && variate != kEnumDeleted)
86
+ return static_cast<Enum>(variate);
87
+ }
88
+ }
89
+ };
90
+
91
+ template <>
92
+ struct Generator<EnumClass> {
93
+ EnumClass operator()() const {
94
+ std::uniform_int_distribution<
95
+ typename std::underlying_type<EnumClass>::type>
96
+ dist;
97
+ while (true) {
98
+ EnumClass variate = static_cast<EnumClass>(dist(*GetSharedRng()));
99
+ if (variate != EnumClass::kEmpty && variate != EnumClass::kDeleted)
100
+ return static_cast<EnumClass>(variate);
101
+ }
102
+ }
103
+ };
104
+
105
+ template <>
106
+ struct Generator<std::string> {
107
+ std::string operator()() const;
108
+ };
109
+
110
+ template <>
111
+ struct Generator<absl::string_view> {
112
+ absl::string_view operator()() const;
113
+ };
114
+
115
+ template <>
116
+ struct Generator<NonStandardLayout> {
117
+ NonStandardLayout operator()() const {
118
+ return NonStandardLayout(Generator<std::string>()());
119
+ }
120
+ };
121
+
122
+ template <class K, class V>
123
+ struct Generator<std::pair<K, V>> {
124
+ std::pair<K, V> operator()() const {
125
+ return std::pair<K, V>(Generator<typename std::decay<K>::type>()(),
126
+ Generator<typename std::decay<V>::type>()());
127
+ }
128
+ };
129
+
130
+ template <class... Ts>
131
+ struct Generator<std::tuple<Ts...>> {
132
+ std::tuple<Ts...> operator()() const {
133
+ return std::tuple<Ts...>(Generator<typename std::decay<Ts>::type>()()...);
134
+ }
135
+ };
136
+
137
+ template <class T>
138
+ struct Generator<std::unique_ptr<T>> {
139
+ std::unique_ptr<T> operator()() const {
140
+ return absl::make_unique<T>(Generator<T>()());
141
+ }
142
+ };
143
+
144
+ template <class U>
145
+ struct Generator<U, absl::void_t<decltype(std::declval<U&>().key()),
146
+ decltype(std::declval<U&>().value())>>
147
+ : Generator<std::pair<
148
+ typename std::decay<decltype(std::declval<U&>().key())>::type,
149
+ typename std::decay<decltype(std::declval<U&>().value())>::type>> {};
150
+
151
+ template <class Container>
152
+ using GeneratedType = decltype(
153
+ std::declval<const Generator<
154
+ typename std::conditional<generator_internal::IsMap<Container>::value,
155
+ typename Container::value_type,
156
+ typename Container::key_type>::type>&>()());
157
+
158
+ // Naive wrapper that performs a linear search of previous values.
159
+ // Beware this is O(SQR), which is reasonable for smaller kMaxValues.
160
+ template <class T, size_t kMaxValues = 64, class E = void>
161
+ struct UniqueGenerator {
162
+ Generator<T, E> gen;
163
+ std::vector<T> values;
164
+
165
+ T operator()() {
166
+ assert(values.size() < kMaxValues);
167
+ for (;;) {
168
+ T value = gen();
169
+ if (std::find(values.begin(), values.end(), value) == values.end()) {
170
+ values.push_back(value);
171
+ return value;
172
+ }
173
+ }
174
+ }
175
+ };
176
+
177
+ } // namespace hash_internal
178
+ } // namespace container_internal
179
+ ABSL_NAMESPACE_END
180
+ } // namespace absl
181
+
182
+ #endif // ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_
weight/_dep/abseil-cpp/absl/container/internal/hash_policy_testing.h ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // Utilities to help tests verify that hash tables properly handle stateful
16
+ // allocators and hash functions.
17
+
18
+ #ifndef ABSL_CONTAINER_INTERNAL_HASH_POLICY_TESTING_H_
19
+ #define ABSL_CONTAINER_INTERNAL_HASH_POLICY_TESTING_H_
20
+
21
+ #include <cstdlib>
22
+ #include <limits>
23
+ #include <memory>
24
+ #include <ostream>
25
+ #include <type_traits>
26
+ #include <utility>
27
+ #include <vector>
28
+
29
+ #include "absl/hash/hash.h"
30
+ #include "absl/strings/string_view.h"
31
+
32
+ namespace absl {
33
+ ABSL_NAMESPACE_BEGIN
34
+ namespace container_internal {
35
+ namespace hash_testing_internal {
36
+
37
+ template <class Derived>
38
+ struct WithId {
39
+ WithId() : id_(next_id<Derived>()) {}
40
+ WithId(const WithId& that) : id_(that.id_) {}
41
+ WithId(WithId&& that) : id_(that.id_) { that.id_ = 0; }
42
+ WithId& operator=(const WithId& that) {
43
+ id_ = that.id_;
44
+ return *this;
45
+ }
46
+ WithId& operator=(WithId&& that) {
47
+ id_ = that.id_;
48
+ that.id_ = 0;
49
+ return *this;
50
+ }
51
+
52
+ size_t id() const { return id_; }
53
+
54
+ friend bool operator==(const WithId& a, const WithId& b) {
55
+ return a.id_ == b.id_;
56
+ }
57
+ friend bool operator!=(const WithId& a, const WithId& b) { return !(a == b); }
58
+
59
+ protected:
60
+ explicit WithId(size_t id) : id_(id) {}
61
+
62
+ private:
63
+ size_t id_;
64
+
65
+ template <class T>
66
+ static size_t next_id() {
67
+ // 0 is reserved for moved from state.
68
+ static size_t gId = 1;
69
+ return gId++;
70
+ }
71
+ };
72
+
73
+ } // namespace hash_testing_internal
74
+
75
+ struct NonStandardLayout {
76
+ NonStandardLayout() {}
77
+ explicit NonStandardLayout(std::string s) : value(std::move(s)) {}
78
+ virtual ~NonStandardLayout() {}
79
+
80
+ friend bool operator==(const NonStandardLayout& a,
81
+ const NonStandardLayout& b) {
82
+ return a.value == b.value;
83
+ }
84
+ friend bool operator!=(const NonStandardLayout& a,
85
+ const NonStandardLayout& b) {
86
+ return a.value != b.value;
87
+ }
88
+
89
+ template <typename H>
90
+ friend H AbslHashValue(H h, const NonStandardLayout& v) {
91
+ return H::combine(std::move(h), v.value);
92
+ }
93
+
94
+ std::string value;
95
+ };
96
+
97
+ struct StatefulTestingHash
98
+ : absl::container_internal::hash_testing_internal::WithId<
99
+ StatefulTestingHash> {
100
+ template <class T>
101
+ size_t operator()(const T& t) const {
102
+ return absl::Hash<T>{}(t);
103
+ }
104
+ };
105
+
106
+ struct StatefulTestingEqual
107
+ : absl::container_internal::hash_testing_internal::WithId<
108
+ StatefulTestingEqual> {
109
+ template <class T, class U>
110
+ bool operator()(const T& t, const U& u) const {
111
+ return t == u;
112
+ }
113
+ };
114
+
115
+ // It is expected that Alloc() == Alloc() for all allocators so we cannot use
116
+ // WithId base. We need to explicitly assign ids.
117
+ template <class T = int>
118
+ struct Alloc : std::allocator<T> {
119
+ using propagate_on_container_swap = std::true_type;
120
+
121
+ // Using old paradigm for this to ensure compatibility.
122
+ explicit Alloc(size_t id = 0) : id_(id) {}
123
+
124
+ Alloc(const Alloc&) = default;
125
+ Alloc& operator=(const Alloc&) = default;
126
+
127
+ template <class U>
128
+ Alloc(const Alloc<U>& that) : std::allocator<T>(that), id_(that.id()) {}
129
+
130
+ template <class U>
131
+ struct rebind {
132
+ using other = Alloc<U>;
133
+ };
134
+
135
+ size_t id() const { return id_; }
136
+
137
+ friend bool operator==(const Alloc& a, const Alloc& b) {
138
+ return a.id_ == b.id_;
139
+ }
140
+ friend bool operator!=(const Alloc& a, const Alloc& b) { return !(a == b); }
141
+
142
+ private:
143
+ size_t id_ = (std::numeric_limits<size_t>::max)();
144
+ };
145
+
146
+ template <class Map>
147
+ auto items(const Map& m) -> std::vector<
148
+ std::pair<typename Map::key_type, typename Map::mapped_type>> {
149
+ using std::get;
150
+ std::vector<std::pair<typename Map::key_type, typename Map::mapped_type>> res;
151
+ res.reserve(m.size());
152
+ for (const auto& v : m) res.emplace_back(get<0>(v), get<1>(v));
153
+ return res;
154
+ }
155
+
156
+ template <class Set>
157
+ auto keys(const Set& s)
158
+ -> std::vector<typename std::decay<typename Set::key_type>::type> {
159
+ std::vector<typename std::decay<typename Set::key_type>::type> res;
160
+ res.reserve(s.size());
161
+ for (const auto& v : s) res.emplace_back(v);
162
+ return res;
163
+ }
164
+
165
+ } // namespace container_internal
166
+ ABSL_NAMESPACE_END
167
+ } // namespace absl
168
+
169
+ // ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS is false for glibcxx versions
170
+ // where the unordered containers are missing certain constructors that
171
+ // take allocator arguments. This test is defined ad-hoc for the platforms
172
+ // we care about (notably Crosstool 17) because libstdcxx's useless
173
+ // versioning scheme precludes a more principled solution.
174
+ // From GCC-4.9 Changelog: (src: https://gcc.gnu.org/gcc-4.9/changes.html)
175
+ // "the unordered associative containers in <unordered_map> and <unordered_set>
176
+ // meet the allocator-aware container requirements;"
177
+ #if (defined(__GLIBCXX__) && __GLIBCXX__ <= 20140425 ) || \
178
+ ( __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9 ))
179
+ #define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 0
180
+ #else
181
+ #define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 1
182
+ #endif
183
+
184
+ #endif // ABSL_CONTAINER_INTERNAL_HASH_POLICY_TESTING_H_
weight/_dep/abseil-cpp/absl/container/internal/hash_policy_traits_test.cc ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/container/internal/hash_policy_traits.h"
16
+
17
+ #include <functional>
18
+ #include <memory>
19
+ #include <new>
20
+
21
+ #include "gmock/gmock.h"
22
+ #include "gtest/gtest.h"
23
+
24
+ namespace absl {
25
+ ABSL_NAMESPACE_BEGIN
26
+ namespace container_internal {
27
+ namespace {
28
+
29
+ using ::testing::MockFunction;
30
+ using ::testing::Return;
31
+ using ::testing::ReturnRef;
32
+
33
+ using Alloc = std::allocator<int>;
34
+ using Slot = int;
35
+
36
+ struct PolicyWithoutOptionalOps {
37
+ using slot_type = Slot;
38
+ using key_type = Slot;
39
+ using init_type = Slot;
40
+
41
+ static std::function<Slot&(Slot*)> element;
42
+ static int apply(int v) { return apply_impl(v); }
43
+ static std::function<int(int)> apply_impl;
44
+ static std::function<Slot&(Slot*)> value;
45
+ };
46
+
47
+ std::function<int(int)> PolicyWithoutOptionalOps::apply_impl;
48
+ std::function<Slot&(Slot*)> PolicyWithoutOptionalOps::value;
49
+
50
+ struct Test : ::testing::Test {
51
+ Test() {
52
+ PolicyWithoutOptionalOps::apply_impl = [&](int a1) -> int {
53
+ return apply.Call(a1);
54
+ };
55
+ PolicyWithoutOptionalOps::value = [&](Slot* a1) -> Slot& {
56
+ return value.Call(a1);
57
+ };
58
+ }
59
+
60
+ std::allocator<int> alloc;
61
+ int a = 53;
62
+ MockFunction<int(int)> apply;
63
+ MockFunction<Slot&(Slot*)> value;
64
+ };
65
+
66
+ TEST_F(Test, apply) {
67
+ EXPECT_CALL(apply, Call(42)).WillOnce(Return(1337));
68
+ EXPECT_EQ(1337, (hash_policy_traits<PolicyWithoutOptionalOps>::apply(42)));
69
+ }
70
+
71
+ TEST_F(Test, value) {
72
+ int b = 0;
73
+ EXPECT_CALL(value, Call(&a)).WillOnce(ReturnRef(b));
74
+ EXPECT_EQ(&b, &hash_policy_traits<PolicyWithoutOptionalOps>::value(&a));
75
+ }
76
+
77
+ } // namespace
78
+ } // namespace container_internal
79
+ ABSL_NAMESPACE_END
80
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/hashtablez_sampler.cc ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/container/internal/hashtablez_sampler.h"
16
+
17
+ #include <algorithm>
18
+ #include <atomic>
19
+ #include <cassert>
20
+ #include <cmath>
21
+ #include <functional>
22
+ #include <limits>
23
+
24
+ #include "absl/base/attributes.h"
25
+ #include "absl/base/config.h"
26
+ #include "absl/base/internal/raw_logging.h"
27
+ #include "absl/debugging/stacktrace.h"
28
+ #include "absl/memory/memory.h"
29
+ #include "absl/profiling/internal/exponential_biased.h"
30
+ #include "absl/profiling/internal/sample_recorder.h"
31
+ #include "absl/synchronization/mutex.h"
32
+ #include "absl/time/clock.h"
33
+ #include "absl/utility/utility.h"
34
+
35
+ namespace absl {
36
+ ABSL_NAMESPACE_BEGIN
37
+ namespace container_internal {
38
+
39
+ #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
40
+ constexpr int HashtablezInfo::kMaxStackDepth;
41
+ #endif
42
+
43
+ namespace {
44
+ ABSL_CONST_INIT std::atomic<bool> g_hashtablez_enabled{
45
+ false
46
+ };
47
+ ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_sample_parameter{1 << 10};
48
+ std::atomic<HashtablezConfigListener> g_hashtablez_config_listener{nullptr};
49
+
50
+ #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
51
+ ABSL_PER_THREAD_TLS_KEYWORD absl::profiling_internal::ExponentialBiased
52
+ g_exponential_biased_generator;
53
+ #endif
54
+
55
+ void TriggerHashtablezConfigListener() {
56
+ auto* listener = g_hashtablez_config_listener.load(std::memory_order_acquire);
57
+ if (listener != nullptr) listener();
58
+ }
59
+
60
+ } // namespace
61
+
62
+ #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
63
+ ABSL_PER_THREAD_TLS_KEYWORD SamplingState global_next_sample = {0, 0};
64
+ #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
65
+
66
+ HashtablezSampler& GlobalHashtablezSampler() {
67
+ static auto* sampler = new HashtablezSampler();
68
+ return *sampler;
69
+ }
70
+
71
+ HashtablezInfo::HashtablezInfo() = default;
72
+ HashtablezInfo::~HashtablezInfo() = default;
73
+
74
+ void HashtablezInfo::PrepareForSampling(int64_t stride,
75
+ size_t inline_element_size_value) {
76
+ capacity.store(0, std::memory_order_relaxed);
77
+ size.store(0, std::memory_order_relaxed);
78
+ num_erases.store(0, std::memory_order_relaxed);
79
+ num_rehashes.store(0, std::memory_order_relaxed);
80
+ max_probe_length.store(0, std::memory_order_relaxed);
81
+ total_probe_length.store(0, std::memory_order_relaxed);
82
+ hashes_bitwise_or.store(0, std::memory_order_relaxed);
83
+ hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed);
84
+ hashes_bitwise_xor.store(0, std::memory_order_relaxed);
85
+ max_reserve.store(0, std::memory_order_relaxed);
86
+
87
+ create_time = absl::Now();
88
+ weight = stride;
89
+ // The inliner makes hardcoded skip_count difficult (especially when combined
90
+ // with LTO). We use the ability to exclude stacks by regex when encoding
91
+ // instead.
92
+ depth = absl::GetStackTrace(stack, HashtablezInfo::kMaxStackDepth,
93
+ /* skip_count= */ 0);
94
+ inline_element_size = inline_element_size_value;
95
+ }
96
+
97
+ static bool ShouldForceSampling() {
98
+ enum ForceState {
99
+ kDontForce,
100
+ kForce,
101
+ kUninitialized
102
+ };
103
+ ABSL_CONST_INIT static std::atomic<ForceState> global_state{
104
+ kUninitialized};
105
+ ForceState state = global_state.load(std::memory_order_relaxed);
106
+ if (ABSL_PREDICT_TRUE(state == kDontForce)) return false;
107
+
108
+ if (state == kUninitialized) {
109
+ state = ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)()
110
+ ? kForce
111
+ : kDontForce;
112
+ global_state.store(state, std::memory_order_relaxed);
113
+ }
114
+ return state == kForce;
115
+ }
116
+
117
+ HashtablezInfo* SampleSlow(SamplingState& next_sample,
118
+ size_t inline_element_size) {
119
+ if (ABSL_PREDICT_FALSE(ShouldForceSampling())) {
120
+ next_sample.next_sample = 1;
121
+ const int64_t old_stride = exchange(next_sample.sample_stride, 1);
122
+ HashtablezInfo* result =
123
+ GlobalHashtablezSampler().Register(old_stride, inline_element_size);
124
+ return result;
125
+ }
126
+
127
+ #if !defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
128
+ next_sample = {
129
+ std::numeric_limits<int64_t>::max(),
130
+ std::numeric_limits<int64_t>::max(),
131
+ };
132
+ return nullptr;
133
+ #else
134
+ bool first = next_sample.next_sample < 0;
135
+
136
+ const int64_t next_stride = g_exponential_biased_generator.GetStride(
137
+ g_hashtablez_sample_parameter.load(std::memory_order_relaxed));
138
+
139
+ next_sample.next_sample = next_stride;
140
+ const int64_t old_stride = exchange(next_sample.sample_stride, next_stride);
141
+ // Small values of interval are equivalent to just sampling next time.
142
+ ABSL_ASSERT(next_stride >= 1);
143
+
144
+ // g_hashtablez_enabled can be dynamically flipped, we need to set a threshold
145
+ // low enough that we will start sampling in a reasonable time, so we just use
146
+ // the default sampling rate.
147
+ if (!g_hashtablez_enabled.load(std::memory_order_relaxed)) return nullptr;
148
+
149
+ // We will only be negative on our first count, so we should just retry in
150
+ // that case.
151
+ if (first) {
152
+ if (ABSL_PREDICT_TRUE(--next_sample.next_sample > 0)) return nullptr;
153
+ return SampleSlow(next_sample, inline_element_size);
154
+ }
155
+
156
+ return GlobalHashtablezSampler().Register(old_stride, inline_element_size);
157
+ #endif
158
+ }
159
+
160
+ void UnsampleSlow(HashtablezInfo* info) {
161
+ GlobalHashtablezSampler().Unregister(info);
162
+ }
163
+
164
+ void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) {
165
+ #ifdef ABSL_INTERNAL_HAVE_SSE2
166
+ total_probe_length /= 16;
167
+ #else
168
+ total_probe_length /= 8;
169
+ #endif
170
+ info->total_probe_length.store(total_probe_length, std::memory_order_relaxed);
171
+ info->num_erases.store(0, std::memory_order_relaxed);
172
+ // There is only one concurrent writer, so `load` then `store` is sufficient
173
+ // instead of using `fetch_add`.
174
+ info->num_rehashes.store(
175
+ 1 + info->num_rehashes.load(std::memory_order_relaxed),
176
+ std::memory_order_relaxed);
177
+ }
178
+
179
+ void RecordReservationSlow(HashtablezInfo* info, size_t target_capacity) {
180
+ info->max_reserve.store(
181
+ (std::max)(info->max_reserve.load(std::memory_order_relaxed),
182
+ target_capacity),
183
+ std::memory_order_relaxed);
184
+ }
185
+
186
+ void RecordClearedReservationSlow(HashtablezInfo* info) {
187
+ info->max_reserve.store(0, std::memory_order_relaxed);
188
+ }
189
+
190
+ void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
191
+ size_t capacity) {
192
+ info->size.store(size, std::memory_order_relaxed);
193
+ info->capacity.store(capacity, std::memory_order_relaxed);
194
+ if (size == 0) {
195
+ // This is a clear, reset the total/num_erases too.
196
+ info->total_probe_length.store(0, std::memory_order_relaxed);
197
+ info->num_erases.store(0, std::memory_order_relaxed);
198
+ }
199
+ }
200
+
201
+ void RecordInsertSlow(HashtablezInfo* info, size_t hash,
202
+ size_t distance_from_desired) {
203
+ // SwissTables probe in groups of 16, so scale this to count items probes and
204
+ // not offset from desired.
205
+ size_t probe_length = distance_from_desired;
206
+ #ifdef ABSL_INTERNAL_HAVE_SSE2
207
+ probe_length /= 16;
208
+ #else
209
+ probe_length /= 8;
210
+ #endif
211
+
212
+ info->hashes_bitwise_and.fetch_and(hash, std::memory_order_relaxed);
213
+ info->hashes_bitwise_or.fetch_or(hash, std::memory_order_relaxed);
214
+ info->hashes_bitwise_xor.fetch_xor(hash, std::memory_order_relaxed);
215
+ info->max_probe_length.store(
216
+ std::max(info->max_probe_length.load(std::memory_order_relaxed),
217
+ probe_length),
218
+ std::memory_order_relaxed);
219
+ info->total_probe_length.fetch_add(probe_length, std::memory_order_relaxed);
220
+ info->size.fetch_add(1, std::memory_order_relaxed);
221
+ }
222
+
223
+ void RecordEraseSlow(HashtablezInfo* info) {
224
+ info->size.fetch_sub(1, std::memory_order_relaxed);
225
+ // There is only one concurrent writer, so `load` then `store` is sufficient
226
+ // instead of using `fetch_add`.
227
+ info->num_erases.store(1 + info->num_erases.load(std::memory_order_relaxed),
228
+ std::memory_order_relaxed);
229
+ }
230
+
231
+ void SetHashtablezConfigListener(HashtablezConfigListener l) {
232
+ g_hashtablez_config_listener.store(l, std::memory_order_release);
233
+ }
234
+
235
+ bool IsHashtablezEnabled() {
236
+ return g_hashtablez_enabled.load(std::memory_order_acquire);
237
+ }
238
+
239
+ void SetHashtablezEnabled(bool enabled) {
240
+ SetHashtablezEnabledInternal(enabled);
241
+ TriggerHashtablezConfigListener();
242
+ }
243
+
244
+ void SetHashtablezEnabledInternal(bool enabled) {
245
+ g_hashtablez_enabled.store(enabled, std::memory_order_release);
246
+ }
247
+
248
+ int32_t GetHashtablezSampleParameter() {
249
+ return g_hashtablez_sample_parameter.load(std::memory_order_acquire);
250
+ }
251
+
252
+ void SetHashtablezSampleParameter(int32_t rate) {
253
+ SetHashtablezSampleParameterInternal(rate);
254
+ TriggerHashtablezConfigListener();
255
+ }
256
+
257
+ void SetHashtablezSampleParameterInternal(int32_t rate) {
258
+ if (rate > 0) {
259
+ g_hashtablez_sample_parameter.store(rate, std::memory_order_release);
260
+ } else {
261
+ ABSL_RAW_LOG(ERROR, "Invalid hashtablez sample rate: %lld",
262
+ static_cast<long long>(rate)); // NOLINT(runtime/int)
263
+ }
264
+ }
265
+
266
+ size_t GetHashtablezMaxSamples() {
267
+ return GlobalHashtablezSampler().GetMaxSamples();
268
+ }
269
+
270
+ void SetHashtablezMaxSamples(size_t max) {
271
+ SetHashtablezMaxSamplesInternal(max);
272
+ TriggerHashtablezConfigListener();
273
+ }
274
+
275
+ void SetHashtablezMaxSamplesInternal(size_t max) {
276
+ if (max > 0) {
277
+ GlobalHashtablezSampler().SetMaxSamples(max);
278
+ } else {
279
+ ABSL_RAW_LOG(ERROR, "Invalid hashtablez max samples: 0");
280
+ }
281
+ }
282
+
283
+ } // namespace container_internal
284
+ ABSL_NAMESPACE_END
285
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/hashtablez_sampler.h ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // -----------------------------------------------------------------------------
16
+ // File: hashtablez_sampler.h
17
+ // -----------------------------------------------------------------------------
18
+ //
19
+ // This header file defines the API for a low level library to sample hashtables
20
+ // and collect runtime statistics about them.
21
+ //
22
+ // `HashtablezSampler` controls the lifecycle of `HashtablezInfo` objects which
23
+ // store information about a single sample.
24
+ //
25
+ // `Record*` methods store information into samples.
26
+ // `Sample()` and `Unsample()` make use of a single global sampler with
27
+ // properties controlled by the flags hashtablez_enabled,
28
+ // hashtablez_sample_rate, and hashtablez_max_samples.
29
+ //
30
+ // WARNING
31
+ //
32
+ // Using this sampling API may cause sampled Swiss tables to use the global
33
+ // allocator (operator `new`) in addition to any custom allocator. If you
34
+ // are using a table in an unusual circumstance where allocation or calling a
35
+ // linux syscall is unacceptable, this could interfere.
36
+ //
37
+ // This utility is internal-only. Use at your own risk.
38
+
39
+ #ifndef ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
40
+ #define ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
41
+
42
+ #include <atomic>
43
+ #include <functional>
44
+ #include <memory>
45
+ #include <vector>
46
+
47
+ #include "absl/base/config.h"
48
+ #include "absl/base/internal/per_thread_tls.h"
49
+ #include "absl/base/optimization.h"
50
+ #include "absl/profiling/internal/sample_recorder.h"
51
+ #include "absl/synchronization/mutex.h"
52
+ #include "absl/utility/utility.h"
53
+
54
+ namespace absl {
55
+ ABSL_NAMESPACE_BEGIN
56
+ namespace container_internal {
57
+
58
+ // Stores information about a sampled hashtable. All mutations to this *must*
59
+ // be made through `Record*` functions below. All reads from this *must* only
60
+ // occur in the callback to `HashtablezSampler::Iterate`.
61
+ struct HashtablezInfo : public profiling_internal::Sample<HashtablezInfo> {
62
+ // Constructs the object but does not fill in any fields.
63
+ HashtablezInfo();
64
+ ~HashtablezInfo();
65
+ HashtablezInfo(const HashtablezInfo&) = delete;
66
+ HashtablezInfo& operator=(const HashtablezInfo&) = delete;
67
+
68
+ // Puts the object into a clean state, fills in the logically `const` members,
69
+ // blocking for any readers that are currently sampling the object.
70
+ void PrepareForSampling(int64_t stride, size_t inline_element_size_value)
71
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);
72
+
73
+ // These fields are mutated by the various Record* APIs and need to be
74
+ // thread-safe.
75
+ std::atomic<size_t> capacity;
76
+ std::atomic<size_t> size;
77
+ std::atomic<size_t> num_erases;
78
+ std::atomic<size_t> num_rehashes;
79
+ std::atomic<size_t> max_probe_length;
80
+ std::atomic<size_t> total_probe_length;
81
+ std::atomic<size_t> hashes_bitwise_or;
82
+ std::atomic<size_t> hashes_bitwise_and;
83
+ std::atomic<size_t> hashes_bitwise_xor;
84
+ std::atomic<size_t> max_reserve;
85
+
86
+ // All of the fields below are set by `PrepareForSampling`, they must not be
87
+ // mutated in `Record*` functions. They are logically `const` in that sense.
88
+ // These are guarded by init_mu, but that is not externalized to clients,
89
+ // which can read them only during `SampleRecorder::Iterate` which will hold
90
+ // the lock.
91
+ static constexpr int kMaxStackDepth = 64;
92
+ absl::Time create_time;
93
+ int32_t depth;
94
+ void* stack[kMaxStackDepth];
95
+ size_t inline_element_size; // How big is the slot?
96
+ };
97
+
98
+ void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length);
99
+
100
+ void RecordReservationSlow(HashtablezInfo* info, size_t target_capacity);
101
+
102
+ void RecordClearedReservationSlow(HashtablezInfo* info);
103
+
104
+ void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
105
+ size_t capacity);
106
+
107
+ void RecordInsertSlow(HashtablezInfo* info, size_t hash,
108
+ size_t distance_from_desired);
109
+
110
+ void RecordEraseSlow(HashtablezInfo* info);
111
+
112
+ struct SamplingState {
113
+ int64_t next_sample;
114
+ // When we make a sampling decision, we record that distance so we can weight
115
+ // each sample.
116
+ int64_t sample_stride;
117
+ };
118
+
119
+ HashtablezInfo* SampleSlow(SamplingState& next_sample,
120
+ size_t inline_element_size);
121
+ void UnsampleSlow(HashtablezInfo* info);
122
+
123
+ #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
124
+ #error ABSL_INTERNAL_HASHTABLEZ_SAMPLE cannot be directly set
125
+ #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
126
+
127
+ #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
128
+ class HashtablezInfoHandle {
129
+ public:
130
+ explicit HashtablezInfoHandle() : info_(nullptr) {}
131
+ explicit HashtablezInfoHandle(HashtablezInfo* info) : info_(info) {}
132
+
133
+ // We do not have a destructor. Caller is responsible for calling Unregister
134
+ // before destroying the handle.
135
+ void Unregister() {
136
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
137
+ UnsampleSlow(info_);
138
+ }
139
+
140
+ inline bool IsSampled() const { return ABSL_PREDICT_FALSE(info_ != nullptr); }
141
+
142
+ inline void RecordStorageChanged(size_t size, size_t capacity) {
143
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
144
+ RecordStorageChangedSlow(info_, size, capacity);
145
+ }
146
+
147
+ inline void RecordRehash(size_t total_probe_length) {
148
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
149
+ RecordRehashSlow(info_, total_probe_length);
150
+ }
151
+
152
+ inline void RecordReservation(size_t target_capacity) {
153
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
154
+ RecordReservationSlow(info_, target_capacity);
155
+ }
156
+
157
+ inline void RecordClearedReservation() {
158
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
159
+ RecordClearedReservationSlow(info_);
160
+ }
161
+
162
+ inline void RecordInsert(size_t hash, size_t distance_from_desired) {
163
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
164
+ RecordInsertSlow(info_, hash, distance_from_desired);
165
+ }
166
+
167
+ inline void RecordErase() {
168
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
169
+ RecordEraseSlow(info_);
170
+ }
171
+
172
+ friend inline void swap(HashtablezInfoHandle& lhs,
173
+ HashtablezInfoHandle& rhs) {
174
+ std::swap(lhs.info_, rhs.info_);
175
+ }
176
+
177
+ private:
178
+ friend class HashtablezInfoHandlePeer;
179
+ HashtablezInfo* info_;
180
+ };
181
+ #else
182
+ // Ensure that when Hashtablez is turned off at compile time, HashtablezInfo can
183
+ // be removed by the linker, in order to reduce the binary size.
184
+ class HashtablezInfoHandle {
185
+ public:
186
+ explicit HashtablezInfoHandle() = default;
187
+ explicit HashtablezInfoHandle(std::nullptr_t) {}
188
+
189
+ inline void Unregister() {}
190
+ inline bool IsSampled() const { return false; }
191
+ inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {}
192
+ inline void RecordRehash(size_t /*total_probe_length*/) {}
193
+ inline void RecordReservation(size_t /*target_capacity*/) {}
194
+ inline void RecordClearedReservation() {}
195
+ inline void RecordInsert(size_t /*hash*/, size_t /*distance_from_desired*/) {}
196
+ inline void RecordErase() {}
197
+
198
+ friend inline void swap(HashtablezInfoHandle& /*lhs*/,
199
+ HashtablezInfoHandle& /*rhs*/) {}
200
+ };
201
+ #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
202
+
203
+ #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
204
+ extern ABSL_PER_THREAD_TLS_KEYWORD SamplingState global_next_sample;
205
+ #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
206
+
207
+ // Returns an RAII sampling handle that manages registration and unregistation
208
+ // with the global sampler.
209
+ inline HashtablezInfoHandle Sample(
210
+ size_t inline_element_size ABSL_ATTRIBUTE_UNUSED) {
211
+ #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
212
+ if (ABSL_PREDICT_TRUE(--global_next_sample.next_sample > 0)) {
213
+ return HashtablezInfoHandle(nullptr);
214
+ }
215
+ return HashtablezInfoHandle(
216
+ SampleSlow(global_next_sample, inline_element_size));
217
+ #else
218
+ return HashtablezInfoHandle(nullptr);
219
+ #endif // !ABSL_PER_THREAD_TLS
220
+ }
221
+
222
+ using HashtablezSampler =
223
+ ::absl::profiling_internal::SampleRecorder<HashtablezInfo>;
224
+
225
+ // Returns a global Sampler.
226
+ HashtablezSampler& GlobalHashtablezSampler();
227
+
228
+ using HashtablezConfigListener = void (*)();
229
+ void SetHashtablezConfigListener(HashtablezConfigListener l);
230
+
231
+ // Enables or disables sampling for Swiss tables.
232
+ bool IsHashtablezEnabled();
233
+ void SetHashtablezEnabled(bool enabled);
234
+ void SetHashtablezEnabledInternal(bool enabled);
235
+
236
+ // Sets the rate at which Swiss tables will be sampled.
237
+ int32_t GetHashtablezSampleParameter();
238
+ void SetHashtablezSampleParameter(int32_t rate);
239
+ void SetHashtablezSampleParameterInternal(int32_t rate);
240
+
241
+ // Sets a soft max for the number of samples that will be kept.
242
+ size_t GetHashtablezMaxSamples();
243
+ void SetHashtablezMaxSamples(size_t max);
244
+ void SetHashtablezMaxSamplesInternal(size_t max);
245
+
246
+ // Configuration override.
247
+ // This allows process-wide sampling without depending on order of
248
+ // initialization of static storage duration objects.
249
+ // The definition of this constant is weak, which allows us to inject a
250
+ // different value for it at link time.
251
+ extern "C" bool ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)();
252
+
253
+ } // namespace container_internal
254
+ ABSL_NAMESPACE_END
255
+ } // namespace absl
256
+
257
+ #endif // ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
weight/_dep/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc ADDED
@@ -0,0 +1,424 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/container/internal/hashtablez_sampler.h"
16
+
17
+ #include <atomic>
18
+ #include <limits>
19
+ #include <random>
20
+
21
+ #include "gmock/gmock.h"
22
+ #include "gtest/gtest.h"
23
+ #include "absl/base/attributes.h"
24
+ #include "absl/base/config.h"
25
+ #include "absl/profiling/internal/sample_recorder.h"
26
+ #include "absl/synchronization/blocking_counter.h"
27
+ #include "absl/synchronization/internal/thread_pool.h"
28
+ #include "absl/synchronization/mutex.h"
29
+ #include "absl/synchronization/notification.h"
30
+ #include "absl/time/clock.h"
31
+ #include "absl/time/time.h"
32
+
33
+ #ifdef ABSL_INTERNAL_HAVE_SSE2
34
+ constexpr int kProbeLength = 16;
35
+ #else
36
+ constexpr int kProbeLength = 8;
37
+ #endif
38
+
39
+ namespace absl {
40
+ ABSL_NAMESPACE_BEGIN
41
+ namespace container_internal {
42
+ #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
43
+ class HashtablezInfoHandlePeer {
44
+ public:
45
+ static HashtablezInfo* GetInfo(HashtablezInfoHandle* h) { return h->info_; }
46
+ };
47
+ #else
48
+ class HashtablezInfoHandlePeer {
49
+ public:
50
+ static HashtablezInfo* GetInfo(HashtablezInfoHandle*) { return nullptr; }
51
+ };
52
+ #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
53
+
54
+ namespace {
55
+ using ::absl::synchronization_internal::ThreadPool;
56
+ using ::testing::IsEmpty;
57
+ using ::testing::UnorderedElementsAre;
58
+
59
+ std::vector<size_t> GetSizes(HashtablezSampler* s) {
60
+ std::vector<size_t> res;
61
+ s->Iterate([&](const HashtablezInfo& info) {
62
+ res.push_back(info.size.load(std::memory_order_acquire));
63
+ });
64
+ return res;
65
+ }
66
+
67
+ HashtablezInfo* Register(HashtablezSampler* s, size_t size) {
68
+ const int64_t test_stride = 123;
69
+ const size_t test_element_size = 17;
70
+ auto* info = s->Register(test_stride, test_element_size);
71
+ assert(info != nullptr);
72
+ info->size.store(size);
73
+ return info;
74
+ }
75
+
76
+ TEST(HashtablezInfoTest, PrepareForSampling) {
77
+ absl::Time test_start = absl::Now();
78
+ const int64_t test_stride = 123;
79
+ const size_t test_element_size = 17;
80
+ HashtablezInfo info;
81
+ absl::MutexLock l(&info.init_mu);
82
+ info.PrepareForSampling(test_stride, test_element_size);
83
+
84
+ EXPECT_EQ(info.capacity.load(), 0);
85
+ EXPECT_EQ(info.size.load(), 0);
86
+ EXPECT_EQ(info.num_erases.load(), 0);
87
+ EXPECT_EQ(info.num_rehashes.load(), 0);
88
+ EXPECT_EQ(info.max_probe_length.load(), 0);
89
+ EXPECT_EQ(info.total_probe_length.load(), 0);
90
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
91
+ EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
92
+ EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
93
+ EXPECT_EQ(info.max_reserve.load(), 0);
94
+ EXPECT_GE(info.create_time, test_start);
95
+ EXPECT_EQ(info.weight, test_stride);
96
+ EXPECT_EQ(info.inline_element_size, test_element_size);
97
+
98
+ info.capacity.store(1, std::memory_order_relaxed);
99
+ info.size.store(1, std::memory_order_relaxed);
100
+ info.num_erases.store(1, std::memory_order_relaxed);
101
+ info.max_probe_length.store(1, std::memory_order_relaxed);
102
+ info.total_probe_length.store(1, std::memory_order_relaxed);
103
+ info.hashes_bitwise_or.store(1, std::memory_order_relaxed);
104
+ info.hashes_bitwise_and.store(1, std::memory_order_relaxed);
105
+ info.hashes_bitwise_xor.store(1, std::memory_order_relaxed);
106
+ info.max_reserve.store(1, std::memory_order_relaxed);
107
+ info.create_time = test_start - absl::Hours(20);
108
+
109
+ info.PrepareForSampling(test_stride * 2, test_element_size);
110
+ EXPECT_EQ(info.capacity.load(), 0);
111
+ EXPECT_EQ(info.size.load(), 0);
112
+ EXPECT_EQ(info.num_erases.load(), 0);
113
+ EXPECT_EQ(info.num_rehashes.load(), 0);
114
+ EXPECT_EQ(info.max_probe_length.load(), 0);
115
+ EXPECT_EQ(info.total_probe_length.load(), 0);
116
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
117
+ EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
118
+ EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
119
+ EXPECT_EQ(info.max_reserve.load(), 0);
120
+ EXPECT_EQ(info.weight, 2 * test_stride);
121
+ EXPECT_EQ(info.inline_element_size, test_element_size);
122
+ EXPECT_GE(info.create_time, test_start);
123
+ }
124
+
125
+ TEST(HashtablezInfoTest, RecordStorageChanged) {
126
+ HashtablezInfo info;
127
+ absl::MutexLock l(&info.init_mu);
128
+ const int64_t test_stride = 21;
129
+ const size_t test_element_size = 19;
130
+ info.PrepareForSampling(test_stride, test_element_size);
131
+ RecordStorageChangedSlow(&info, 17, 47);
132
+ EXPECT_EQ(info.size.load(), 17);
133
+ EXPECT_EQ(info.capacity.load(), 47);
134
+ RecordStorageChangedSlow(&info, 20, 20);
135
+ EXPECT_EQ(info.size.load(), 20);
136
+ EXPECT_EQ(info.capacity.load(), 20);
137
+ }
138
+
139
+ TEST(HashtablezInfoTest, RecordInsert) {
140
+ HashtablezInfo info;
141
+ absl::MutexLock l(&info.init_mu);
142
+ const int64_t test_stride = 25;
143
+ const size_t test_element_size = 23;
144
+ info.PrepareForSampling(test_stride, test_element_size);
145
+ EXPECT_EQ(info.max_probe_length.load(), 0);
146
+ RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength);
147
+ EXPECT_EQ(info.max_probe_length.load(), 6);
148
+ EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000FF00);
149
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0x0000FF00);
150
+ EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x0000FF00);
151
+ RecordInsertSlow(&info, 0x000FF000, 4 * kProbeLength);
152
+ EXPECT_EQ(info.max_probe_length.load(), 6);
153
+ EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000F000);
154
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0x000FFF00);
155
+ EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x000F0F00);
156
+ RecordInsertSlow(&info, 0x00FF0000, 12 * kProbeLength);
157
+ EXPECT_EQ(info.max_probe_length.load(), 12);
158
+ EXPECT_EQ(info.hashes_bitwise_and.load(), 0x00000000);
159
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0x00FFFF00);
160
+ EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x00F00F00);
161
+ }
162
+
163
+ TEST(HashtablezInfoTest, RecordErase) {
164
+ const int64_t test_stride = 31;
165
+ const size_t test_element_size = 29;
166
+ HashtablezInfo info;
167
+ absl::MutexLock l(&info.init_mu);
168
+ info.PrepareForSampling(test_stride, test_element_size);
169
+ EXPECT_EQ(info.num_erases.load(), 0);
170
+ EXPECT_EQ(info.size.load(), 0);
171
+ RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength);
172
+ EXPECT_EQ(info.size.load(), 1);
173
+ RecordEraseSlow(&info);
174
+ EXPECT_EQ(info.size.load(), 0);
175
+ EXPECT_EQ(info.num_erases.load(), 1);
176
+ EXPECT_EQ(info.inline_element_size, test_element_size);
177
+ }
178
+
179
+ TEST(HashtablezInfoTest, RecordRehash) {
180
+ const int64_t test_stride = 33;
181
+ const size_t test_element_size = 31;
182
+ HashtablezInfo info;
183
+ absl::MutexLock l(&info.init_mu);
184
+ info.PrepareForSampling(test_stride, test_element_size);
185
+ RecordInsertSlow(&info, 0x1, 0);
186
+ RecordInsertSlow(&info, 0x2, kProbeLength);
187
+ RecordInsertSlow(&info, 0x4, kProbeLength);
188
+ RecordInsertSlow(&info, 0x8, 2 * kProbeLength);
189
+ EXPECT_EQ(info.size.load(), 4);
190
+ EXPECT_EQ(info.total_probe_length.load(), 4);
191
+
192
+ RecordEraseSlow(&info);
193
+ RecordEraseSlow(&info);
194
+ EXPECT_EQ(info.size.load(), 2);
195
+ EXPECT_EQ(info.total_probe_length.load(), 4);
196
+ EXPECT_EQ(info.num_erases.load(), 2);
197
+
198
+ RecordRehashSlow(&info, 3 * kProbeLength);
199
+ EXPECT_EQ(info.size.load(), 2);
200
+ EXPECT_EQ(info.total_probe_length.load(), 3);
201
+ EXPECT_EQ(info.num_erases.load(), 0);
202
+ EXPECT_EQ(info.num_rehashes.load(), 1);
203
+ EXPECT_EQ(info.inline_element_size, test_element_size);
204
+ }
205
+
206
+ TEST(HashtablezInfoTest, RecordReservation) {
207
+ HashtablezInfo info;
208
+ absl::MutexLock l(&info.init_mu);
209
+ const int64_t test_stride = 35;
210
+ const size_t test_element_size = 33;
211
+ info.PrepareForSampling(test_stride, test_element_size);
212
+ RecordReservationSlow(&info, 3);
213
+ EXPECT_EQ(info.max_reserve.load(), 3);
214
+
215
+ RecordReservationSlow(&info, 2);
216
+ // High watermark does not change
217
+ EXPECT_EQ(info.max_reserve.load(), 3);
218
+
219
+ RecordReservationSlow(&info, 10);
220
+ // High watermark does change
221
+ EXPECT_EQ(info.max_reserve.load(), 10);
222
+ }
223
+
224
+ #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
225
+ TEST(HashtablezSamplerTest, SmallSampleParameter) {
226
+ const size_t test_element_size = 31;
227
+ SetHashtablezEnabled(true);
228
+ SetHashtablezSampleParameter(100);
229
+
230
+ for (int i = 0; i < 1000; ++i) {
231
+ SamplingState next_sample = {0, 0};
232
+ HashtablezInfo* sample = SampleSlow(next_sample, test_element_size);
233
+ EXPECT_GT(next_sample.next_sample, 0);
234
+ EXPECT_EQ(next_sample.next_sample, next_sample.sample_stride);
235
+ EXPECT_NE(sample, nullptr);
236
+ UnsampleSlow(sample);
237
+ }
238
+ }
239
+
240
+ TEST(HashtablezSamplerTest, LargeSampleParameter) {
241
+ const size_t test_element_size = 31;
242
+ SetHashtablezEnabled(true);
243
+ SetHashtablezSampleParameter(std::numeric_limits<int32_t>::max());
244
+
245
+ for (int i = 0; i < 1000; ++i) {
246
+ SamplingState next_sample = {0, 0};
247
+ HashtablezInfo* sample = SampleSlow(next_sample, test_element_size);
248
+ EXPECT_GT(next_sample.next_sample, 0);
249
+ EXPECT_EQ(next_sample.next_sample, next_sample.sample_stride);
250
+ EXPECT_NE(sample, nullptr);
251
+ UnsampleSlow(sample);
252
+ }
253
+ }
254
+
255
+ TEST(HashtablezSamplerTest, Sample) {
256
+ const size_t test_element_size = 31;
257
+ SetHashtablezEnabled(true);
258
+ SetHashtablezSampleParameter(100);
259
+ int64_t num_sampled = 0;
260
+ int64_t total = 0;
261
+ double sample_rate = 0.0;
262
+ for (int i = 0; i < 1000000; ++i) {
263
+ HashtablezInfoHandle h = Sample(test_element_size);
264
+ ++total;
265
+ if (h.IsSampled()) {
266
+ ++num_sampled;
267
+ }
268
+ sample_rate = static_cast<double>(num_sampled) / total;
269
+ if (0.005 < sample_rate && sample_rate < 0.015) break;
270
+ }
271
+ EXPECT_NEAR(sample_rate, 0.01, 0.005);
272
+ }
273
+
274
+ TEST(HashtablezSamplerTest, Handle) {
275
+ auto& sampler = GlobalHashtablezSampler();
276
+ const int64_t test_stride = 41;
277
+ const size_t test_element_size = 39;
278
+ HashtablezInfoHandle h(sampler.Register(test_stride, test_element_size));
279
+ auto* info = HashtablezInfoHandlePeer::GetInfo(&h);
280
+ info->hashes_bitwise_and.store(0x12345678, std::memory_order_relaxed);
281
+
282
+ bool found = false;
283
+ sampler.Iterate([&](const HashtablezInfo& h) {
284
+ if (&h == info) {
285
+ EXPECT_EQ(h.weight, test_stride);
286
+ EXPECT_EQ(h.hashes_bitwise_and.load(), 0x12345678);
287
+ found = true;
288
+ }
289
+ });
290
+ EXPECT_TRUE(found);
291
+
292
+ h.Unregister();
293
+ h = HashtablezInfoHandle();
294
+ found = false;
295
+ sampler.Iterate([&](const HashtablezInfo& h) {
296
+ if (&h == info) {
297
+ // this will only happen if some other thread has resurrected the info
298
+ // the old handle was using.
299
+ if (h.hashes_bitwise_and.load() == 0x12345678) {
300
+ found = true;
301
+ }
302
+ }
303
+ });
304
+ EXPECT_FALSE(found);
305
+ }
306
+ #endif
307
+
308
+
309
+ TEST(HashtablezSamplerTest, Registration) {
310
+ HashtablezSampler sampler;
311
+ auto* info1 = Register(&sampler, 1);
312
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(1));
313
+
314
+ auto* info2 = Register(&sampler, 2);
315
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(1, 2));
316
+ info1->size.store(3);
317
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(3, 2));
318
+
319
+ sampler.Unregister(info1);
320
+ sampler.Unregister(info2);
321
+ }
322
+
323
+ TEST(HashtablezSamplerTest, Unregistration) {
324
+ HashtablezSampler sampler;
325
+ std::vector<HashtablezInfo*> infos;
326
+ for (size_t i = 0; i < 3; ++i) {
327
+ infos.push_back(Register(&sampler, i));
328
+ }
329
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 1, 2));
330
+
331
+ sampler.Unregister(infos[1]);
332
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2));
333
+
334
+ infos.push_back(Register(&sampler, 3));
335
+ infos.push_back(Register(&sampler, 4));
336
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2, 3, 4));
337
+ sampler.Unregister(infos[3]);
338
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2, 4));
339
+
340
+ sampler.Unregister(infos[0]);
341
+ sampler.Unregister(infos[2]);
342
+ sampler.Unregister(infos[4]);
343
+ EXPECT_THAT(GetSizes(&sampler), IsEmpty());
344
+ }
345
+
346
+ TEST(HashtablezSamplerTest, MultiThreaded) {
347
+ HashtablezSampler sampler;
348
+ Notification stop;
349
+ ThreadPool pool(10);
350
+
351
+ for (int i = 0; i < 10; ++i) {
352
+ const int64_t sampling_stride = 11 + i % 3;
353
+ const size_t elt_size = 10 + i % 2;
354
+ pool.Schedule([&sampler, &stop, sampling_stride, elt_size]() {
355
+ std::random_device rd;
356
+ std::mt19937 gen(rd());
357
+
358
+ std::vector<HashtablezInfo*> infoz;
359
+ while (!stop.HasBeenNotified()) {
360
+ if (infoz.empty()) {
361
+ infoz.push_back(sampler.Register(sampling_stride, elt_size));
362
+ }
363
+ switch (std::uniform_int_distribution<>(0, 2)(gen)) {
364
+ case 0: {
365
+ infoz.push_back(sampler.Register(sampling_stride, elt_size));
366
+ break;
367
+ }
368
+ case 1: {
369
+ size_t p =
370
+ std::uniform_int_distribution<>(0, infoz.size() - 1)(gen);
371
+ HashtablezInfo* info = infoz[p];
372
+ infoz[p] = infoz.back();
373
+ infoz.pop_back();
374
+ EXPECT_EQ(info->weight, sampling_stride);
375
+ sampler.Unregister(info);
376
+ break;
377
+ }
378
+ case 2: {
379
+ absl::Duration oldest = absl::ZeroDuration();
380
+ sampler.Iterate([&](const HashtablezInfo& info) {
381
+ oldest = std::max(oldest, absl::Now() - info.create_time);
382
+ });
383
+ ASSERT_GE(oldest, absl::ZeroDuration());
384
+ break;
385
+ }
386
+ }
387
+ }
388
+ });
389
+ }
390
+ // The threads will hammer away. Give it a little bit of time for tsan to
391
+ // spot errors.
392
+ absl::SleepFor(absl::Seconds(3));
393
+ stop.Notify();
394
+ }
395
+
396
+ TEST(HashtablezSamplerTest, Callback) {
397
+ HashtablezSampler sampler;
398
+
399
+ auto* info1 = Register(&sampler, 1);
400
+ auto* info2 = Register(&sampler, 2);
401
+
402
+ static const HashtablezInfo* expected;
403
+
404
+ auto callback = [](const HashtablezInfo& info) {
405
+ // We can't use `info` outside of this callback because the object will be
406
+ // disposed as soon as we return from here.
407
+ EXPECT_EQ(&info, expected);
408
+ };
409
+
410
+ // Set the callback.
411
+ EXPECT_EQ(sampler.SetDisposeCallback(callback), nullptr);
412
+ expected = info1;
413
+ sampler.Unregister(info1);
414
+
415
+ // Unset the callback.
416
+ EXPECT_EQ(callback, sampler.SetDisposeCallback(nullptr));
417
+ expected = nullptr; // no more calls.
418
+ sampler.Unregister(info2);
419
+ }
420
+
421
+ } // namespace
422
+ } // namespace container_internal
423
+ ABSL_NAMESPACE_END
424
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/layout_benchmark.cc ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // Every benchmark should have the same performance as the corresponding
16
+ // headroom benchmark.
17
+
18
+ #include "absl/base/internal/raw_logging.h"
19
+ #include "absl/container/internal/layout.h"
20
+ #include "benchmark/benchmark.h"
21
+
22
+ namespace absl {
23
+ ABSL_NAMESPACE_BEGIN
24
+ namespace container_internal {
25
+ namespace {
26
+
27
+ using ::benchmark::DoNotOptimize;
28
+
29
+ using Int128 = int64_t[2];
30
+
31
+ // This benchmark provides the upper bound on performance for BM_OffsetConstant.
32
+ template <size_t Offset, class... Ts>
33
+ void BM_OffsetConstantHeadroom(benchmark::State& state) {
34
+ for (auto _ : state) {
35
+ DoNotOptimize(Offset);
36
+ }
37
+ }
38
+
39
+ template <size_t Offset, class... Ts>
40
+ void BM_OffsetConstant(benchmark::State& state) {
41
+ using L = Layout<Ts...>;
42
+ ABSL_RAW_CHECK(L::Partial(3, 5, 7).template Offset<3>() == Offset,
43
+ "Invalid offset");
44
+ for (auto _ : state) {
45
+ DoNotOptimize(L::Partial(3, 5, 7).template Offset<3>());
46
+ }
47
+ }
48
+
49
+ template <class... Ts>
50
+ size_t VariableOffset(size_t n, size_t m, size_t k);
51
+
52
+ template <>
53
+ size_t VariableOffset<int8_t, int16_t, int32_t, Int128>(size_t n, size_t m,
54
+ size_t k) {
55
+ auto Align = [](size_t n, size_t m) { return (n + m - 1) & ~(m - 1); };
56
+ return Align(Align(Align(n * 1, 2) + m * 2, 4) + k * 4, 8);
57
+ }
58
+
59
+ template <>
60
+ size_t VariableOffset<Int128, int32_t, int16_t, int8_t>(size_t n, size_t m,
61
+ size_t k) {
62
+ // No alignment is necessary.
63
+ return n * 16 + m * 4 + k * 2;
64
+ }
65
+
66
+ // This benchmark provides the upper bound on performance for BM_OffsetVariable.
67
+ template <size_t Offset, class... Ts>
68
+ void BM_OffsetVariableHeadroom(benchmark::State& state) {
69
+ size_t n = 3;
70
+ size_t m = 5;
71
+ size_t k = 7;
72
+ ABSL_RAW_CHECK(VariableOffset<Ts...>(n, m, k) == Offset, "Invalid offset");
73
+ for (auto _ : state) {
74
+ DoNotOptimize(n);
75
+ DoNotOptimize(m);
76
+ DoNotOptimize(k);
77
+ DoNotOptimize(VariableOffset<Ts...>(n, m, k));
78
+ }
79
+ }
80
+
81
+ template <size_t Offset, class... Ts>
82
+ void BM_OffsetVariable(benchmark::State& state) {
83
+ using L = Layout<Ts...>;
84
+ size_t n = 3;
85
+ size_t m = 5;
86
+ size_t k = 7;
87
+ ABSL_RAW_CHECK(L::Partial(n, m, k).template Offset<3>() == Offset,
88
+ "Invalid offset");
89
+ for (auto _ : state) {
90
+ DoNotOptimize(n);
91
+ DoNotOptimize(m);
92
+ DoNotOptimize(k);
93
+ DoNotOptimize(L::Partial(n, m, k).template Offset<3>());
94
+ }
95
+ }
96
+
97
+ // Run all benchmarks in two modes:
98
+ //
99
+ // Layout with padding: int8_t[3], int16_t[5], int32_t[7], Int128[?].
100
+ // Layout without padding: Int128[3], int32_t[5], int16_t[7], int8_t[?].
101
+
102
+ #define OFFSET_BENCHMARK(NAME, OFFSET, T1, T2, T3, T4) \
103
+ auto& NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4 = \
104
+ NAME<OFFSET, T1, T2, T3, T4>; \
105
+ BENCHMARK(NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4)
106
+
107
+ OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 48, int8_t, int16_t, int32_t,
108
+ Int128);
109
+ OFFSET_BENCHMARK(BM_OffsetConstant, 48, int8_t, int16_t, int32_t, Int128);
110
+ OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 82, Int128, int32_t, int16_t,
111
+ int8_t);
112
+ OFFSET_BENCHMARK(BM_OffsetConstant, 82, Int128, int32_t, int16_t, int8_t);
113
+ OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 48, int8_t, int16_t, int32_t,
114
+ Int128);
115
+ OFFSET_BENCHMARK(BM_OffsetVariable, 48, int8_t, int16_t, int32_t, Int128);
116
+ OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 82, Int128, int32_t, int16_t,
117
+ int8_t);
118
+ OFFSET_BENCHMARK(BM_OffsetVariable, 82, Int128, int32_t, int16_t, int8_t);
119
+ } // namespace
120
+ } // namespace container_internal
121
+ ABSL_NAMESPACE_END
122
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/layout_test.cc ADDED
@@ -0,0 +1,1646 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/container/internal/layout.h"
16
+
17
+ // We need ::max_align_t because some libstdc++ versions don't provide
18
+ // std::max_align_t
19
+ #include <stddef.h>
20
+
21
+ #include <cstdint>
22
+ #include <cstring>
23
+ #include <initializer_list>
24
+ #include <memory>
25
+ #include <ostream>
26
+ #include <string>
27
+ #include <tuple>
28
+ #include <type_traits>
29
+
30
+ #include "gmock/gmock.h"
31
+ #include "gtest/gtest.h"
32
+ #include "absl/base/config.h"
33
+ #include "absl/log/check.h"
34
+ #include "absl/types/span.h"
35
+ #include "absl/utility/utility.h"
36
+
37
+ namespace absl {
38
+ ABSL_NAMESPACE_BEGIN
39
+ namespace container_internal {
40
+ namespace {
41
+
42
+ using ::absl::Span;
43
+ using ::testing::ElementsAre;
44
+
45
+ size_t Distance(const void* from, const void* to) {
46
+ CHECK_LE(from, to) << "Distance must be non-negative";
47
+ return static_cast<const char*>(to) - static_cast<const char*>(from);
48
+ }
49
+
50
+ template <class Expected, class Actual>
51
+ Expected Type(Actual val) {
52
+ static_assert(std::is_same<Expected, Actual>(), "");
53
+ return val;
54
+ }
55
+
56
+ // Helper classes to test different size and alignments.
57
+ struct alignas(8) Int128 {
58
+ uint64_t a, b;
59
+ friend bool operator==(Int128 lhs, Int128 rhs) {
60
+ return std::tie(lhs.a, lhs.b) == std::tie(rhs.a, rhs.b);
61
+ }
62
+
63
+ static std::string Name() {
64
+ return internal_layout::adl_barrier::TypeName<Int128>();
65
+ }
66
+ };
67
+
68
+ // int64_t is *not* 8-byte aligned on all platforms!
69
+ struct alignas(8) Int64 {
70
+ int64_t a;
71
+ friend bool operator==(Int64 lhs, Int64 rhs) {
72
+ return lhs.a == rhs.a;
73
+ }
74
+ };
75
+
76
+ // Properties of types that this test relies on.
77
+ static_assert(sizeof(int8_t) == 1, "");
78
+ static_assert(alignof(int8_t) == 1, "");
79
+ static_assert(sizeof(int16_t) == 2, "");
80
+ static_assert(alignof(int16_t) == 2, "");
81
+ static_assert(sizeof(int32_t) == 4, "");
82
+ static_assert(alignof(int32_t) == 4, "");
83
+ static_assert(sizeof(Int64) == 8, "");
84
+ static_assert(alignof(Int64) == 8, "");
85
+ static_assert(sizeof(Int128) == 16, "");
86
+ static_assert(alignof(Int128) == 8, "");
87
+
88
+ template <class Expected, class Actual>
89
+ void SameType() {
90
+ static_assert(std::is_same<Expected, Actual>(), "");
91
+ }
92
+
93
+ TEST(Layout, ElementType) {
94
+ {
95
+ using L = Layout<int32_t>;
96
+ SameType<int32_t, L::ElementType<0>>();
97
+ SameType<int32_t, decltype(L::Partial())::ElementType<0>>();
98
+ SameType<int32_t, decltype(L::Partial(0))::ElementType<0>>();
99
+ }
100
+ {
101
+ using L = Layout<int32_t, int32_t>;
102
+ SameType<int32_t, L::ElementType<0>>();
103
+ SameType<int32_t, L::ElementType<1>>();
104
+ SameType<int32_t, decltype(L::Partial())::ElementType<0>>();
105
+ SameType<int32_t, decltype(L::Partial())::ElementType<1>>();
106
+ SameType<int32_t, decltype(L::Partial(0))::ElementType<0>>();
107
+ SameType<int32_t, decltype(L::Partial(0))::ElementType<1>>();
108
+ }
109
+ {
110
+ using L = Layout<int8_t, int32_t, Int128>;
111
+ SameType<int8_t, L::ElementType<0>>();
112
+ SameType<int32_t, L::ElementType<1>>();
113
+ SameType<Int128, L::ElementType<2>>();
114
+ SameType<int8_t, decltype(L::Partial())::ElementType<0>>();
115
+ SameType<int8_t, decltype(L::Partial(0))::ElementType<0>>();
116
+ SameType<int32_t, decltype(L::Partial(0))::ElementType<1>>();
117
+ SameType<int8_t, decltype(L::Partial(0, 0))::ElementType<0>>();
118
+ SameType<int32_t, decltype(L::Partial(0, 0))::ElementType<1>>();
119
+ SameType<Int128, decltype(L::Partial(0, 0))::ElementType<2>>();
120
+ SameType<int8_t, decltype(L::Partial(0, 0, 0))::ElementType<0>>();
121
+ SameType<int32_t, decltype(L::Partial(0, 0, 0))::ElementType<1>>();
122
+ SameType<Int128, decltype(L::Partial(0, 0, 0))::ElementType<2>>();
123
+ }
124
+ }
125
+
126
+ TEST(Layout, ElementTypes) {
127
+ {
128
+ using L = Layout<int32_t>;
129
+ SameType<std::tuple<int32_t>, L::ElementTypes>();
130
+ SameType<std::tuple<int32_t>, decltype(L::Partial())::ElementTypes>();
131
+ SameType<std::tuple<int32_t>, decltype(L::Partial(0))::ElementTypes>();
132
+ }
133
+ {
134
+ using L = Layout<int32_t, int32_t>;
135
+ SameType<std::tuple<int32_t, int32_t>, L::ElementTypes>();
136
+ SameType<std::tuple<int32_t, int32_t>,
137
+ decltype(L::Partial())::ElementTypes>();
138
+ SameType<std::tuple<int32_t, int32_t>,
139
+ decltype(L::Partial(0))::ElementTypes>();
140
+ }
141
+ {
142
+ using L = Layout<int8_t, int32_t, Int128>;
143
+ SameType<std::tuple<int8_t, int32_t, Int128>, L::ElementTypes>();
144
+ SameType<std::tuple<int8_t, int32_t, Int128>,
145
+ decltype(L::Partial())::ElementTypes>();
146
+ SameType<std::tuple<int8_t, int32_t, Int128>,
147
+ decltype(L::Partial(0))::ElementTypes>();
148
+ SameType<std::tuple<int8_t, int32_t, Int128>,
149
+ decltype(L::Partial(0, 0))::ElementTypes>();
150
+ SameType<std::tuple<int8_t, int32_t, Int128>,
151
+ decltype(L::Partial(0, 0, 0))::ElementTypes>();
152
+ }
153
+ }
154
+
155
+ TEST(Layout, OffsetByIndex) {
156
+ {
157
+ using L = Layout<int32_t>;
158
+ EXPECT_EQ(0, L::Partial().Offset<0>());
159
+ EXPECT_EQ(0, L::Partial(3).Offset<0>());
160
+ EXPECT_EQ(0, L(3).Offset<0>());
161
+ }
162
+ {
163
+ using L = Layout<int32_t, int32_t>;
164
+ EXPECT_EQ(0, L::Partial().Offset<0>());
165
+ EXPECT_EQ(0, L::Partial(3).Offset<0>());
166
+ EXPECT_EQ(12, L::Partial(3).Offset<1>());
167
+ EXPECT_EQ(0, L::Partial(3, 5).Offset<0>());
168
+ EXPECT_EQ(12, L::Partial(3, 5).Offset<1>());
169
+ EXPECT_EQ(0, L(3, 5).Offset<0>());
170
+ EXPECT_EQ(12, L(3, 5).Offset<1>());
171
+ }
172
+ {
173
+ using L = Layout<int8_t, int32_t, Int128>;
174
+ EXPECT_EQ(0, L::Partial().Offset<0>());
175
+ EXPECT_EQ(0, L::Partial(0).Offset<0>());
176
+ EXPECT_EQ(0, L::Partial(0).Offset<1>());
177
+ EXPECT_EQ(0, L::Partial(1).Offset<0>());
178
+ EXPECT_EQ(4, L::Partial(1).Offset<1>());
179
+ EXPECT_EQ(0, L::Partial(5).Offset<0>());
180
+ EXPECT_EQ(8, L::Partial(5).Offset<1>());
181
+ EXPECT_EQ(0, L::Partial(0, 0).Offset<0>());
182
+ EXPECT_EQ(0, L::Partial(0, 0).Offset<1>());
183
+ EXPECT_EQ(0, L::Partial(0, 0).Offset<2>());
184
+ EXPECT_EQ(0, L::Partial(1, 0).Offset<0>());
185
+ EXPECT_EQ(4, L::Partial(1, 0).Offset<1>());
186
+ EXPECT_EQ(8, L::Partial(1, 0).Offset<2>());
187
+ EXPECT_EQ(0, L::Partial(5, 3).Offset<0>());
188
+ EXPECT_EQ(8, L::Partial(5, 3).Offset<1>());
189
+ EXPECT_EQ(24, L::Partial(5, 3).Offset<2>());
190
+ EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<0>());
191
+ EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<1>());
192
+ EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<2>());
193
+ EXPECT_EQ(0, L::Partial(1, 0, 0).Offset<0>());
194
+ EXPECT_EQ(4, L::Partial(1, 0, 0).Offset<1>());
195
+ EXPECT_EQ(8, L::Partial(1, 0, 0).Offset<2>());
196
+ EXPECT_EQ(0, L::Partial(5, 3, 1).Offset<0>());
197
+ EXPECT_EQ(24, L::Partial(5, 3, 1).Offset<2>());
198
+ EXPECT_EQ(8, L::Partial(5, 3, 1).Offset<1>());
199
+ EXPECT_EQ(0, L(5, 3, 1).Offset<0>());
200
+ EXPECT_EQ(24, L(5, 3, 1).Offset<2>());
201
+ EXPECT_EQ(8, L(5, 3, 1).Offset<1>());
202
+ }
203
+ }
204
+
205
+ TEST(Layout, OffsetByType) {
206
+ {
207
+ using L = Layout<int32_t>;
208
+ EXPECT_EQ(0, L::Partial().Offset<int32_t>());
209
+ EXPECT_EQ(0, L::Partial(3).Offset<int32_t>());
210
+ EXPECT_EQ(0, L(3).Offset<int32_t>());
211
+ }
212
+ {
213
+ using L = Layout<int8_t, int32_t, Int128>;
214
+ EXPECT_EQ(0, L::Partial().Offset<int8_t>());
215
+ EXPECT_EQ(0, L::Partial(0).Offset<int8_t>());
216
+ EXPECT_EQ(0, L::Partial(0).Offset<int32_t>());
217
+ EXPECT_EQ(0, L::Partial(1).Offset<int8_t>());
218
+ EXPECT_EQ(4, L::Partial(1).Offset<int32_t>());
219
+ EXPECT_EQ(0, L::Partial(5).Offset<int8_t>());
220
+ EXPECT_EQ(8, L::Partial(5).Offset<int32_t>());
221
+ EXPECT_EQ(0, L::Partial(0, 0).Offset<int8_t>());
222
+ EXPECT_EQ(0, L::Partial(0, 0).Offset<int32_t>());
223
+ EXPECT_EQ(0, L::Partial(0, 0).Offset<Int128>());
224
+ EXPECT_EQ(0, L::Partial(1, 0).Offset<int8_t>());
225
+ EXPECT_EQ(4, L::Partial(1, 0).Offset<int32_t>());
226
+ EXPECT_EQ(8, L::Partial(1, 0).Offset<Int128>());
227
+ EXPECT_EQ(0, L::Partial(5, 3).Offset<int8_t>());
228
+ EXPECT_EQ(8, L::Partial(5, 3).Offset<int32_t>());
229
+ EXPECT_EQ(24, L::Partial(5, 3).Offset<Int128>());
230
+ EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<int8_t>());
231
+ EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<int32_t>());
232
+ EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<Int128>());
233
+ EXPECT_EQ(0, L::Partial(1, 0, 0).Offset<int8_t>());
234
+ EXPECT_EQ(4, L::Partial(1, 0, 0).Offset<int32_t>());
235
+ EXPECT_EQ(8, L::Partial(1, 0, 0).Offset<Int128>());
236
+ EXPECT_EQ(0, L::Partial(5, 3, 1).Offset<int8_t>());
237
+ EXPECT_EQ(24, L::Partial(5, 3, 1).Offset<Int128>());
238
+ EXPECT_EQ(8, L::Partial(5, 3, 1).Offset<int32_t>());
239
+ EXPECT_EQ(0, L(5, 3, 1).Offset<int8_t>());
240
+ EXPECT_EQ(24, L(5, 3, 1).Offset<Int128>());
241
+ EXPECT_EQ(8, L(5, 3, 1).Offset<int32_t>());
242
+ }
243
+ }
244
+
245
+ TEST(Layout, Offsets) {
246
+ {
247
+ using L = Layout<int32_t>;
248
+ EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0));
249
+ EXPECT_THAT(L::Partial(3).Offsets(), ElementsAre(0));
250
+ EXPECT_THAT(L(3).Offsets(), ElementsAre(0));
251
+ }
252
+ {
253
+ using L = Layout<int32_t, int32_t>;
254
+ EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0));
255
+ EXPECT_THAT(L::Partial(3).Offsets(), ElementsAre(0, 12));
256
+ EXPECT_THAT(L::Partial(3, 5).Offsets(), ElementsAre(0, 12));
257
+ EXPECT_THAT(L(3, 5).Offsets(), ElementsAre(0, 12));
258
+ }
259
+ {
260
+ using L = Layout<int8_t, int32_t, Int128>;
261
+ EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0));
262
+ EXPECT_THAT(L::Partial(1).Offsets(), ElementsAre(0, 4));
263
+ EXPECT_THAT(L::Partial(5).Offsets(), ElementsAre(0, 8));
264
+ EXPECT_THAT(L::Partial(0, 0).Offsets(), ElementsAre(0, 0, 0));
265
+ EXPECT_THAT(L::Partial(1, 0).Offsets(), ElementsAre(0, 4, 8));
266
+ EXPECT_THAT(L::Partial(5, 3).Offsets(), ElementsAre(0, 8, 24));
267
+ EXPECT_THAT(L::Partial(0, 0, 0).Offsets(), ElementsAre(0, 0, 0));
268
+ EXPECT_THAT(L::Partial(1, 0, 0).Offsets(), ElementsAre(0, 4, 8));
269
+ EXPECT_THAT(L::Partial(5, 3, 1).Offsets(), ElementsAre(0, 8, 24));
270
+ EXPECT_THAT(L(5, 3, 1).Offsets(), ElementsAre(0, 8, 24));
271
+ }
272
+ }
273
+
274
+ TEST(Layout, AllocSize) {
275
+ {
276
+ using L = Layout<int32_t>;
277
+ EXPECT_EQ(0, L::Partial(0).AllocSize());
278
+ EXPECT_EQ(12, L::Partial(3).AllocSize());
279
+ EXPECT_EQ(12, L(3).AllocSize());
280
+ }
281
+ {
282
+ using L = Layout<int32_t, int32_t>;
283
+ EXPECT_EQ(32, L::Partial(3, 5).AllocSize());
284
+ EXPECT_EQ(32, L(3, 5).AllocSize());
285
+ }
286
+ {
287
+ using L = Layout<int8_t, int32_t, Int128>;
288
+ EXPECT_EQ(0, L::Partial(0, 0, 0).AllocSize());
289
+ EXPECT_EQ(8, L::Partial(1, 0, 0).AllocSize());
290
+ EXPECT_EQ(8, L::Partial(0, 1, 0).AllocSize());
291
+ EXPECT_EQ(16, L::Partial(0, 0, 1).AllocSize());
292
+ EXPECT_EQ(24, L::Partial(1, 1, 1).AllocSize());
293
+ EXPECT_EQ(136, L::Partial(3, 5, 7).AllocSize());
294
+ EXPECT_EQ(136, L(3, 5, 7).AllocSize());
295
+ }
296
+ }
297
+
298
+ TEST(Layout, SizeByIndex) {
299
+ {
300
+ using L = Layout<int32_t>;
301
+ EXPECT_EQ(0, L::Partial(0).Size<0>());
302
+ EXPECT_EQ(3, L::Partial(3).Size<0>());
303
+ EXPECT_EQ(3, L(3).Size<0>());
304
+ }
305
+ {
306
+ using L = Layout<int32_t, int32_t>;
307
+ EXPECT_EQ(0, L::Partial(0).Size<0>());
308
+ EXPECT_EQ(3, L::Partial(3).Size<0>());
309
+ EXPECT_EQ(3, L::Partial(3, 5).Size<0>());
310
+ EXPECT_EQ(5, L::Partial(3, 5).Size<1>());
311
+ EXPECT_EQ(3, L(3, 5).Size<0>());
312
+ EXPECT_EQ(5, L(3, 5).Size<1>());
313
+ }
314
+ {
315
+ using L = Layout<int8_t, int32_t, Int128>;
316
+ EXPECT_EQ(3, L::Partial(3).Size<0>());
317
+ EXPECT_EQ(3, L::Partial(3, 5).Size<0>());
318
+ EXPECT_EQ(5, L::Partial(3, 5).Size<1>());
319
+ EXPECT_EQ(3, L::Partial(3, 5, 7).Size<0>());
320
+ EXPECT_EQ(5, L::Partial(3, 5, 7).Size<1>());
321
+ EXPECT_EQ(7, L::Partial(3, 5, 7).Size<2>());
322
+ EXPECT_EQ(3, L(3, 5, 7).Size<0>());
323
+ EXPECT_EQ(5, L(3, 5, 7).Size<1>());
324
+ EXPECT_EQ(7, L(3, 5, 7).Size<2>());
325
+ }
326
+ }
327
+
328
+ TEST(Layout, SizeByType) {
329
+ {
330
+ using L = Layout<int32_t>;
331
+ EXPECT_EQ(0, L::Partial(0).Size<int32_t>());
332
+ EXPECT_EQ(3, L::Partial(3).Size<int32_t>());
333
+ EXPECT_EQ(3, L(3).Size<int32_t>());
334
+ }
335
+ {
336
+ using L = Layout<int8_t, int32_t, Int128>;
337
+ EXPECT_EQ(3, L::Partial(3).Size<int8_t>());
338
+ EXPECT_EQ(3, L::Partial(3, 5).Size<int8_t>());
339
+ EXPECT_EQ(5, L::Partial(3, 5).Size<int32_t>());
340
+ EXPECT_EQ(3, L::Partial(3, 5, 7).Size<int8_t>());
341
+ EXPECT_EQ(5, L::Partial(3, 5, 7).Size<int32_t>());
342
+ EXPECT_EQ(7, L::Partial(3, 5, 7).Size<Int128>());
343
+ EXPECT_EQ(3, L(3, 5, 7).Size<int8_t>());
344
+ EXPECT_EQ(5, L(3, 5, 7).Size<int32_t>());
345
+ EXPECT_EQ(7, L(3, 5, 7).Size<Int128>());
346
+ }
347
+ }
348
+
349
+ TEST(Layout, Sizes) {
350
+ {
351
+ using L = Layout<int32_t>;
352
+ EXPECT_THAT(L::Partial().Sizes(), ElementsAre());
353
+ EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3));
354
+ EXPECT_THAT(L(3).Sizes(), ElementsAre(3));
355
+ }
356
+ {
357
+ using L = Layout<int32_t, int32_t>;
358
+ EXPECT_THAT(L::Partial().Sizes(), ElementsAre());
359
+ EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3));
360
+ EXPECT_THAT(L::Partial(3, 5).Sizes(), ElementsAre(3, 5));
361
+ EXPECT_THAT(L(3, 5).Sizes(), ElementsAre(3, 5));
362
+ }
363
+ {
364
+ using L = Layout<int8_t, int32_t, Int128>;
365
+ EXPECT_THAT(L::Partial().Sizes(), ElementsAre());
366
+ EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3));
367
+ EXPECT_THAT(L::Partial(3, 5).Sizes(), ElementsAre(3, 5));
368
+ EXPECT_THAT(L::Partial(3, 5, 7).Sizes(), ElementsAre(3, 5, 7));
369
+ EXPECT_THAT(L(3, 5, 7).Sizes(), ElementsAre(3, 5, 7));
370
+ }
371
+ }
372
+
373
+ TEST(Layout, PointerByIndex) {
374
+ alignas(max_align_t) const unsigned char p[100] = {0};
375
+ {
376
+ using L = Layout<int32_t>;
377
+ EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
378
+ EXPECT_EQ(0,
379
+ Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
380
+ EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<0>(p))));
381
+ }
382
+ {
383
+ using L = Layout<int32_t, int32_t>;
384
+ EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
385
+ EXPECT_EQ(0,
386
+ Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
387
+ EXPECT_EQ(12,
388
+ Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
389
+ EXPECT_EQ(
390
+ 0, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
391
+ EXPECT_EQ(
392
+ 12, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
393
+ EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<0>(p))));
394
+ EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<1>(p))));
395
+ }
396
+ {
397
+ using L = Layout<int8_t, int32_t, Int128>;
398
+ EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<0>(p))));
399
+ EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<0>(p))));
400
+ EXPECT_EQ(0,
401
+ Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p))));
402
+ EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<0>(p))));
403
+ EXPECT_EQ(4,
404
+ Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p))));
405
+ EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<0>(p))));
406
+ EXPECT_EQ(8,
407
+ Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p))));
408
+ EXPECT_EQ(0,
409
+ Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<0>(p))));
410
+ EXPECT_EQ(
411
+ 0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
412
+ EXPECT_EQ(0,
413
+ Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<2>(p))));
414
+ EXPECT_EQ(0,
415
+ Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<0>(p))));
416
+ EXPECT_EQ(
417
+ 4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
418
+ EXPECT_EQ(8,
419
+ Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<2>(p))));
420
+ EXPECT_EQ(0,
421
+ Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<0>(p))));
422
+ EXPECT_EQ(
423
+ 8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
424
+ EXPECT_EQ(24,
425
+ Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<2>(p))));
426
+ EXPECT_EQ(
427
+ 0, Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
428
+ EXPECT_EQ(
429
+ 0,
430
+ Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
431
+ EXPECT_EQ(
432
+ 0, Distance(p, Type<const Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
433
+ EXPECT_EQ(
434
+ 0, Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
435
+ EXPECT_EQ(
436
+ 4,
437
+ Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
438
+ EXPECT_EQ(
439
+ 8, Distance(p, Type<const Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
440
+ EXPECT_EQ(
441
+ 0, Distance(p, Type<const int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p))));
442
+ EXPECT_EQ(
443
+ 24,
444
+ Distance(p, Type<const Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
445
+ EXPECT_EQ(
446
+ 8,
447
+ Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
448
+ EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L(5, 3, 1).Pointer<0>(p))));
449
+ EXPECT_EQ(24, Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<2>(p))));
450
+ EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<1>(p))));
451
+ }
452
+ }
453
+
454
+ TEST(Layout, PointerByType) {
455
+ alignas(max_align_t) const unsigned char p[100] = {0};
456
+ {
457
+ using L = Layout<int32_t>;
458
+ EXPECT_EQ(
459
+ 0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p))));
460
+ EXPECT_EQ(
461
+ 0,
462
+ Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
463
+ EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<int32_t>(p))));
464
+ }
465
+ {
466
+ using L = Layout<int8_t, int32_t, Int128>;
467
+ EXPECT_EQ(
468
+ 0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p))));
469
+ EXPECT_EQ(
470
+ 0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
471
+ EXPECT_EQ(
472
+ 0,
473
+ Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
474
+ EXPECT_EQ(
475
+ 0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
476
+ EXPECT_EQ(
477
+ 4,
478
+ Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
479
+ EXPECT_EQ(
480
+ 0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
481
+ EXPECT_EQ(
482
+ 8,
483
+ Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
484
+ EXPECT_EQ(
485
+ 0,
486
+ Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
487
+ EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
488
+ L::Partial(0, 0).Pointer<int32_t>(p))));
489
+ EXPECT_EQ(
490
+ 0,
491
+ Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
492
+ EXPECT_EQ(
493
+ 0,
494
+ Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
495
+ EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
496
+ L::Partial(1, 0).Pointer<int32_t>(p))));
497
+ EXPECT_EQ(
498
+ 8,
499
+ Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
500
+ EXPECT_EQ(
501
+ 0,
502
+ Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
503
+ EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
504
+ L::Partial(5, 3).Pointer<int32_t>(p))));
505
+ EXPECT_EQ(
506
+ 24,
507
+ Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
508
+ EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
509
+ L::Partial(0, 0, 0).Pointer<int8_t>(p))));
510
+ EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
511
+ L::Partial(0, 0, 0).Pointer<int32_t>(p))));
512
+ EXPECT_EQ(0, Distance(p, Type<const Int128*>(
513
+ L::Partial(0, 0, 0).Pointer<Int128>(p))));
514
+ EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
515
+ L::Partial(1, 0, 0).Pointer<int8_t>(p))));
516
+ EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
517
+ L::Partial(1, 0, 0).Pointer<int32_t>(p))));
518
+ EXPECT_EQ(8, Distance(p, Type<const Int128*>(
519
+ L::Partial(1, 0, 0).Pointer<Int128>(p))));
520
+ EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
521
+ L::Partial(5, 3, 1).Pointer<int8_t>(p))));
522
+ EXPECT_EQ(24, Distance(p, Type<const Int128*>(
523
+ L::Partial(5, 3, 1).Pointer<Int128>(p))));
524
+ EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
525
+ L::Partial(5, 3, 1).Pointer<int32_t>(p))));
526
+ EXPECT_EQ(24,
527
+ Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
528
+ EXPECT_EQ(
529
+ 8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
530
+ }
531
+ }
532
+
533
+ TEST(Layout, MutablePointerByIndex) {
534
+ alignas(max_align_t) unsigned char p[100] = {0};
535
+ {
536
+ using L = Layout<int32_t>;
537
+ EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<0>(p))));
538
+ EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<0>(p))));
539
+ EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<0>(p))));
540
+ }
541
+ {
542
+ using L = Layout<int32_t, int32_t>;
543
+ EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<0>(p))));
544
+ EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<0>(p))));
545
+ EXPECT_EQ(12, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<1>(p))));
546
+ EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
547
+ EXPECT_EQ(12, Distance(p, Type<int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
548
+ EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3, 5).Pointer<0>(p))));
549
+ EXPECT_EQ(12, Distance(p, Type<int32_t*>(L(3, 5).Pointer<1>(p))));
550
+ }
551
+ {
552
+ using L = Layout<int8_t, int32_t, Int128>;
553
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<0>(p))));
554
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<0>(p))));
555
+ EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0).Pointer<1>(p))));
556
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<0>(p))));
557
+ EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1).Pointer<1>(p))));
558
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<0>(p))));
559
+ EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5).Pointer<1>(p))));
560
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<0>(p))));
561
+ EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
562
+ EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<2>(p))));
563
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<0>(p))));
564
+ EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
565
+ EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<2>(p))));
566
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<0>(p))));
567
+ EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
568
+ EXPECT_EQ(24, Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<2>(p))));
569
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
570
+ EXPECT_EQ(0,
571
+ Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
572
+ EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
573
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
574
+ EXPECT_EQ(4,
575
+ Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
576
+ EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
577
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p))));
578
+ EXPECT_EQ(24,
579
+ Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
580
+ EXPECT_EQ(8,
581
+ Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
582
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<0>(p))));
583
+ EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<2>(p))));
584
+ EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<1>(p))));
585
+ }
586
+ }
587
+
588
+ TEST(Layout, MutablePointerByType) {
589
+ alignas(max_align_t) unsigned char p[100] = {0};
590
+ {
591
+ using L = Layout<int32_t>;
592
+ EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<int32_t>(p))));
593
+ EXPECT_EQ(0,
594
+ Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
595
+ EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<int32_t>(p))));
596
+ }
597
+ {
598
+ using L = Layout<int8_t, int32_t, Int128>;
599
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<int8_t>(p))));
600
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
601
+ EXPECT_EQ(0,
602
+ Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
603
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
604
+ EXPECT_EQ(4,
605
+ Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
606
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
607
+ EXPECT_EQ(8,
608
+ Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
609
+ EXPECT_EQ(0,
610
+ Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
611
+ EXPECT_EQ(
612
+ 0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
613
+ EXPECT_EQ(0,
614
+ Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
615
+ EXPECT_EQ(0,
616
+ Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
617
+ EXPECT_EQ(
618
+ 4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
619
+ EXPECT_EQ(8,
620
+ Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
621
+ EXPECT_EQ(0,
622
+ Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
623
+ EXPECT_EQ(
624
+ 8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
625
+ EXPECT_EQ(24,
626
+ Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
627
+ EXPECT_EQ(
628
+ 0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
629
+ EXPECT_EQ(
630
+ 0,
631
+ Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
632
+ EXPECT_EQ(
633
+ 0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<Int128>(p))));
634
+ EXPECT_EQ(
635
+ 0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
636
+ EXPECT_EQ(
637
+ 4,
638
+ Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
639
+ EXPECT_EQ(
640
+ 8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<Int128>(p))));
641
+ EXPECT_EQ(
642
+ 0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
643
+ EXPECT_EQ(
644
+ 24, Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<Int128>(p))));
645
+ EXPECT_EQ(
646
+ 8,
647
+ Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
648
+ EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<int8_t>(p))));
649
+ EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
650
+ EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
651
+ }
652
+ }
653
+
654
+ TEST(Layout, Pointers) {
655
+ alignas(max_align_t) const unsigned char p[100] = {0};
656
+ using L = Layout<int8_t, int8_t, Int128>;
657
+ {
658
+ const auto x = L::Partial();
659
+ EXPECT_EQ(std::make_tuple(x.Pointer<0>(p)),
660
+ Type<std::tuple<const int8_t*>>(x.Pointers(p)));
661
+ }
662
+ {
663
+ const auto x = L::Partial(1);
664
+ EXPECT_EQ(std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p)),
665
+ (Type<std::tuple<const int8_t*, const int8_t*>>(x.Pointers(p))));
666
+ }
667
+ {
668
+ const auto x = L::Partial(1, 2);
669
+ EXPECT_EQ(
670
+ std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
671
+ (Type<std::tuple<const int8_t*, const int8_t*, const Int128*>>(
672
+ x.Pointers(p))));
673
+ }
674
+ {
675
+ const auto x = L::Partial(1, 2, 3);
676
+ EXPECT_EQ(
677
+ std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
678
+ (Type<std::tuple<const int8_t*, const int8_t*, const Int128*>>(
679
+ x.Pointers(p))));
680
+ }
681
+ {
682
+ const L x(1, 2, 3);
683
+ EXPECT_EQ(
684
+ std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
685
+ (Type<std::tuple<const int8_t*, const int8_t*, const Int128*>>(
686
+ x.Pointers(p))));
687
+ }
688
+ }
689
+
690
+ TEST(Layout, MutablePointers) {
691
+ alignas(max_align_t) unsigned char p[100] = {0};
692
+ using L = Layout<int8_t, int8_t, Int128>;
693
+ {
694
+ const auto x = L::Partial();
695
+ EXPECT_EQ(std::make_tuple(x.Pointer<0>(p)),
696
+ Type<std::tuple<int8_t*>>(x.Pointers(p)));
697
+ }
698
+ {
699
+ const auto x = L::Partial(1);
700
+ EXPECT_EQ(std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p)),
701
+ (Type<std::tuple<int8_t*, int8_t*>>(x.Pointers(p))));
702
+ }
703
+ {
704
+ const auto x = L::Partial(1, 2);
705
+ EXPECT_EQ(
706
+ std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
707
+ (Type<std::tuple<int8_t*, int8_t*, Int128*>>(x.Pointers(p))));
708
+ }
709
+ {
710
+ const auto x = L::Partial(1, 2, 3);
711
+ EXPECT_EQ(
712
+ std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
713
+ (Type<std::tuple<int8_t*, int8_t*, Int128*>>(x.Pointers(p))));
714
+ }
715
+ {
716
+ const L x(1, 2, 3);
717
+ EXPECT_EQ(
718
+ std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
719
+ (Type<std::tuple<int8_t*, int8_t*, Int128*>>(x.Pointers(p))));
720
+ }
721
+ }
722
+
723
+ TEST(Layout, SliceByIndexSize) {
724
+ alignas(max_align_t) const unsigned char p[100] = {0};
725
+ {
726
+ using L = Layout<int32_t>;
727
+ EXPECT_EQ(0, L::Partial(0).Slice<0>(p).size());
728
+ EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
729
+ EXPECT_EQ(3, L(3).Slice<0>(p).size());
730
+ }
731
+ {
732
+ using L = Layout<int32_t, int32_t>;
733
+ EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
734
+ EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size());
735
+ EXPECT_EQ(5, L(3, 5).Slice<1>(p).size());
736
+ }
737
+ {
738
+ using L = Layout<int8_t, int32_t, Int128>;
739
+ EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
740
+ EXPECT_EQ(3, L::Partial(3, 5).Slice<0>(p).size());
741
+ EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size());
742
+ EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<0>(p).size());
743
+ EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<1>(p).size());
744
+ EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<2>(p).size());
745
+ EXPECT_EQ(3, L(3, 5, 7).Slice<0>(p).size());
746
+ EXPECT_EQ(5, L(3, 5, 7).Slice<1>(p).size());
747
+ EXPECT_EQ(7, L(3, 5, 7).Slice<2>(p).size());
748
+ }
749
+ }
750
+
751
+ TEST(Layout, SliceByTypeSize) {
752
+ alignas(max_align_t) const unsigned char p[100] = {0};
753
+ {
754
+ using L = Layout<int32_t>;
755
+ EXPECT_EQ(0, L::Partial(0).Slice<int32_t>(p).size());
756
+ EXPECT_EQ(3, L::Partial(3).Slice<int32_t>(p).size());
757
+ EXPECT_EQ(3, L(3).Slice<int32_t>(p).size());
758
+ }
759
+ {
760
+ using L = Layout<int8_t, int32_t, Int128>;
761
+ EXPECT_EQ(3, L::Partial(3).Slice<int8_t>(p).size());
762
+ EXPECT_EQ(3, L::Partial(3, 5).Slice<int8_t>(p).size());
763
+ EXPECT_EQ(5, L::Partial(3, 5).Slice<int32_t>(p).size());
764
+ EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<int8_t>(p).size());
765
+ EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<int32_t>(p).size());
766
+ EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<Int128>(p).size());
767
+ EXPECT_EQ(3, L(3, 5, 7).Slice<int8_t>(p).size());
768
+ EXPECT_EQ(5, L(3, 5, 7).Slice<int32_t>(p).size());
769
+ EXPECT_EQ(7, L(3, 5, 7).Slice<Int128>(p).size());
770
+ }
771
+ }
772
+
773
+ TEST(Layout, MutableSliceByIndexSize) {
774
+ alignas(max_align_t) unsigned char p[100] = {0};
775
+ {
776
+ using L = Layout<int32_t>;
777
+ EXPECT_EQ(0, L::Partial(0).Slice<0>(p).size());
778
+ EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
779
+ EXPECT_EQ(3, L(3).Slice<0>(p).size());
780
+ }
781
+ {
782
+ using L = Layout<int32_t, int32_t>;
783
+ EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
784
+ EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size());
785
+ EXPECT_EQ(5, L(3, 5).Slice<1>(p).size());
786
+ }
787
+ {
788
+ using L = Layout<int8_t, int32_t, Int128>;
789
+ EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
790
+ EXPECT_EQ(3, L::Partial(3, 5).Slice<0>(p).size());
791
+ EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size());
792
+ EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<0>(p).size());
793
+ EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<1>(p).size());
794
+ EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<2>(p).size());
795
+ EXPECT_EQ(3, L(3, 5, 7).Slice<0>(p).size());
796
+ EXPECT_EQ(5, L(3, 5, 7).Slice<1>(p).size());
797
+ EXPECT_EQ(7, L(3, 5, 7).Slice<2>(p).size());
798
+ }
799
+ }
800
+
801
+ TEST(Layout, MutableSliceByTypeSize) {
802
+ alignas(max_align_t) unsigned char p[100] = {0};
803
+ {
804
+ using L = Layout<int32_t>;
805
+ EXPECT_EQ(0, L::Partial(0).Slice<int32_t>(p).size());
806
+ EXPECT_EQ(3, L::Partial(3).Slice<int32_t>(p).size());
807
+ EXPECT_EQ(3, L(3).Slice<int32_t>(p).size());
808
+ }
809
+ {
810
+ using L = Layout<int8_t, int32_t, Int128>;
811
+ EXPECT_EQ(3, L::Partial(3).Slice<int8_t>(p).size());
812
+ EXPECT_EQ(3, L::Partial(3, 5).Slice<int8_t>(p).size());
813
+ EXPECT_EQ(5, L::Partial(3, 5).Slice<int32_t>(p).size());
814
+ EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<int8_t>(p).size());
815
+ EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<int32_t>(p).size());
816
+ EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<Int128>(p).size());
817
+ EXPECT_EQ(3, L(3, 5, 7).Slice<int8_t>(p).size());
818
+ EXPECT_EQ(5, L(3, 5, 7).Slice<int32_t>(p).size());
819
+ EXPECT_EQ(7, L(3, 5, 7).Slice<Int128>(p).size());
820
+ }
821
+ }
822
+
823
+ TEST(Layout, SliceByIndexData) {
824
+ alignas(max_align_t) const unsigned char p[100] = {0};
825
+ {
826
+ using L = Layout<int32_t>;
827
+ EXPECT_EQ(
828
+ 0, Distance(
829
+ p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data()));
830
+ EXPECT_EQ(
831
+ 0, Distance(
832
+ p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
833
+ EXPECT_EQ(0,
834
+ Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data()));
835
+ }
836
+ {
837
+ using L = Layout<int32_t, int32_t>;
838
+ EXPECT_EQ(
839
+ 0, Distance(
840
+ p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
841
+ EXPECT_EQ(
842
+ 0,
843
+ Distance(
844
+ p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
845
+ EXPECT_EQ(
846
+ 12,
847
+ Distance(
848
+ p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
849
+ EXPECT_EQ(
850
+ 0, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data()));
851
+ EXPECT_EQ(
852
+ 12, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data()));
853
+ }
854
+ {
855
+ using L = Layout<int8_t, int32_t, Int128>;
856
+ EXPECT_EQ(
857
+ 0, Distance(
858
+ p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data()));
859
+ EXPECT_EQ(
860
+ 0, Distance(
861
+ p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
862
+ EXPECT_EQ(
863
+ 0, Distance(
864
+ p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data()));
865
+ EXPECT_EQ(
866
+ 0,
867
+ Distance(
868
+ p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
869
+ EXPECT_EQ(
870
+ 0,
871
+ Distance(
872
+ p, Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
873
+ EXPECT_EQ(
874
+ 0,
875
+ Distance(
876
+ p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
877
+ EXPECT_EQ(
878
+ 4,
879
+ Distance(
880
+ p, Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
881
+ EXPECT_EQ(
882
+ 0,
883
+ Distance(
884
+ p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
885
+ EXPECT_EQ(
886
+ 8,
887
+ Distance(
888
+ p, Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
889
+ EXPECT_EQ(
890
+ 0,
891
+ Distance(
892
+ p,
893
+ Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
894
+ EXPECT_EQ(
895
+ 0,
896
+ Distance(
897
+ p,
898
+ Type<Span<const int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
899
+ EXPECT_EQ(
900
+ 0,
901
+ Distance(
902
+ p,
903
+ Type<Span<const Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data()));
904
+ EXPECT_EQ(
905
+ 0,
906
+ Distance(
907
+ p,
908
+ Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
909
+ EXPECT_EQ(
910
+ 4,
911
+ Distance(
912
+ p,
913
+ Type<Span<const int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
914
+ EXPECT_EQ(
915
+ 8,
916
+ Distance(
917
+ p,
918
+ Type<Span<const Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data()));
919
+ EXPECT_EQ(
920
+ 0,
921
+ Distance(
922
+ p,
923
+ Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
924
+ EXPECT_EQ(
925
+ 24,
926
+ Distance(
927
+ p,
928
+ Type<Span<const Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data()));
929
+ EXPECT_EQ(
930
+ 8,
931
+ Distance(
932
+ p,
933
+ Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
934
+ EXPECT_EQ(
935
+ 0,
936
+ Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
937
+ EXPECT_EQ(
938
+ 24,
939
+ Distance(p, Type<Span<const Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
940
+ EXPECT_EQ(
941
+ 8,
942
+ Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
943
+ }
944
+ }
945
+
946
+ TEST(Layout, SliceByTypeData) {
947
+ alignas(max_align_t) const unsigned char p[100] = {0};
948
+ {
949
+ using L = Layout<int32_t>;
950
+ EXPECT_EQ(
951
+ 0,
952
+ Distance(
953
+ p,
954
+ Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
955
+ EXPECT_EQ(
956
+ 0,
957
+ Distance(
958
+ p,
959
+ Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
960
+ EXPECT_EQ(
961
+ 0,
962
+ Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data()));
963
+ }
964
+ {
965
+ using L = Layout<int8_t, int32_t, Int128>;
966
+ EXPECT_EQ(
967
+ 0,
968
+ Distance(
969
+ p,
970
+ Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
971
+ EXPECT_EQ(
972
+ 0,
973
+ Distance(
974
+ p,
975
+ Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
976
+ EXPECT_EQ(
977
+ 0,
978
+ Distance(
979
+ p,
980
+ Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
981
+ EXPECT_EQ(
982
+ 0,
983
+ Distance(p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p))
984
+ .data()));
985
+ EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
986
+ L::Partial(0, 0).Slice<int32_t>(p))
987
+ .data()));
988
+ EXPECT_EQ(
989
+ 0,
990
+ Distance(p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p))
991
+ .data()));
992
+ EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
993
+ L::Partial(1, 0).Slice<int32_t>(p))
994
+ .data()));
995
+ EXPECT_EQ(
996
+ 0,
997
+ Distance(p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p))
998
+ .data()));
999
+ EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
1000
+ L::Partial(5, 3).Slice<int32_t>(p))
1001
+ .data()));
1002
+ EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
1003
+ L::Partial(0, 0, 0).Slice<int8_t>(p))
1004
+ .data()));
1005
+ EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
1006
+ L::Partial(0, 0, 0).Slice<int32_t>(p))
1007
+ .data()));
1008
+ EXPECT_EQ(0, Distance(p, Type<Span<const Int128>>(
1009
+ L::Partial(0, 0, 0).Slice<Int128>(p))
1010
+ .data()));
1011
+ EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
1012
+ L::Partial(1, 0, 0).Slice<int8_t>(p))
1013
+ .data()));
1014
+ EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
1015
+ L::Partial(1, 0, 0).Slice<int32_t>(p))
1016
+ .data()));
1017
+ EXPECT_EQ(8, Distance(p, Type<Span<const Int128>>(
1018
+ L::Partial(1, 0, 0).Slice<Int128>(p))
1019
+ .data()));
1020
+ EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
1021
+ L::Partial(5, 3, 1).Slice<int8_t>(p))
1022
+ .data()));
1023
+ EXPECT_EQ(24, Distance(p, Type<Span<const Int128>>(
1024
+ L::Partial(5, 3, 1).Slice<Int128>(p))
1025
+ .data()));
1026
+ EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
1027
+ L::Partial(5, 3, 1).Slice<int32_t>(p))
1028
+ .data()));
1029
+ EXPECT_EQ(
1030
+ 0,
1031
+ Distance(p,
1032
+ Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
1033
+ EXPECT_EQ(
1034
+ 24,
1035
+ Distance(p,
1036
+ Type<Span<const Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
1037
+ EXPECT_EQ(
1038
+ 8,
1039
+ Distance(
1040
+ p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
1041
+ }
1042
+ }
1043
+
1044
+ TEST(Layout, MutableSliceByIndexData) {
1045
+ alignas(max_align_t) unsigned char p[100] = {0};
1046
+ {
1047
+ using L = Layout<int32_t>;
1048
+ EXPECT_EQ(
1049
+ 0, Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data()));
1050
+ EXPECT_EQ(
1051
+ 0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
1052
+ EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<0>(p)).data()));
1053
+ }
1054
+ {
1055
+ using L = Layout<int32_t, int32_t>;
1056
+ EXPECT_EQ(
1057
+ 0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
1058
+ EXPECT_EQ(
1059
+ 0,
1060
+ Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
1061
+ EXPECT_EQ(
1062
+ 12,
1063
+ Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
1064
+ EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3, 5).Slice<0>(p)).data()));
1065
+ EXPECT_EQ(12, Distance(p, Type<Span<int32_t>>(L(3, 5).Slice<1>(p)).data()));
1066
+ }
1067
+ {
1068
+ using L = Layout<int8_t, int32_t, Int128>;
1069
+ EXPECT_EQ(
1070
+ 0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
1071
+ EXPECT_EQ(
1072
+ 0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
1073
+ EXPECT_EQ(
1074
+ 0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
1075
+ EXPECT_EQ(
1076
+ 0,
1077
+ Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
1078
+ EXPECT_EQ(
1079
+ 0,
1080
+ Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
1081
+ EXPECT_EQ(
1082
+ 0,
1083
+ Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
1084
+ EXPECT_EQ(
1085
+ 4,
1086
+ Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
1087
+ EXPECT_EQ(
1088
+ 0,
1089
+ Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
1090
+ EXPECT_EQ(
1091
+ 8,
1092
+ Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
1093
+ EXPECT_EQ(
1094
+ 0, Distance(
1095
+ p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
1096
+ EXPECT_EQ(
1097
+ 0, Distance(
1098
+ p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
1099
+ EXPECT_EQ(
1100
+ 0, Distance(
1101
+ p, Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data()));
1102
+ EXPECT_EQ(
1103
+ 0, Distance(
1104
+ p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
1105
+ EXPECT_EQ(
1106
+ 4, Distance(
1107
+ p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
1108
+ EXPECT_EQ(
1109
+ 8, Distance(
1110
+ p, Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data()));
1111
+ EXPECT_EQ(
1112
+ 0, Distance(
1113
+ p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
1114
+ EXPECT_EQ(
1115
+ 24, Distance(
1116
+ p, Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data()));
1117
+ EXPECT_EQ(
1118
+ 8, Distance(
1119
+ p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
1120
+ EXPECT_EQ(0,
1121
+ Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
1122
+ EXPECT_EQ(24,
1123
+ Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
1124
+ EXPECT_EQ(8,
1125
+ Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
1126
+ }
1127
+ }
1128
+
1129
+ TEST(Layout, MutableSliceByTypeData) {
1130
+ alignas(max_align_t) unsigned char p[100] = {0};
1131
+ {
1132
+ using L = Layout<int32_t>;
1133
+ EXPECT_EQ(
1134
+ 0, Distance(
1135
+ p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
1136
+ EXPECT_EQ(
1137
+ 0, Distance(
1138
+ p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
1139
+ EXPECT_EQ(0,
1140
+ Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data()));
1141
+ }
1142
+ {
1143
+ using L = Layout<int8_t, int32_t, Int128>;
1144
+ EXPECT_EQ(
1145
+ 0,
1146
+ Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
1147
+ EXPECT_EQ(
1148
+ 0,
1149
+ Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
1150
+ EXPECT_EQ(
1151
+ 0,
1152
+ Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
1153
+ EXPECT_EQ(
1154
+ 0,
1155
+ Distance(p,
1156
+ Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
1157
+ EXPECT_EQ(
1158
+ 0,
1159
+ Distance(
1160
+ p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
1161
+ EXPECT_EQ(
1162
+ 0,
1163
+ Distance(p,
1164
+ Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
1165
+ EXPECT_EQ(
1166
+ 4,
1167
+ Distance(
1168
+ p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
1169
+ EXPECT_EQ(
1170
+ 0,
1171
+ Distance(p,
1172
+ Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
1173
+ EXPECT_EQ(
1174
+ 8,
1175
+ Distance(
1176
+ p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
1177
+ EXPECT_EQ(
1178
+ 0,
1179
+ Distance(
1180
+ p,
1181
+ Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
1182
+ EXPECT_EQ(
1183
+ 0,
1184
+ Distance(
1185
+ p,
1186
+ Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data()));
1187
+ EXPECT_EQ(
1188
+ 0,
1189
+ Distance(
1190
+ p,
1191
+ Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<Int128>(p)).data()));
1192
+ EXPECT_EQ(
1193
+ 0,
1194
+ Distance(
1195
+ p,
1196
+ Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
1197
+ EXPECT_EQ(
1198
+ 4,
1199
+ Distance(
1200
+ p,
1201
+ Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data()));
1202
+ EXPECT_EQ(
1203
+ 8,
1204
+ Distance(
1205
+ p,
1206
+ Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<Int128>(p)).data()));
1207
+ EXPECT_EQ(
1208
+ 0,
1209
+ Distance(
1210
+ p,
1211
+ Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
1212
+ EXPECT_EQ(
1213
+ 24,
1214
+ Distance(
1215
+ p,
1216
+ Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<Int128>(p)).data()));
1217
+ EXPECT_EQ(
1218
+ 8,
1219
+ Distance(
1220
+ p,
1221
+ Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data()));
1222
+ EXPECT_EQ(
1223
+ 0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
1224
+ EXPECT_EQ(
1225
+ 24,
1226
+ Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
1227
+ EXPECT_EQ(
1228
+ 8,
1229
+ Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
1230
+ }
1231
+ }
1232
+
1233
+ MATCHER_P(IsSameSlice, slice, "") {
1234
+ return arg.size() == slice.size() && arg.data() == slice.data();
1235
+ }
1236
+
1237
+ template <typename... M>
1238
+ class TupleMatcher {
1239
+ public:
1240
+ explicit TupleMatcher(M... matchers) : matchers_(std::move(matchers)...) {}
1241
+
1242
+ template <typename Tuple>
1243
+ bool MatchAndExplain(const Tuple& p,
1244
+ testing::MatchResultListener* /* listener */) const {
1245
+ static_assert(std::tuple_size<Tuple>::value == sizeof...(M), "");
1246
+ return MatchAndExplainImpl(
1247
+ p, absl::make_index_sequence<std::tuple_size<Tuple>::value>{});
1248
+ }
1249
+
1250
+ // For the matcher concept. Left empty as we don't really need the diagnostics
1251
+ // right now.
1252
+ void DescribeTo(::std::ostream* os) const {}
1253
+ void DescribeNegationTo(::std::ostream* os) const {}
1254
+
1255
+ private:
1256
+ template <typename Tuple, size_t... Is>
1257
+ bool MatchAndExplainImpl(const Tuple& p, absl::index_sequence<Is...>) const {
1258
+ // Using std::min as a simple variadic "and".
1259
+ return std::min(
1260
+ {true, testing::SafeMatcherCast<
1261
+ const typename std::tuple_element<Is, Tuple>::type&>(
1262
+ std::get<Is>(matchers_))
1263
+ .Matches(std::get<Is>(p))...});
1264
+ }
1265
+
1266
+ std::tuple<M...> matchers_;
1267
+ };
1268
+
1269
+ template <typename... M>
1270
+ testing::PolymorphicMatcher<TupleMatcher<M...>> Tuple(M... matchers) {
1271
+ return testing::MakePolymorphicMatcher(
1272
+ TupleMatcher<M...>(std::move(matchers)...));
1273
+ }
1274
+
1275
+ TEST(Layout, Slices) {
1276
+ alignas(max_align_t) const unsigned char p[100] = {0};
1277
+ using L = Layout<int8_t, int8_t, Int128>;
1278
+ {
1279
+ const auto x = L::Partial();
1280
+ EXPECT_THAT(Type<std::tuple<>>(x.Slices(p)), Tuple());
1281
+ }
1282
+ {
1283
+ const auto x = L::Partial(1);
1284
+ EXPECT_THAT(Type<std::tuple<Span<const int8_t>>>(x.Slices(p)),
1285
+ Tuple(IsSameSlice(x.Slice<0>(p))));
1286
+ }
1287
+ {
1288
+ const auto x = L::Partial(1, 2);
1289
+ EXPECT_THAT(
1290
+ (Type<std::tuple<Span<const int8_t>, Span<const int8_t>>>(x.Slices(p))),
1291
+ Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p))));
1292
+ }
1293
+ {
1294
+ const auto x = L::Partial(1, 2, 3);
1295
+ EXPECT_THAT((Type<std::tuple<Span<const int8_t>, Span<const int8_t>,
1296
+ Span<const Int128>>>(x.Slices(p))),
1297
+ Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
1298
+ IsSameSlice(x.Slice<2>(p))));
1299
+ }
1300
+ {
1301
+ const L x(1, 2, 3);
1302
+ EXPECT_THAT((Type<std::tuple<Span<const int8_t>, Span<const int8_t>,
1303
+ Span<const Int128>>>(x.Slices(p))),
1304
+ Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
1305
+ IsSameSlice(x.Slice<2>(p))));
1306
+ }
1307
+ }
1308
+
1309
+ TEST(Layout, MutableSlices) {
1310
+ alignas(max_align_t) unsigned char p[100] = {0};
1311
+ using L = Layout<int8_t, int8_t, Int128>;
1312
+ {
1313
+ const auto x = L::Partial();
1314
+ EXPECT_THAT(Type<std::tuple<>>(x.Slices(p)), Tuple());
1315
+ }
1316
+ {
1317
+ const auto x = L::Partial(1);
1318
+ EXPECT_THAT(Type<std::tuple<Span<int8_t>>>(x.Slices(p)),
1319
+ Tuple(IsSameSlice(x.Slice<0>(p))));
1320
+ }
1321
+ {
1322
+ const auto x = L::Partial(1, 2);
1323
+ EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>>>(x.Slices(p))),
1324
+ Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p))));
1325
+ }
1326
+ {
1327
+ const auto x = L::Partial(1, 2, 3);
1328
+ EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
1329
+ x.Slices(p))),
1330
+ Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
1331
+ IsSameSlice(x.Slice<2>(p))));
1332
+ }
1333
+ {
1334
+ const L x(1, 2, 3);
1335
+ EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
1336
+ x.Slices(p))),
1337
+ Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
1338
+ IsSameSlice(x.Slice<2>(p))));
1339
+ }
1340
+ }
1341
+
1342
+ TEST(Layout, UnalignedTypes) {
1343
+ constexpr Layout<unsigned char, unsigned char, unsigned char> x(1, 2, 3);
1344
+ alignas(max_align_t) unsigned char p[x.AllocSize() + 1];
1345
+ EXPECT_THAT(x.Pointers(p + 1), Tuple(p + 1, p + 2, p + 4));
1346
+ }
1347
+
1348
+ TEST(Layout, CustomAlignment) {
1349
+ constexpr Layout<unsigned char, Aligned<unsigned char, 8>> x(1, 2);
1350
+ alignas(max_align_t) unsigned char p[x.AllocSize()];
1351
+ EXPECT_EQ(10, x.AllocSize());
1352
+ EXPECT_THAT(x.Pointers(p), Tuple(p + 0, p + 8));
1353
+ }
1354
+
1355
+ TEST(Layout, OverAligned) {
1356
+ constexpr size_t M = alignof(max_align_t);
1357
+ constexpr Layout<unsigned char, Aligned<unsigned char, 2 * M>> x(1, 3);
1358
+ #ifdef __GNUC__
1359
+ // Using __attribute__ ((aligned ())) instead of alignas to bypass a gcc bug:
1360
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89357
1361
+ __attribute__((aligned(2 * M))) unsigned char p[x.AllocSize()];
1362
+ #else
1363
+ alignas(2 * M) unsigned char p[x.AllocSize()];
1364
+ #endif
1365
+ EXPECT_EQ(2 * M + 3, x.AllocSize());
1366
+ EXPECT_THAT(x.Pointers(p), Tuple(p + 0, p + 2 * M));
1367
+ }
1368
+
1369
+ TEST(Layout, Alignment) {
1370
+ static_assert(Layout<int8_t>::Alignment() == 1, "");
1371
+ static_assert(Layout<int32_t>::Alignment() == 4, "");
1372
+ static_assert(Layout<Int64>::Alignment() == 8, "");
1373
+ static_assert(Layout<Aligned<int8_t, 64>>::Alignment() == 64, "");
1374
+ static_assert(Layout<int8_t, int32_t, Int64>::Alignment() == 8, "");
1375
+ static_assert(Layout<int8_t, Int64, int32_t>::Alignment() == 8, "");
1376
+ static_assert(Layout<int32_t, int8_t, Int64>::Alignment() == 8, "");
1377
+ static_assert(Layout<int32_t, Int64, int8_t>::Alignment() == 8, "");
1378
+ static_assert(Layout<Int64, int8_t, int32_t>::Alignment() == 8, "");
1379
+ static_assert(Layout<Int64, int32_t, int8_t>::Alignment() == 8, "");
1380
+ }
1381
+
1382
+ TEST(Layout, ConstexprPartial) {
1383
+ constexpr size_t M = alignof(max_align_t);
1384
+ constexpr Layout<unsigned char, Aligned<unsigned char, 2 * M>> x(1, 3);
1385
+ static_assert(x.Partial(1).template Offset<1>() == 2 * M, "");
1386
+ }
1387
+ // [from, to)
1388
+ struct Region {
1389
+ size_t from;
1390
+ size_t to;
1391
+ };
1392
+
1393
+ void ExpectRegionPoisoned(const unsigned char* p, size_t n, bool poisoned) {
1394
+ #ifdef ABSL_HAVE_ADDRESS_SANITIZER
1395
+ for (size_t i = 0; i != n; ++i) {
1396
+ EXPECT_EQ(poisoned, __asan_address_is_poisoned(p + i));
1397
+ }
1398
+ #endif
1399
+ }
1400
+
1401
+ template <size_t N>
1402
+ void ExpectPoisoned(const unsigned char (&buf)[N],
1403
+ std::initializer_list<Region> reg) {
1404
+ size_t prev = 0;
1405
+ for (const Region& r : reg) {
1406
+ ExpectRegionPoisoned(buf + prev, r.from - prev, false);
1407
+ ExpectRegionPoisoned(buf + r.from, r.to - r.from, true);
1408
+ prev = r.to;
1409
+ }
1410
+ ExpectRegionPoisoned(buf + prev, N - prev, false);
1411
+ }
1412
+
1413
+ TEST(Layout, PoisonPadding) {
1414
+ using L = Layout<int8_t, Int64, int32_t, Int128>;
1415
+
1416
+ constexpr size_t n = L::Partial(1, 2, 3, 4).AllocSize();
1417
+ {
1418
+ constexpr auto x = L::Partial();
1419
+ alignas(max_align_t) const unsigned char c[n] = {};
1420
+ x.PoisonPadding(c);
1421
+ EXPECT_EQ(x.Slices(c), x.Slices(c));
1422
+ ExpectPoisoned(c, {});
1423
+ }
1424
+ {
1425
+ constexpr auto x = L::Partial(1);
1426
+ alignas(max_align_t) const unsigned char c[n] = {};
1427
+ x.PoisonPadding(c);
1428
+ EXPECT_EQ(x.Slices(c), x.Slices(c));
1429
+ ExpectPoisoned(c, {{1, 8}});
1430
+ }
1431
+ {
1432
+ constexpr auto x = L::Partial(1, 2);
1433
+ alignas(max_align_t) const unsigned char c[n] = {};
1434
+ x.PoisonPadding(c);
1435
+ EXPECT_EQ(x.Slices(c), x.Slices(c));
1436
+ ExpectPoisoned(c, {{1, 8}});
1437
+ }
1438
+ {
1439
+ constexpr auto x = L::Partial(1, 2, 3);
1440
+ alignas(max_align_t) const unsigned char c[n] = {};
1441
+ x.PoisonPadding(c);
1442
+ EXPECT_EQ(x.Slices(c), x.Slices(c));
1443
+ ExpectPoisoned(c, {{1, 8}, {36, 40}});
1444
+ }
1445
+ {
1446
+ constexpr auto x = L::Partial(1, 2, 3, 4);
1447
+ alignas(max_align_t) const unsigned char c[n] = {};
1448
+ x.PoisonPadding(c);
1449
+ EXPECT_EQ(x.Slices(c), x.Slices(c));
1450
+ ExpectPoisoned(c, {{1, 8}, {36, 40}});
1451
+ }
1452
+ {
1453
+ constexpr L x(1, 2, 3, 4);
1454
+ alignas(max_align_t) const unsigned char c[n] = {};
1455
+ x.PoisonPadding(c);
1456
+ EXPECT_EQ(x.Slices(c), x.Slices(c));
1457
+ ExpectPoisoned(c, {{1, 8}, {36, 40}});
1458
+ }
1459
+ }
1460
+
1461
+ TEST(Layout, DebugString) {
1462
+ {
1463
+ constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial();
1464
+ EXPECT_EQ("@0<signed char>(1)", x.DebugString());
1465
+ }
1466
+ {
1467
+ constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1);
1468
+ EXPECT_EQ("@0<signed char>(1)[1]; @4<int>(4)", x.DebugString());
1469
+ }
1470
+ {
1471
+ constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2);
1472
+ EXPECT_EQ("@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)",
1473
+ x.DebugString());
1474
+ }
1475
+ {
1476
+ constexpr auto x =
1477
+ Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
1478
+ EXPECT_EQ(
1479
+ "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
1480
+ "@16" +
1481
+ Int128::Name() + "(16)",
1482
+ x.DebugString());
1483
+ }
1484
+ {
1485
+ constexpr auto x =
1486
+ Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
1487
+ EXPECT_EQ(
1488
+ "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
1489
+ "@16" +
1490
+ Int128::Name() + "(16)[4]",
1491
+ x.DebugString());
1492
+ }
1493
+ {
1494
+ constexpr Layout<int8_t, int32_t, int8_t, Int128> x(1, 2, 3, 4);
1495
+ EXPECT_EQ(
1496
+ "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
1497
+ "@16" +
1498
+ Int128::Name() + "(16)[4]",
1499
+ x.DebugString());
1500
+ }
1501
+ }
1502
+
1503
+ TEST(Layout, CharTypes) {
1504
+ constexpr Layout<int32_t> x(1);
1505
+ alignas(max_align_t) char c[x.AllocSize()] = {};
1506
+ alignas(max_align_t) unsigned char uc[x.AllocSize()] = {};
1507
+ alignas(max_align_t) signed char sc[x.AllocSize()] = {};
1508
+ alignas(max_align_t) const char cc[x.AllocSize()] = {};
1509
+ alignas(max_align_t) const unsigned char cuc[x.AllocSize()] = {};
1510
+ alignas(max_align_t) const signed char csc[x.AllocSize()] = {};
1511
+
1512
+ Type<int32_t*>(x.Pointer<0>(c));
1513
+ Type<int32_t*>(x.Pointer<0>(uc));
1514
+ Type<int32_t*>(x.Pointer<0>(sc));
1515
+ Type<const int32_t*>(x.Pointer<0>(cc));
1516
+ Type<const int32_t*>(x.Pointer<0>(cuc));
1517
+ Type<const int32_t*>(x.Pointer<0>(csc));
1518
+
1519
+ Type<int32_t*>(x.Pointer<int32_t>(c));
1520
+ Type<int32_t*>(x.Pointer<int32_t>(uc));
1521
+ Type<int32_t*>(x.Pointer<int32_t>(sc));
1522
+ Type<const int32_t*>(x.Pointer<int32_t>(cc));
1523
+ Type<const int32_t*>(x.Pointer<int32_t>(cuc));
1524
+ Type<const int32_t*>(x.Pointer<int32_t>(csc));
1525
+
1526
+ Type<std::tuple<int32_t*>>(x.Pointers(c));
1527
+ Type<std::tuple<int32_t*>>(x.Pointers(uc));
1528
+ Type<std::tuple<int32_t*>>(x.Pointers(sc));
1529
+ Type<std::tuple<const int32_t*>>(x.Pointers(cc));
1530
+ Type<std::tuple<const int32_t*>>(x.Pointers(cuc));
1531
+ Type<std::tuple<const int32_t*>>(x.Pointers(csc));
1532
+
1533
+ Type<Span<int32_t>>(x.Slice<0>(c));
1534
+ Type<Span<int32_t>>(x.Slice<0>(uc));
1535
+ Type<Span<int32_t>>(x.Slice<0>(sc));
1536
+ Type<Span<const int32_t>>(x.Slice<0>(cc));
1537
+ Type<Span<const int32_t>>(x.Slice<0>(cuc));
1538
+ Type<Span<const int32_t>>(x.Slice<0>(csc));
1539
+
1540
+ Type<std::tuple<Span<int32_t>>>(x.Slices(c));
1541
+ Type<std::tuple<Span<int32_t>>>(x.Slices(uc));
1542
+ Type<std::tuple<Span<int32_t>>>(x.Slices(sc));
1543
+ Type<std::tuple<Span<const int32_t>>>(x.Slices(cc));
1544
+ Type<std::tuple<Span<const int32_t>>>(x.Slices(cuc));
1545
+ Type<std::tuple<Span<const int32_t>>>(x.Slices(csc));
1546
+ }
1547
+
1548
+ TEST(Layout, ConstElementType) {
1549
+ constexpr Layout<const int32_t> x(1);
1550
+ alignas(int32_t) char c[x.AllocSize()] = {};
1551
+ const char* cc = c;
1552
+ const int32_t* p = reinterpret_cast<const int32_t*>(cc);
1553
+
1554
+ EXPECT_EQ(alignof(int32_t), x.Alignment());
1555
+
1556
+ EXPECT_EQ(0, x.Offset<0>());
1557
+ EXPECT_EQ(0, x.Offset<const int32_t>());
1558
+
1559
+ EXPECT_THAT(x.Offsets(), ElementsAre(0));
1560
+
1561
+ EXPECT_EQ(1, x.Size<0>());
1562
+ EXPECT_EQ(1, x.Size<const int32_t>());
1563
+
1564
+ EXPECT_THAT(x.Sizes(), ElementsAre(1));
1565
+
1566
+ EXPECT_EQ(sizeof(int32_t), x.AllocSize());
1567
+
1568
+ EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<0>(c)));
1569
+ EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<0>(cc)));
1570
+
1571
+ EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<const int32_t>(c)));
1572
+ EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<const int32_t>(cc)));
1573
+
1574
+ EXPECT_THAT(Type<std::tuple<const int32_t*>>(x.Pointers(c)), Tuple(p));
1575
+ EXPECT_THAT(Type<std::tuple<const int32_t*>>(x.Pointers(cc)), Tuple(p));
1576
+
1577
+ EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<0>(c)),
1578
+ IsSameSlice(Span<const int32_t>(p, 1)));
1579
+ EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<0>(cc)),
1580
+ IsSameSlice(Span<const int32_t>(p, 1)));
1581
+
1582
+ EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<const int32_t>(c)),
1583
+ IsSameSlice(Span<const int32_t>(p, 1)));
1584
+ EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<const int32_t>(cc)),
1585
+ IsSameSlice(Span<const int32_t>(p, 1)));
1586
+
1587
+ EXPECT_THAT(Type<std::tuple<Span<const int32_t>>>(x.Slices(c)),
1588
+ Tuple(IsSameSlice(Span<const int32_t>(p, 1))));
1589
+ EXPECT_THAT(Type<std::tuple<Span<const int32_t>>>(x.Slices(cc)),
1590
+ Tuple(IsSameSlice(Span<const int32_t>(p, 1))));
1591
+ }
1592
+
1593
+ namespace example {
1594
+
1595
+ // Immutable move-only string with sizeof equal to sizeof(void*). The string
1596
+ // size and the characters are kept in the same heap allocation.
1597
+ class CompactString {
1598
+ public:
1599
+ CompactString(const char* s = "") { // NOLINT
1600
+ const size_t size = strlen(s);
1601
+ // size_t[1], followed by char[size + 1].
1602
+ // This statement doesn't allocate memory.
1603
+ const L layout(1, size + 1);
1604
+ // AllocSize() tells us how much memory we need to allocate for all our
1605
+ // data.
1606
+ p_.reset(new unsigned char[layout.AllocSize()]);
1607
+ // If running under ASAN, mark the padding bytes, if any, to catch memory
1608
+ // errors.
1609
+ layout.PoisonPadding(p_.get());
1610
+ // Store the size in the allocation.
1611
+ // Pointer<size_t>() is a synonym for Pointer<0>().
1612
+ *layout.Pointer<size_t>(p_.get()) = size;
1613
+ // Store the characters in the allocation.
1614
+ memcpy(layout.Pointer<char>(p_.get()), s, size + 1);
1615
+ }
1616
+
1617
+ size_t size() const {
1618
+ // Equivalent to reinterpret_cast<size_t&>(*p).
1619
+ return *L::Partial().Pointer<size_t>(p_.get());
1620
+ }
1621
+
1622
+ const char* c_str() const {
1623
+ // Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)).
1624
+ // The argument in Partial(1) specifies that we have size_t[1] in front of
1625
+ // the characters.
1626
+ return L::Partial(1).Pointer<char>(p_.get());
1627
+ }
1628
+
1629
+ private:
1630
+ // Our heap allocation contains a size_t followed by an array of chars.
1631
+ using L = Layout<size_t, char>;
1632
+ std::unique_ptr<unsigned char[]> p_;
1633
+ };
1634
+
1635
+ TEST(CompactString, Works) {
1636
+ CompactString s = "hello";
1637
+ EXPECT_EQ(5, s.size());
1638
+ EXPECT_STREQ("hello", s.c_str());
1639
+ }
1640
+
1641
+ } // namespace example
1642
+
1643
+ } // namespace
1644
+ } // namespace container_internal
1645
+ ABSL_NAMESPACE_END
1646
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/raw_hash_map.h ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
16
+ #define ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
17
+
18
+ #include <tuple>
19
+ #include <type_traits>
20
+ #include <utility>
21
+
22
+ #include "absl/base/attributes.h"
23
+ #include "absl/base/config.h"
24
+ #include "absl/base/internal/throw_delegate.h"
25
+ #include "absl/container/internal/container_memory.h"
26
+ #include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export
27
+
28
+ namespace absl {
29
+ ABSL_NAMESPACE_BEGIN
30
+ namespace container_internal {
31
+
32
+ template <class Policy, class Hash, class Eq, class Alloc>
33
+ class raw_hash_map : public raw_hash_set<Policy, Hash, Eq, Alloc> {
34
+ // P is Policy. It's passed as a template argument to support maps that have
35
+ // incomplete types as values, as in unordered_map<K, IncompleteType>.
36
+ // MappedReference<> may be a non-reference type.
37
+ template <class P>
38
+ using MappedReference = decltype(P::value(
39
+ std::addressof(std::declval<typename raw_hash_map::reference>())));
40
+
41
+ // MappedConstReference<> may be a non-reference type.
42
+ template <class P>
43
+ using MappedConstReference = decltype(P::value(
44
+ std::addressof(std::declval<typename raw_hash_map::const_reference>())));
45
+
46
+ using KeyArgImpl =
47
+ KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
48
+
49
+ public:
50
+ using key_type = typename Policy::key_type;
51
+ using mapped_type = typename Policy::mapped_type;
52
+ template <class K>
53
+ using key_arg = typename KeyArgImpl::template type<K, key_type>;
54
+
55
+ static_assert(!std::is_reference<key_type>::value, "");
56
+
57
+ // TODO(b/187807849): Evaluate whether to support reference mapped_type and
58
+ // remove this assertion if/when it is supported.
59
+ static_assert(!std::is_reference<mapped_type>::value, "");
60
+
61
+ using iterator = typename raw_hash_map::raw_hash_set::iterator;
62
+ using const_iterator = typename raw_hash_map::raw_hash_set::const_iterator;
63
+
64
+ raw_hash_map() {}
65
+ using raw_hash_map::raw_hash_set::raw_hash_set;
66
+
67
+ // The last two template parameters ensure that both arguments are rvalues
68
+ // (lvalue arguments are handled by the overloads below). This is necessary
69
+ // for supporting bitfield arguments.
70
+ //
71
+ // union { int n : 1; };
72
+ // flat_hash_map<int, int> m;
73
+ // m.insert_or_assign(n, n);
74
+ template <class K = key_type, class V = mapped_type, K* = nullptr,
75
+ V* = nullptr>
76
+ std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v)
77
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
78
+ return insert_or_assign_impl(std::forward<K>(k), std::forward<V>(v));
79
+ }
80
+
81
+ template <class K = key_type, class V = mapped_type, K* = nullptr>
82
+ std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v)
83
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
84
+ return insert_or_assign_impl(std::forward<K>(k), v);
85
+ }
86
+
87
+ template <class K = key_type, class V = mapped_type, V* = nullptr>
88
+ std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v)
89
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
90
+ return insert_or_assign_impl(k, std::forward<V>(v));
91
+ }
92
+
93
+ template <class K = key_type, class V = mapped_type>
94
+ std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v)
95
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
96
+ return insert_or_assign_impl(k, v);
97
+ }
98
+
99
+ template <class K = key_type, class V = mapped_type, K* = nullptr,
100
+ V* = nullptr>
101
+ iterator insert_or_assign(const_iterator, key_arg<K>&& k,
102
+ V&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
103
+ return insert_or_assign(std::forward<K>(k), std::forward<V>(v)).first;
104
+ }
105
+
106
+ template <class K = key_type, class V = mapped_type, K* = nullptr>
107
+ iterator insert_or_assign(const_iterator, key_arg<K>&& k,
108
+ const V& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
109
+ return insert_or_assign(std::forward<K>(k), v).first;
110
+ }
111
+
112
+ template <class K = key_type, class V = mapped_type, V* = nullptr>
113
+ iterator insert_or_assign(const_iterator, const key_arg<K>& k,
114
+ V&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
115
+ return insert_or_assign(k, std::forward<V>(v)).first;
116
+ }
117
+
118
+ template <class K = key_type, class V = mapped_type>
119
+ iterator insert_or_assign(const_iterator, const key_arg<K>& k,
120
+ const V& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
121
+ return insert_or_assign(k, v).first;
122
+ }
123
+
124
+ // All `try_emplace()` overloads make the same guarantees regarding rvalue
125
+ // arguments as `std::unordered_map::try_emplace()`, namely that these
126
+ // functions will not move from rvalue arguments if insertions do not happen.
127
+ template <class K = key_type, class... Args,
128
+ typename std::enable_if<
129
+ !std::is_convertible<K, const_iterator>::value, int>::type = 0,
130
+ K* = nullptr>
131
+ std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args)
132
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
133
+ return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
134
+ }
135
+
136
+ template <class K = key_type, class... Args,
137
+ typename std::enable_if<
138
+ !std::is_convertible<K, const_iterator>::value, int>::type = 0>
139
+ std::pair<iterator, bool> try_emplace(const key_arg<K>& k, Args&&... args)
140
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
141
+ return try_emplace_impl(k, std::forward<Args>(args)...);
142
+ }
143
+
144
+ template <class K = key_type, class... Args, K* = nullptr>
145
+ iterator try_emplace(const_iterator, key_arg<K>&& k,
146
+ Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
147
+ return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
148
+ }
149
+
150
+ template <class K = key_type, class... Args>
151
+ iterator try_emplace(const_iterator, const key_arg<K>& k,
152
+ Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
153
+ return try_emplace(k, std::forward<Args>(args)...).first;
154
+ }
155
+
156
+ template <class K = key_type, class P = Policy>
157
+ MappedReference<P> at(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
158
+ auto it = this->find(key);
159
+ if (it == this->end()) {
160
+ base_internal::ThrowStdOutOfRange(
161
+ "absl::container_internal::raw_hash_map<>::at");
162
+ }
163
+ return Policy::value(&*it);
164
+ }
165
+
166
+ template <class K = key_type, class P = Policy>
167
+ MappedConstReference<P> at(const key_arg<K>& key) const
168
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
169
+ auto it = this->find(key);
170
+ if (it == this->end()) {
171
+ base_internal::ThrowStdOutOfRange(
172
+ "absl::container_internal::raw_hash_map<>::at");
173
+ }
174
+ return Policy::value(&*it);
175
+ }
176
+
177
+ template <class K = key_type, class P = Policy, K* = nullptr>
178
+ MappedReference<P> operator[](key_arg<K>&& key)
179
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
180
+ // It is safe to use unchecked_deref here because try_emplace
181
+ // will always return an iterator pointing to a valid item in the table,
182
+ // since it inserts if nothing is found for the given key.
183
+ return Policy::value(
184
+ &this->unchecked_deref(try_emplace(std::forward<K>(key)).first));
185
+ }
186
+
187
+ template <class K = key_type, class P = Policy>
188
+ MappedReference<P> operator[](const key_arg<K>& key)
189
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
190
+ // It is safe to use unchecked_deref here because try_emplace
191
+ // will always return an iterator pointing to a valid item in the table,
192
+ // since it inserts if nothing is found for the given key.
193
+ return Policy::value(&this->unchecked_deref(try_emplace(key).first));
194
+ }
195
+
196
+ private:
197
+ template <class K, class V>
198
+ std::pair<iterator, bool> insert_or_assign_impl(K&& k, V&& v)
199
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
200
+ auto res = this->find_or_prepare_insert(k);
201
+ if (res.second)
202
+ this->emplace_at(res.first, std::forward<K>(k), std::forward<V>(v));
203
+ else
204
+ Policy::value(&*this->iterator_at(res.first)) = std::forward<V>(v);
205
+ return {this->iterator_at(res.first), res.second};
206
+ }
207
+
208
+ template <class K = key_type, class... Args>
209
+ std::pair<iterator, bool> try_emplace_impl(K&& k, Args&&... args)
210
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
211
+ auto res = this->find_or_prepare_insert(k);
212
+ if (res.second)
213
+ this->emplace_at(res.first, std::piecewise_construct,
214
+ std::forward_as_tuple(std::forward<K>(k)),
215
+ std::forward_as_tuple(std::forward<Args>(args)...));
216
+ return {this->iterator_at(res.first), res.second};
217
+ }
218
+ };
219
+
220
+ } // namespace container_internal
221
+ ABSL_NAMESPACE_END
222
+ } // namespace absl
223
+
224
+ #endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
weight/_dep/abseil-cpp/absl/container/internal/raw_hash_set.cc ADDED
@@ -0,0 +1,380 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/container/internal/raw_hash_set.h"
16
+
17
+ #include <atomic>
18
+ #include <cassert>
19
+ #include <cstddef>
20
+ #include <cstdint>
21
+ #include <cstring>
22
+
23
+ #include "absl/base/attributes.h"
24
+ #include "absl/base/config.h"
25
+ #include "absl/base/dynamic_annotations.h"
26
+ #include "absl/container/internal/container_memory.h"
27
+ #include "absl/hash/hash.h"
28
+
29
+ namespace absl {
30
+ ABSL_NAMESPACE_BEGIN
31
+ namespace container_internal {
32
+
33
+ // We have space for `growth_left` before a single block of control bytes. A
34
+ // single block of empty control bytes for tables without any slots allocated.
35
+ // This enables removing a branch in the hot path of find(). In order to ensure
36
+ // that the control bytes are aligned to 16, we have 16 bytes before the control
37
+ // bytes even though growth_left only needs 8.
38
+ constexpr ctrl_t ZeroCtrlT() { return static_cast<ctrl_t>(0); }
39
+ alignas(16) ABSL_CONST_INIT ABSL_DLL const ctrl_t kEmptyGroup[32] = {
40
+ ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
41
+ ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
42
+ ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
43
+ ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
44
+ ctrl_t::kSentinel, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
45
+ ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
46
+ ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
47
+ ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty};
48
+
49
+ #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
50
+ constexpr size_t Group::kWidth;
51
+ #endif
52
+
53
+ namespace {
54
+
55
+ // Returns "random" seed.
56
+ inline size_t RandomSeed() {
57
+ #ifdef ABSL_HAVE_THREAD_LOCAL
58
+ static thread_local size_t counter = 0;
59
+ // On Linux kernels >= 5.4 the MSAN runtime has a false-positive when
60
+ // accessing thread local storage data from loaded libraries
61
+ // (https://github.com/google/sanitizers/issues/1265), for this reason counter
62
+ // needs to be annotated as initialized.
63
+ ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(&counter, sizeof(size_t));
64
+ size_t value = ++counter;
65
+ #else // ABSL_HAVE_THREAD_LOCAL
66
+ static std::atomic<size_t> counter(0);
67
+ size_t value = counter.fetch_add(1, std::memory_order_relaxed);
68
+ #endif // ABSL_HAVE_THREAD_LOCAL
69
+ return value ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(&counter));
70
+ }
71
+
72
+ bool ShouldRehashForBugDetection(const ctrl_t* ctrl, size_t capacity) {
73
+ // Note: we can't use the abseil-random library because abseil-random
74
+ // depends on swisstable. We want to return true with probability
75
+ // `min(1, RehashProbabilityConstant() / capacity())`. In order to do this,
76
+ // we probe based on a random hash and see if the offset is less than
77
+ // RehashProbabilityConstant().
78
+ return probe(ctrl, capacity, absl::HashOf(RandomSeed())).offset() <
79
+ RehashProbabilityConstant();
80
+ }
81
+
82
+ } // namespace
83
+
84
+ GenerationType* EmptyGeneration() {
85
+ if (SwisstableGenerationsEnabled()) {
86
+ constexpr size_t kNumEmptyGenerations = 1024;
87
+ static constexpr GenerationType kEmptyGenerations[kNumEmptyGenerations]{};
88
+ return const_cast<GenerationType*>(
89
+ &kEmptyGenerations[RandomSeed() % kNumEmptyGenerations]);
90
+ }
91
+ return nullptr;
92
+ }
93
+
94
+ bool CommonFieldsGenerationInfoEnabled::
95
+ should_rehash_for_bug_detection_on_insert(const ctrl_t* ctrl,
96
+ size_t capacity) const {
97
+ if (reserved_growth_ == kReservedGrowthJustRanOut) return true;
98
+ if (reserved_growth_ > 0) return false;
99
+ return ShouldRehashForBugDetection(ctrl, capacity);
100
+ }
101
+
102
+ bool CommonFieldsGenerationInfoEnabled::should_rehash_for_bug_detection_on_move(
103
+ const ctrl_t* ctrl, size_t capacity) const {
104
+ return ShouldRehashForBugDetection(ctrl, capacity);
105
+ }
106
+
107
+ bool ShouldInsertBackwards(size_t hash, const ctrl_t* ctrl) {
108
+ // To avoid problems with weak hashes and single bit tests, we use % 13.
109
+ // TODO(kfm,sbenza): revisit after we do unconditional mixing
110
+ return (H1(hash, ctrl) ^ RandomSeed()) % 13 > 6;
111
+ }
112
+
113
+ void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity) {
114
+ assert(ctrl[capacity] == ctrl_t::kSentinel);
115
+ assert(IsValidCapacity(capacity));
116
+ for (ctrl_t* pos = ctrl; pos < ctrl + capacity; pos += Group::kWidth) {
117
+ Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
118
+ }
119
+ // Copy the cloned ctrl bytes.
120
+ std::memcpy(ctrl + capacity + 1, ctrl, NumClonedBytes());
121
+ ctrl[capacity] = ctrl_t::kSentinel;
122
+ }
123
+ // Extern template instantiation for inline function.
124
+ template FindInfo find_first_non_full(const CommonFields&, size_t);
125
+
126
+ FindInfo find_first_non_full_outofline(const CommonFields& common,
127
+ size_t hash) {
128
+ return find_first_non_full(common, hash);
129
+ }
130
+
131
+ // Returns the address of the slot just after slot assuming each slot has the
132
+ // specified size.
133
+ static inline void* NextSlot(void* slot, size_t slot_size) {
134
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) + slot_size);
135
+ }
136
+
137
+ // Returns the address of the slot just before slot assuming each slot has the
138
+ // specified size.
139
+ static inline void* PrevSlot(void* slot, size_t slot_size) {
140
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) - slot_size);
141
+ }
142
+
143
+ void DropDeletesWithoutResize(CommonFields& common,
144
+ const PolicyFunctions& policy, void* tmp_space) {
145
+ void* set = &common;
146
+ void* slot_array = common.slot_array();
147
+ const size_t capacity = common.capacity();
148
+ assert(IsValidCapacity(capacity));
149
+ assert(!is_small(capacity));
150
+ // Algorithm:
151
+ // - mark all DELETED slots as EMPTY
152
+ // - mark all FULL slots as DELETED
153
+ // - for each slot marked as DELETED
154
+ // hash = Hash(element)
155
+ // target = find_first_non_full(hash)
156
+ // if target is in the same group
157
+ // mark slot as FULL
158
+ // else if target is EMPTY
159
+ // transfer element to target
160
+ // mark slot as EMPTY
161
+ // mark target as FULL
162
+ // else if target is DELETED
163
+ // swap current element with target element
164
+ // mark target as FULL
165
+ // repeat procedure for current slot with moved from element (target)
166
+ ctrl_t* ctrl = common.control();
167
+ ConvertDeletedToEmptyAndFullToDeleted(ctrl, capacity);
168
+ auto hasher = policy.hash_slot;
169
+ auto transfer = policy.transfer;
170
+ const size_t slot_size = policy.slot_size;
171
+
172
+ size_t total_probe_length = 0;
173
+ void* slot_ptr = SlotAddress(slot_array, 0, slot_size);
174
+ for (size_t i = 0; i != capacity;
175
+ ++i, slot_ptr = NextSlot(slot_ptr, slot_size)) {
176
+ assert(slot_ptr == SlotAddress(slot_array, i, slot_size));
177
+ if (!IsDeleted(ctrl[i])) continue;
178
+ const size_t hash = (*hasher)(set, slot_ptr);
179
+ const FindInfo target = find_first_non_full(common, hash);
180
+ const size_t new_i = target.offset;
181
+ total_probe_length += target.probe_length;
182
+
183
+ // Verify if the old and new i fall within the same group wrt the hash.
184
+ // If they do, we don't need to move the object as it falls already in the
185
+ // best probe we can.
186
+ const size_t probe_offset = probe(common, hash).offset();
187
+ const auto probe_index = [probe_offset, capacity](size_t pos) {
188
+ return ((pos - probe_offset) & capacity) / Group::kWidth;
189
+ };
190
+
191
+ // Element doesn't move.
192
+ if (ABSL_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) {
193
+ SetCtrl(common, i, H2(hash), slot_size);
194
+ continue;
195
+ }
196
+
197
+ void* new_slot_ptr = SlotAddress(slot_array, new_i, slot_size);
198
+ if (IsEmpty(ctrl[new_i])) {
199
+ // Transfer element to the empty spot.
200
+ // SetCtrl poisons/unpoisons the slots so we have to call it at the
201
+ // right time.
202
+ SetCtrl(common, new_i, H2(hash), slot_size);
203
+ (*transfer)(set, new_slot_ptr, slot_ptr);
204
+ SetCtrl(common, i, ctrl_t::kEmpty, slot_size);
205
+ } else {
206
+ assert(IsDeleted(ctrl[new_i]));
207
+ SetCtrl(common, new_i, H2(hash), slot_size);
208
+ // Until we are done rehashing, DELETED marks previously FULL slots.
209
+
210
+ // Swap i and new_i elements.
211
+ (*transfer)(set, tmp_space, new_slot_ptr);
212
+ (*transfer)(set, new_slot_ptr, slot_ptr);
213
+ (*transfer)(set, slot_ptr, tmp_space);
214
+
215
+ // repeat the processing of the ith slot
216
+ --i;
217
+ slot_ptr = PrevSlot(slot_ptr, slot_size);
218
+ }
219
+ }
220
+ ResetGrowthLeft(common);
221
+ common.infoz().RecordRehash(total_probe_length);
222
+ }
223
+
224
+ static bool WasNeverFull(CommonFields& c, size_t index) {
225
+ if (is_single_group(c.capacity())) {
226
+ return true;
227
+ }
228
+ const size_t index_before = (index - Group::kWidth) & c.capacity();
229
+ const auto empty_after = Group(c.control() + index).MaskEmpty();
230
+ const auto empty_before = Group(c.control() + index_before).MaskEmpty();
231
+
232
+ // We count how many consecutive non empties we have to the right and to the
233
+ // left of `it`. If the sum is >= kWidth then there is at least one probe
234
+ // window that might have seen a full group.
235
+ return empty_before && empty_after &&
236
+ static_cast<size_t>(empty_after.TrailingZeros()) +
237
+ empty_before.LeadingZeros() <
238
+ Group::kWidth;
239
+ }
240
+
241
+ void EraseMetaOnly(CommonFields& c, size_t index, size_t slot_size) {
242
+ assert(IsFull(c.control()[index]) && "erasing a dangling iterator");
243
+ c.decrement_size();
244
+ c.infoz().RecordErase();
245
+
246
+ if (WasNeverFull(c, index)) {
247
+ SetCtrl(c, index, ctrl_t::kEmpty, slot_size);
248
+ c.set_growth_left(c.growth_left() + 1);
249
+ return;
250
+ }
251
+
252
+ SetCtrl(c, index, ctrl_t::kDeleted, slot_size);
253
+ }
254
+
255
+ void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
256
+ bool reuse) {
257
+ c.set_size(0);
258
+ if (reuse) {
259
+ ResetCtrl(c, policy.slot_size);
260
+ ResetGrowthLeft(c);
261
+ c.infoz().RecordStorageChanged(0, c.capacity());
262
+ } else {
263
+ // We need to record infoz before calling dealloc, which will unregister
264
+ // infoz.
265
+ c.infoz().RecordClearedReservation();
266
+ c.infoz().RecordStorageChanged(0, 0);
267
+ (*policy.dealloc)(c, policy);
268
+ c.set_control(EmptyGroup());
269
+ c.set_generation_ptr(EmptyGeneration());
270
+ c.set_slots(nullptr);
271
+ c.set_capacity(0);
272
+ }
273
+ }
274
+
275
+ void HashSetResizeHelper::GrowIntoSingleGroupShuffleControlBytes(
276
+ ctrl_t* new_ctrl, size_t new_capacity) const {
277
+ assert(is_single_group(new_capacity));
278
+ constexpr size_t kHalfWidth = Group::kWidth / 2;
279
+ assert(old_capacity_ < kHalfWidth);
280
+
281
+ const size_t half_old_capacity = old_capacity_ / 2;
282
+
283
+ // NOTE: operations are done with compile time known size = kHalfWidth.
284
+ // Compiler optimizes that into single ASM operation.
285
+
286
+ // Copy second half of bytes to the beginning.
287
+ // We potentially copy more bytes in order to have compile time known size.
288
+ // Mirrored bytes from the old_ctrl_ will also be copied.
289
+ // In case of old_capacity_ == 3, we will copy 1st element twice.
290
+ // Examples:
291
+ // old_ctrl = 0S0EEEEEEE...
292
+ // new_ctrl = S0EEEEEEEE...
293
+ //
294
+ // old_ctrl = 01S01EEEEE...
295
+ // new_ctrl = 1S01EEEEEE...
296
+ //
297
+ // old_ctrl = 0123456S0123456EE...
298
+ // new_ctrl = 456S0123?????????...
299
+ std::memcpy(new_ctrl, old_ctrl_ + half_old_capacity + 1, kHalfWidth);
300
+ // Clean up copied kSentinel from old_ctrl.
301
+ new_ctrl[half_old_capacity] = ctrl_t::kEmpty;
302
+
303
+ // Clean up damaged or uninitialized bytes.
304
+
305
+ // Clean bytes after the intended size of the copy.
306
+ // Example:
307
+ // new_ctrl = 1E01EEEEEEE????
308
+ // *new_ctrl= 1E0EEEEEEEE????
309
+ // position /
310
+ std::memset(new_ctrl + old_capacity_ + 1, static_cast<int8_t>(ctrl_t::kEmpty),
311
+ kHalfWidth);
312
+ // Clean non-mirrored bytes that are not initialized.
313
+ // For small old_capacity that may be inside of mirrored bytes zone.
314
+ // Examples:
315
+ // new_ctrl = 1E0EEEEEEEE??????????....
316
+ // *new_ctrl= 1E0EEEEEEEEEEEEE?????....
317
+ // position /
318
+ //
319
+ // new_ctrl = 456E0123???????????...
320
+ // *new_ctrl= 456E0123EEEEEEEE???...
321
+ // position /
322
+ std::memset(new_ctrl + kHalfWidth, static_cast<int8_t>(ctrl_t::kEmpty),
323
+ kHalfWidth);
324
+ // Clean last mirrored bytes that are not initialized
325
+ // and will not be overwritten by mirroring.
326
+ // Examples:
327
+ // new_ctrl = 1E0EEEEEEEEEEEEE????????
328
+ // *new_ctrl= 1E0EEEEEEEEEEEEEEEEEEEEE
329
+ // position S /
330
+ //
331
+ // new_ctrl = 456E0123EEEEEEEE???????????????
332
+ // *new_ctrl= 456E0123EEEEEEEE???????EEEEEEEE
333
+ // position S /
334
+ std::memset(new_ctrl + new_capacity + kHalfWidth,
335
+ static_cast<int8_t>(ctrl_t::kEmpty), kHalfWidth);
336
+
337
+ // Create mirrored bytes. old_capacity_ < kHalfWidth
338
+ // Example:
339
+ // new_ctrl = 456E0123EEEEEEEE???????EEEEEEEE
340
+ // *new_ctrl= 456E0123EEEEEEEE456E0123EEEEEEE
341
+ // position S/
342
+ ctrl_t g[kHalfWidth];
343
+ std::memcpy(g, new_ctrl, kHalfWidth);
344
+ std::memcpy(new_ctrl + new_capacity + 1, g, kHalfWidth);
345
+
346
+ // Finally set sentinel to its place.
347
+ new_ctrl[new_capacity] = ctrl_t::kSentinel;
348
+ }
349
+
350
+ void HashSetResizeHelper::GrowIntoSingleGroupShuffleTransferableSlots(
351
+ void* old_slots, void* new_slots, size_t slot_size) const {
352
+ assert(old_capacity_ > 0);
353
+ const size_t half_old_capacity = old_capacity_ / 2;
354
+
355
+ SanitizerUnpoisonMemoryRegion(old_slots, slot_size * old_capacity_);
356
+ std::memcpy(new_slots,
357
+ SlotAddress(old_slots, half_old_capacity + 1, slot_size),
358
+ slot_size * half_old_capacity);
359
+ std::memcpy(SlotAddress(new_slots, half_old_capacity + 1, slot_size),
360
+ old_slots, slot_size * (half_old_capacity + 1));
361
+ }
362
+
363
+ void HashSetResizeHelper::GrowSizeIntoSingleGroupTransferable(
364
+ CommonFields& c, void* old_slots, size_t slot_size) {
365
+ assert(old_capacity_ < Group::kWidth / 2);
366
+ assert(is_single_group(c.capacity()));
367
+ assert(IsGrowingIntoSingleGroupApplicable(old_capacity_, c.capacity()));
368
+
369
+ GrowIntoSingleGroupShuffleControlBytes(c.control(), c.capacity());
370
+ GrowIntoSingleGroupShuffleTransferableSlots(old_slots, c.slot_array(),
371
+ slot_size);
372
+
373
+ // We poison since GrowIntoSingleGroupShuffleTransferableSlots
374
+ // may leave empty slots unpoisoned.
375
+ PoisonSingleGroupEmptySlots(c, slot_size);
376
+ }
377
+
378
+ } // namespace container_internal
379
+ ABSL_NAMESPACE_END
380
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/raw_hash_set.h ADDED
The diff for this file is too large to render. See raw diff
 
weight/_dep/abseil-cpp/absl/container/internal/raw_hash_set_test.cc ADDED
@@ -0,0 +1,2684 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/container/internal/raw_hash_set.h"
16
+
17
+ #include <algorithm>
18
+ #include <atomic>
19
+ #include <cmath>
20
+ #include <cstddef>
21
+ #include <cstdint>
22
+ #include <deque>
23
+ #include <functional>
24
+ #include <iostream>
25
+ #include <iterator>
26
+ #include <list>
27
+ #include <map>
28
+ #include <memory>
29
+ #include <numeric>
30
+ #include <ostream>
31
+ #include <random>
32
+ #include <string>
33
+ #include <tuple>
34
+ #include <type_traits>
35
+ #include <unordered_map>
36
+ #include <unordered_set>
37
+ #include <utility>
38
+ #include <vector>
39
+
40
+ #include "gmock/gmock.h"
41
+ #include "gtest/gtest.h"
42
+ #include "absl/base/attributes.h"
43
+ #include "absl/base/config.h"
44
+ #include "absl/base/internal/cycleclock.h"
45
+ #include "absl/base/prefetch.h"
46
+ #include "absl/container/flat_hash_map.h"
47
+ #include "absl/container/flat_hash_set.h"
48
+ #include "absl/container/internal/container_memory.h"
49
+ #include "absl/container/internal/hash_function_defaults.h"
50
+ #include "absl/container/internal/hash_policy_testing.h"
51
+ #include "absl/container/internal/hashtable_debug.h"
52
+ #include "absl/container/internal/hashtablez_sampler.h"
53
+ #include "absl/container/internal/test_allocator.h"
54
+ #include "absl/hash/hash.h"
55
+ #include "absl/log/log.h"
56
+ #include "absl/memory/memory.h"
57
+ #include "absl/meta/type_traits.h"
58
+ #include "absl/strings/string_view.h"
59
+
60
+ namespace absl {
61
+ ABSL_NAMESPACE_BEGIN
62
+ namespace container_internal {
63
+
64
+ struct RawHashSetTestOnlyAccess {
65
+ template <typename C>
66
+ static auto GetSlots(const C& c) -> decltype(c.slot_array()) {
67
+ return c.slot_array();
68
+ }
69
+ template <typename C>
70
+ static size_t CountTombstones(const C& c) {
71
+ return c.common().TombstonesCount();
72
+ }
73
+ };
74
+
75
+ namespace {
76
+
77
+ using ::testing::ElementsAre;
78
+ using ::testing::Eq;
79
+ using ::testing::Ge;
80
+ using ::testing::Lt;
81
+ using ::testing::Pair;
82
+ using ::testing::UnorderedElementsAre;
83
+
84
+ // Convenience function to static cast to ctrl_t.
85
+ ctrl_t CtrlT(int i) { return static_cast<ctrl_t>(i); }
86
+
87
+ TEST(Util, NormalizeCapacity) {
88
+ EXPECT_EQ(1, NormalizeCapacity(0));
89
+ EXPECT_EQ(1, NormalizeCapacity(1));
90
+ EXPECT_EQ(3, NormalizeCapacity(2));
91
+ EXPECT_EQ(3, NormalizeCapacity(3));
92
+ EXPECT_EQ(7, NormalizeCapacity(4));
93
+ EXPECT_EQ(7, NormalizeCapacity(7));
94
+ EXPECT_EQ(15, NormalizeCapacity(8));
95
+ EXPECT_EQ(15, NormalizeCapacity(15));
96
+ EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 1));
97
+ EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 2));
98
+ }
99
+
100
+ TEST(Util, GrowthAndCapacity) {
101
+ // Verify that GrowthToCapacity gives the minimum capacity that has enough
102
+ // growth.
103
+ for (size_t growth = 0; growth < 10000; ++growth) {
104
+ SCOPED_TRACE(growth);
105
+ size_t capacity = NormalizeCapacity(GrowthToLowerboundCapacity(growth));
106
+ // The capacity is large enough for `growth`.
107
+ EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth));
108
+ // For (capacity+1) < kWidth, growth should equal capacity.
109
+ if (capacity + 1 < Group::kWidth) {
110
+ EXPECT_THAT(CapacityToGrowth(capacity), Eq(capacity));
111
+ } else {
112
+ EXPECT_THAT(CapacityToGrowth(capacity), Lt(capacity));
113
+ }
114
+ if (growth != 0 && capacity > 1) {
115
+ // There is no smaller capacity that works.
116
+ EXPECT_THAT(CapacityToGrowth(capacity / 2), Lt(growth));
117
+ }
118
+ }
119
+
120
+ for (size_t capacity = Group::kWidth - 1; capacity < 10000;
121
+ capacity = 2 * capacity + 1) {
122
+ SCOPED_TRACE(capacity);
123
+ size_t growth = CapacityToGrowth(capacity);
124
+ EXPECT_THAT(growth, Lt(capacity));
125
+ EXPECT_LE(GrowthToLowerboundCapacity(growth), capacity);
126
+ EXPECT_EQ(NormalizeCapacity(GrowthToLowerboundCapacity(growth)), capacity);
127
+ }
128
+ }
129
+
130
+ TEST(Util, probe_seq) {
131
+ probe_seq<16> seq(0, 127);
132
+ auto gen = [&]() {
133
+ size_t res = seq.offset();
134
+ seq.next();
135
+ return res;
136
+ };
137
+ std::vector<size_t> offsets(8);
138
+ std::generate_n(offsets.begin(), 8, gen);
139
+ EXPECT_THAT(offsets, ElementsAre(0, 16, 48, 96, 32, 112, 80, 64));
140
+ seq = probe_seq<16>(128, 127);
141
+ std::generate_n(offsets.begin(), 8, gen);
142
+ EXPECT_THAT(offsets, ElementsAre(0, 16, 48, 96, 32, 112, 80, 64));
143
+ }
144
+
145
+ TEST(BitMask, Smoke) {
146
+ EXPECT_FALSE((BitMask<uint8_t, 8>(0)));
147
+ EXPECT_TRUE((BitMask<uint8_t, 8>(5)));
148
+
149
+ EXPECT_THAT((BitMask<uint8_t, 8>(0)), ElementsAre());
150
+ EXPECT_THAT((BitMask<uint8_t, 8>(0x1)), ElementsAre(0));
151
+ EXPECT_THAT((BitMask<uint8_t, 8>(0x2)), ElementsAre(1));
152
+ EXPECT_THAT((BitMask<uint8_t, 8>(0x3)), ElementsAre(0, 1));
153
+ EXPECT_THAT((BitMask<uint8_t, 8>(0x4)), ElementsAre(2));
154
+ EXPECT_THAT((BitMask<uint8_t, 8>(0x5)), ElementsAre(0, 2));
155
+ EXPECT_THAT((BitMask<uint8_t, 8>(0x55)), ElementsAre(0, 2, 4, 6));
156
+ EXPECT_THAT((BitMask<uint8_t, 8>(0xAA)), ElementsAre(1, 3, 5, 7));
157
+ }
158
+
159
+ TEST(BitMask, WithShift) {
160
+ // See the non-SSE version of Group for details on what this math is for.
161
+ uint64_t ctrl = 0x1716151413121110;
162
+ uint64_t hash = 0x12;
163
+ constexpr uint64_t msbs = 0x8080808080808080ULL;
164
+ constexpr uint64_t lsbs = 0x0101010101010101ULL;
165
+ auto x = ctrl ^ (lsbs * hash);
166
+ uint64_t mask = (x - lsbs) & ~x & msbs;
167
+ EXPECT_EQ(0x0000000080800000, mask);
168
+
169
+ BitMask<uint64_t, 8, 3> b(mask);
170
+ EXPECT_EQ(*b, 2);
171
+ }
172
+
173
+ TEST(BitMask, LeadingTrailing) {
174
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).LeadingZeros()), 3);
175
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).TrailingZeros()), 6);
176
+
177
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).LeadingZeros()), 15);
178
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).TrailingZeros()), 0);
179
+
180
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).LeadingZeros()), 0);
181
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).TrailingZeros()), 15);
182
+
183
+ EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).LeadingZeros()), 3);
184
+ EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).TrailingZeros()), 1);
185
+
186
+ EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000000000000080).LeadingZeros()), 7);
187
+ EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000000000000080).TrailingZeros()), 0);
188
+
189
+ EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x8000000000000000).LeadingZeros()), 0);
190
+ EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x8000000000000000).TrailingZeros()), 7);
191
+ }
192
+
193
+ TEST(Group, EmptyGroup) {
194
+ for (h2_t h = 0; h != 128; ++h) EXPECT_FALSE(Group{EmptyGroup()}.Match(h));
195
+ }
196
+
197
+ TEST(Group, Match) {
198
+ if (Group::kWidth == 16) {
199
+ ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3),
200
+ ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
201
+ CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1),
202
+ CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)};
203
+ EXPECT_THAT(Group{group}.Match(0), ElementsAre());
204
+ EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15));
205
+ EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10));
206
+ EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9));
207
+ EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8));
208
+ } else if (Group::kWidth == 8) {
209
+ ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2),
210
+ ctrl_t::kDeleted, CtrlT(2), CtrlT(1),
211
+ ctrl_t::kSentinel, CtrlT(1)};
212
+ EXPECT_THAT(Group{group}.Match(0), ElementsAre());
213
+ EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7));
214
+ EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4));
215
+ } else {
216
+ FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
217
+ }
218
+ }
219
+
220
+ TEST(Group, MaskEmpty) {
221
+ if (Group::kWidth == 16) {
222
+ ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3),
223
+ ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
224
+ CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1),
225
+ CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)};
226
+ EXPECT_THAT(Group{group}.MaskEmpty().LowestBitSet(), 0);
227
+ EXPECT_THAT(Group{group}.MaskEmpty().HighestBitSet(), 4);
228
+ } else if (Group::kWidth == 8) {
229
+ ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2),
230
+ ctrl_t::kDeleted, CtrlT(2), CtrlT(1),
231
+ ctrl_t::kSentinel, CtrlT(1)};
232
+ EXPECT_THAT(Group{group}.MaskEmpty().LowestBitSet(), 0);
233
+ EXPECT_THAT(Group{group}.MaskEmpty().HighestBitSet(), 0);
234
+ } else {
235
+ FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
236
+ }
237
+ }
238
+
239
+ TEST(Group, MaskFull) {
240
+ if (Group::kWidth == 16) {
241
+ ctrl_t group[] = {
242
+ ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3),
243
+ ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
244
+ CtrlT(7), CtrlT(5), ctrl_t::kDeleted, CtrlT(1),
245
+ CtrlT(1), ctrl_t::kSentinel, ctrl_t::kEmpty, CtrlT(1)};
246
+ EXPECT_THAT(Group{group}.MaskFull(),
247
+ ElementsAre(1, 3, 5, 7, 8, 9, 11, 12, 15));
248
+ } else if (Group::kWidth == 8) {
249
+ ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kEmpty,
250
+ ctrl_t::kDeleted, CtrlT(2), ctrl_t::kSentinel,
251
+ ctrl_t::kSentinel, CtrlT(1)};
252
+ EXPECT_THAT(Group{group}.MaskFull(), ElementsAre(1, 4, 7));
253
+ } else {
254
+ FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
255
+ }
256
+ }
257
+
258
+ TEST(Group, MaskEmptyOrDeleted) {
259
+ if (Group::kWidth == 16) {
260
+ ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kEmpty, CtrlT(3),
261
+ ctrl_t::kDeleted, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
262
+ CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1),
263
+ CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)};
264
+ EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
265
+ EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().HighestBitSet(), 4);
266
+ } else if (Group::kWidth == 8) {
267
+ ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2),
268
+ ctrl_t::kDeleted, CtrlT(2), CtrlT(1),
269
+ ctrl_t::kSentinel, CtrlT(1)};
270
+ EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
271
+ EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().HighestBitSet(), 3);
272
+ } else {
273
+ FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
274
+ }
275
+ }
276
+
277
+ TEST(Batch, DropDeletes) {
278
+ constexpr size_t kCapacity = 63;
279
+ constexpr size_t kGroupWidth = container_internal::Group::kWidth;
280
+ std::vector<ctrl_t> ctrl(kCapacity + 1 + kGroupWidth);
281
+ ctrl[kCapacity] = ctrl_t::kSentinel;
282
+ std::vector<ctrl_t> pattern = {
283
+ ctrl_t::kEmpty, CtrlT(2), ctrl_t::kDeleted, CtrlT(2),
284
+ ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted};
285
+ for (size_t i = 0; i != kCapacity; ++i) {
286
+ ctrl[i] = pattern[i % pattern.size()];
287
+ if (i < kGroupWidth - 1)
288
+ ctrl[i + kCapacity + 1] = pattern[i % pattern.size()];
289
+ }
290
+ ConvertDeletedToEmptyAndFullToDeleted(ctrl.data(), kCapacity);
291
+ ASSERT_EQ(ctrl[kCapacity], ctrl_t::kSentinel);
292
+ for (size_t i = 0; i < kCapacity + kGroupWidth; ++i) {
293
+ ctrl_t expected = pattern[i % (kCapacity + 1) % pattern.size()];
294
+ if (i == kCapacity) expected = ctrl_t::kSentinel;
295
+ if (expected == ctrl_t::kDeleted) expected = ctrl_t::kEmpty;
296
+ if (IsFull(expected)) expected = ctrl_t::kDeleted;
297
+ EXPECT_EQ(ctrl[i], expected)
298
+ << i << " " << static_cast<int>(pattern[i % pattern.size()]);
299
+ }
300
+ }
301
+
302
+ TEST(Group, CountLeadingEmptyOrDeleted) {
303
+ const std::vector<ctrl_t> empty_examples = {ctrl_t::kEmpty, ctrl_t::kDeleted};
304
+ const std::vector<ctrl_t> full_examples = {
305
+ CtrlT(0), CtrlT(1), CtrlT(2), CtrlT(3),
306
+ CtrlT(5), CtrlT(9), CtrlT(127), ctrl_t::kSentinel};
307
+
308
+ for (ctrl_t empty : empty_examples) {
309
+ std::vector<ctrl_t> e(Group::kWidth, empty);
310
+ EXPECT_EQ(Group::kWidth, Group{e.data()}.CountLeadingEmptyOrDeleted());
311
+ for (ctrl_t full : full_examples) {
312
+ for (size_t i = 0; i != Group::kWidth; ++i) {
313
+ std::vector<ctrl_t> f(Group::kWidth, empty);
314
+ f[i] = full;
315
+ EXPECT_EQ(i, Group{f.data()}.CountLeadingEmptyOrDeleted());
316
+ }
317
+ std::vector<ctrl_t> f(Group::kWidth, empty);
318
+ f[Group::kWidth * 2 / 3] = full;
319
+ f[Group::kWidth / 2] = full;
320
+ EXPECT_EQ(Group::kWidth / 2,
321
+ Group{f.data()}.CountLeadingEmptyOrDeleted());
322
+ }
323
+ }
324
+ }
325
+
326
+ template <class T, bool kTransferable = false>
327
+ struct ValuePolicy {
328
+ using slot_type = T;
329
+ using key_type = T;
330
+ using init_type = T;
331
+
332
+ template <class Allocator, class... Args>
333
+ static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
334
+ absl::allocator_traits<Allocator>::construct(*alloc, slot,
335
+ std::forward<Args>(args)...);
336
+ }
337
+
338
+ template <class Allocator>
339
+ static void destroy(Allocator* alloc, slot_type* slot) {
340
+ absl::allocator_traits<Allocator>::destroy(*alloc, slot);
341
+ }
342
+
343
+ template <class Allocator>
344
+ static std::integral_constant<bool, kTransferable> transfer(
345
+ Allocator* alloc, slot_type* new_slot, slot_type* old_slot) {
346
+ construct(alloc, new_slot, std::move(*old_slot));
347
+ destroy(alloc, old_slot);
348
+ return {};
349
+ }
350
+
351
+ static T& element(slot_type* slot) { return *slot; }
352
+
353
+ template <class F, class... Args>
354
+ static decltype(absl::container_internal::DecomposeValue(
355
+ std::declval<F>(), std::declval<Args>()...))
356
+ apply(F&& f, Args&&... args) {
357
+ return absl::container_internal::DecomposeValue(
358
+ std::forward<F>(f), std::forward<Args>(args)...);
359
+ }
360
+ };
361
+
362
+ using IntPolicy = ValuePolicy<int64_t>;
363
+ using Uint8Policy = ValuePolicy<uint8_t>;
364
+
365
+ using TranferableIntPolicy = ValuePolicy<int64_t, /*kTransferable=*/true>;
366
+
367
+ class StringPolicy {
368
+ template <class F, class K, class V,
369
+ class = typename std::enable_if<
370
+ std::is_convertible<const K&, absl::string_view>::value>::type>
371
+ decltype(std::declval<F>()(
372
+ std::declval<const absl::string_view&>(), std::piecewise_construct,
373
+ std::declval<std::tuple<K>>(),
374
+ std::declval<V>())) static apply_impl(F&& f,
375
+ std::pair<std::tuple<K>, V> p) {
376
+ const absl::string_view& key = std::get<0>(p.first);
377
+ return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first),
378
+ std::move(p.second));
379
+ }
380
+
381
+ public:
382
+ struct slot_type {
383
+ struct ctor {};
384
+
385
+ template <class... Ts>
386
+ explicit slot_type(ctor, Ts&&... ts) : pair(std::forward<Ts>(ts)...) {}
387
+
388
+ std::pair<std::string, std::string> pair;
389
+ };
390
+
391
+ using key_type = std::string;
392
+ using init_type = std::pair<std::string, std::string>;
393
+
394
+ template <class allocator_type, class... Args>
395
+ static void construct(allocator_type* alloc, slot_type* slot, Args... args) {
396
+ std::allocator_traits<allocator_type>::construct(
397
+ *alloc, slot, typename slot_type::ctor(), std::forward<Args>(args)...);
398
+ }
399
+
400
+ template <class allocator_type>
401
+ static void destroy(allocator_type* alloc, slot_type* slot) {
402
+ std::allocator_traits<allocator_type>::destroy(*alloc, slot);
403
+ }
404
+
405
+ template <class allocator_type>
406
+ static void transfer(allocator_type* alloc, slot_type* new_slot,
407
+ slot_type* old_slot) {
408
+ construct(alloc, new_slot, std::move(old_slot->pair));
409
+ destroy(alloc, old_slot);
410
+ }
411
+
412
+ static std::pair<std::string, std::string>& element(slot_type* slot) {
413
+ return slot->pair;
414
+ }
415
+
416
+ template <class F, class... Args>
417
+ static auto apply(F&& f, Args&&... args)
418
+ -> decltype(apply_impl(std::forward<F>(f),
419
+ PairArgs(std::forward<Args>(args)...))) {
420
+ return apply_impl(std::forward<F>(f),
421
+ PairArgs(std::forward<Args>(args)...));
422
+ }
423
+ };
424
+
425
+ struct StringHash : absl::Hash<absl::string_view> {
426
+ using is_transparent = void;
427
+ };
428
+ struct StringEq : std::equal_to<absl::string_view> {
429
+ using is_transparent = void;
430
+ };
431
+
432
+ struct StringTable
433
+ : raw_hash_set<StringPolicy, StringHash, StringEq, std::allocator<int>> {
434
+ using Base = typename StringTable::raw_hash_set;
435
+ StringTable() = default;
436
+ using Base::Base;
437
+ };
438
+
439
+ template <typename T, bool kTransferable = false>
440
+ struct ValueTable
441
+ : raw_hash_set<ValuePolicy<T, kTransferable>, hash_default_hash<T>,
442
+ std::equal_to<T>, std::allocator<T>> {
443
+ using Base = typename ValueTable::raw_hash_set;
444
+ using Base::Base;
445
+ };
446
+
447
+ using IntTable = ValueTable<int64_t>;
448
+ using Uint8Table = ValueTable<uint8_t>;
449
+
450
+ using TransferableIntTable = ValueTable<int64_t, /*kTransferable=*/true>;
451
+
452
+ template <typename T>
453
+ struct CustomAlloc : std::allocator<T> {
454
+ CustomAlloc() = default;
455
+
456
+ template <typename U>
457
+ explicit CustomAlloc(const CustomAlloc<U>& /*other*/) {}
458
+
459
+ template <class U>
460
+ struct rebind {
461
+ using other = CustomAlloc<U>;
462
+ };
463
+ };
464
+
465
+ struct CustomAllocIntTable
466
+ : raw_hash_set<IntPolicy, hash_default_hash<int64_t>,
467
+ std::equal_to<int64_t>, CustomAlloc<int64_t>> {
468
+ using Base = typename CustomAllocIntTable::raw_hash_set;
469
+ using Base::Base;
470
+ };
471
+
472
+ struct MinimumAlignmentUint8Table
473
+ : raw_hash_set<Uint8Policy, hash_default_hash<uint8_t>,
474
+ std::equal_to<uint8_t>, MinimumAlignmentAlloc<uint8_t>> {
475
+ using Base = typename MinimumAlignmentUint8Table::raw_hash_set;
476
+ using Base::Base;
477
+ };
478
+
479
+ // Allows for freezing the allocator to expect no further allocations.
480
+ template <typename T>
481
+ struct FreezableAlloc : std::allocator<T> {
482
+ explicit FreezableAlloc(bool* f) : frozen(f) {}
483
+
484
+ template <typename U>
485
+ explicit FreezableAlloc(const FreezableAlloc<U>& other)
486
+ : frozen(other.frozen) {}
487
+
488
+ template <class U>
489
+ struct rebind {
490
+ using other = FreezableAlloc<U>;
491
+ };
492
+
493
+ T* allocate(size_t n) {
494
+ EXPECT_FALSE(*frozen);
495
+ return std::allocator<T>::allocate(n);
496
+ }
497
+
498
+ bool* frozen;
499
+ };
500
+
501
+ struct BadFastHash {
502
+ template <class T>
503
+ size_t operator()(const T&) const {
504
+ return 0;
505
+ }
506
+ };
507
+
508
+ struct BadHashFreezableIntTable
509
+ : raw_hash_set<IntPolicy, BadFastHash, std::equal_to<int64_t>,
510
+ FreezableAlloc<int64_t>> {
511
+ using Base = typename BadHashFreezableIntTable::raw_hash_set;
512
+ using Base::Base;
513
+ };
514
+
515
+ struct BadTable : raw_hash_set<IntPolicy, BadFastHash, std::equal_to<int>,
516
+ std::allocator<int>> {
517
+ using Base = typename BadTable::raw_hash_set;
518
+ BadTable() = default;
519
+ using Base::Base;
520
+ };
521
+
522
+ TEST(Table, EmptyFunctorOptimization) {
523
+ static_assert(std::is_empty<std::equal_to<absl::string_view>>::value, "");
524
+ static_assert(std::is_empty<std::allocator<int>>::value, "");
525
+
526
+ struct MockTable {
527
+ void* ctrl;
528
+ void* slots;
529
+ size_t size;
530
+ size_t capacity;
531
+ };
532
+ struct StatelessHash {
533
+ size_t operator()(absl::string_view) const { return 0; }
534
+ };
535
+ struct StatefulHash : StatelessHash {
536
+ size_t dummy;
537
+ };
538
+
539
+ struct GenerationData {
540
+ size_t reserved_growth;
541
+ size_t reservation_size;
542
+ GenerationType* generation;
543
+ };
544
+
545
+ // Ignore unreachable-code warning. Compiler thinks one branch of each ternary
546
+ // conditional is unreachable.
547
+ #if defined(__clang__)
548
+ #pragma clang diagnostic push
549
+ #pragma clang diagnostic ignored "-Wunreachable-code"
550
+ #endif
551
+ constexpr size_t mock_size = sizeof(MockTable);
552
+ constexpr size_t generation_size =
553
+ SwisstableGenerationsEnabled() ? sizeof(GenerationData) : 0;
554
+ #if defined(__clang__)
555
+ #pragma clang diagnostic pop
556
+ #endif
557
+
558
+ EXPECT_EQ(
559
+ mock_size + generation_size,
560
+ sizeof(
561
+ raw_hash_set<StringPolicy, StatelessHash,
562
+ std::equal_to<absl::string_view>, std::allocator<int>>));
563
+
564
+ EXPECT_EQ(
565
+ mock_size + sizeof(StatefulHash) + generation_size,
566
+ sizeof(
567
+ raw_hash_set<StringPolicy, StatefulHash,
568
+ std::equal_to<absl::string_view>, std::allocator<int>>));
569
+ }
570
+
571
+ TEST(Table, Empty) {
572
+ IntTable t;
573
+ EXPECT_EQ(0, t.size());
574
+ EXPECT_TRUE(t.empty());
575
+ }
576
+
577
+ TEST(Table, LookupEmpty) {
578
+ IntTable t;
579
+ auto it = t.find(0);
580
+ EXPECT_TRUE(it == t.end());
581
+ }
582
+
583
+ TEST(Table, Insert1) {
584
+ IntTable t;
585
+ EXPECT_TRUE(t.find(0) == t.end());
586
+ auto res = t.emplace(0);
587
+ EXPECT_TRUE(res.second);
588
+ EXPECT_THAT(*res.first, 0);
589
+ EXPECT_EQ(1, t.size());
590
+ EXPECT_THAT(*t.find(0), 0);
591
+ }
592
+
593
+ TEST(Table, Insert2) {
594
+ IntTable t;
595
+ EXPECT_TRUE(t.find(0) == t.end());
596
+ auto res = t.emplace(0);
597
+ EXPECT_TRUE(res.second);
598
+ EXPECT_THAT(*res.first, 0);
599
+ EXPECT_EQ(1, t.size());
600
+ EXPECT_TRUE(t.find(1) == t.end());
601
+ res = t.emplace(1);
602
+ EXPECT_TRUE(res.second);
603
+ EXPECT_THAT(*res.first, 1);
604
+ EXPECT_EQ(2, t.size());
605
+ EXPECT_THAT(*t.find(0), 0);
606
+ EXPECT_THAT(*t.find(1), 1);
607
+ }
608
+
609
+ TEST(Table, InsertCollision) {
610
+ BadTable t;
611
+ EXPECT_TRUE(t.find(1) == t.end());
612
+ auto res = t.emplace(1);
613
+ EXPECT_TRUE(res.second);
614
+ EXPECT_THAT(*res.first, 1);
615
+ EXPECT_EQ(1, t.size());
616
+
617
+ EXPECT_TRUE(t.find(2) == t.end());
618
+ res = t.emplace(2);
619
+ EXPECT_THAT(*res.first, 2);
620
+ EXPECT_TRUE(res.second);
621
+ EXPECT_EQ(2, t.size());
622
+
623
+ EXPECT_THAT(*t.find(1), 1);
624
+ EXPECT_THAT(*t.find(2), 2);
625
+ }
626
+
627
+ // Test that we do not add existent element in case we need to search through
628
+ // many groups with deleted elements
629
+ TEST(Table, InsertCollisionAndFindAfterDelete) {
630
+ BadTable t; // all elements go to the same group.
631
+ // Have at least 2 groups with Group::kWidth collisions
632
+ // plus some extra collisions in the last group.
633
+ constexpr size_t kNumInserts = Group::kWidth * 2 + 5;
634
+ for (size_t i = 0; i < kNumInserts; ++i) {
635
+ auto res = t.emplace(i);
636
+ EXPECT_TRUE(res.second);
637
+ EXPECT_THAT(*res.first, i);
638
+ EXPECT_EQ(i + 1, t.size());
639
+ }
640
+
641
+ // Remove elements one by one and check
642
+ // that we still can find all other elements.
643
+ for (size_t i = 0; i < kNumInserts; ++i) {
644
+ EXPECT_EQ(1, t.erase(i)) << i;
645
+ for (size_t j = i + 1; j < kNumInserts; ++j) {
646
+ EXPECT_THAT(*t.find(j), j);
647
+ auto res = t.emplace(j);
648
+ EXPECT_FALSE(res.second) << i << " " << j;
649
+ EXPECT_THAT(*res.first, j);
650
+ EXPECT_EQ(kNumInserts - i - 1, t.size());
651
+ }
652
+ }
653
+ EXPECT_TRUE(t.empty());
654
+ }
655
+
656
+ TEST(Table, EraseInSmallTables) {
657
+ for (int64_t size = 0; size < 64; ++size) {
658
+ IntTable t;
659
+ for (int64_t i = 0; i < size; ++i) {
660
+ t.insert(i);
661
+ }
662
+ for (int64_t i = 0; i < size; ++i) {
663
+ t.erase(i);
664
+ EXPECT_EQ(t.size(), size - i - 1);
665
+ for (int64_t j = i + 1; j < size; ++j) {
666
+ EXPECT_THAT(*t.find(j), j);
667
+ }
668
+ }
669
+ EXPECT_TRUE(t.empty());
670
+ }
671
+ }
672
+
673
+ TEST(Table, InsertWithinCapacity) {
674
+ IntTable t;
675
+ t.reserve(10);
676
+ const size_t original_capacity = t.capacity();
677
+ const auto addr = [&](int i) {
678
+ return reinterpret_cast<uintptr_t>(&*t.find(i));
679
+ };
680
+ // Inserting an element does not change capacity.
681
+ t.insert(0);
682
+ EXPECT_THAT(t.capacity(), original_capacity);
683
+ const uintptr_t original_addr_0 = addr(0);
684
+ // Inserting another element does not rehash.
685
+ t.insert(1);
686
+ EXPECT_THAT(t.capacity(), original_capacity);
687
+ EXPECT_THAT(addr(0), original_addr_0);
688
+ // Inserting lots of duplicate elements does not rehash.
689
+ for (int i = 0; i < 100; ++i) {
690
+ t.insert(i % 10);
691
+ }
692
+ EXPECT_THAT(t.capacity(), original_capacity);
693
+ EXPECT_THAT(addr(0), original_addr_0);
694
+ // Inserting a range of duplicate elements does not rehash.
695
+ std::vector<int> dup_range;
696
+ for (int i = 0; i < 100; ++i) {
697
+ dup_range.push_back(i % 10);
698
+ }
699
+ t.insert(dup_range.begin(), dup_range.end());
700
+ EXPECT_THAT(t.capacity(), original_capacity);
701
+ EXPECT_THAT(addr(0), original_addr_0);
702
+ }
703
+
704
+ template <class TableType>
705
+ class SmallTableResizeTest : public testing::Test {};
706
+
707
+ TYPED_TEST_SUITE_P(SmallTableResizeTest);
708
+
709
+ TYPED_TEST_P(SmallTableResizeTest, InsertIntoSmallTable) {
710
+ TypeParam t;
711
+ for (int i = 0; i < 32; ++i) {
712
+ t.insert(i);
713
+ ASSERT_EQ(t.size(), i + 1);
714
+ for (int j = 0; j < i + 1; ++j) {
715
+ EXPECT_TRUE(t.find(j) != t.end());
716
+ EXPECT_EQ(*t.find(j), j);
717
+ }
718
+ }
719
+ }
720
+
721
+ TYPED_TEST_P(SmallTableResizeTest, ResizeGrowSmallTables) {
722
+ TypeParam t;
723
+ for (size_t source_size = 0; source_size < 32; ++source_size) {
724
+ for (size_t target_size = source_size; target_size < 32; ++target_size) {
725
+ for (bool rehash : {false, true}) {
726
+ for (size_t i = 0; i < source_size; ++i) {
727
+ t.insert(static_cast<int>(i));
728
+ }
729
+ if (rehash) {
730
+ t.rehash(target_size);
731
+ } else {
732
+ t.reserve(target_size);
733
+ }
734
+ for (size_t i = 0; i < source_size; ++i) {
735
+ EXPECT_TRUE(t.find(static_cast<int>(i)) != t.end());
736
+ EXPECT_EQ(*t.find(static_cast<int>(i)), static_cast<int>(i));
737
+ }
738
+ }
739
+ }
740
+ }
741
+ }
742
+
743
+ TYPED_TEST_P(SmallTableResizeTest, ResizeReduceSmallTables) {
744
+ TypeParam t;
745
+ for (size_t source_size = 0; source_size < 32; ++source_size) {
746
+ for (size_t target_size = 0; target_size <= source_size; ++target_size) {
747
+ size_t inserted_count = std::min<size_t>(source_size, 5);
748
+ for (size_t i = 0; i < inserted_count; ++i) {
749
+ t.insert(static_cast<int>(i));
750
+ }
751
+ t.rehash(target_size);
752
+ for (size_t i = 0; i < inserted_count; ++i) {
753
+ EXPECT_TRUE(t.find(static_cast<int>(i)) != t.end());
754
+ EXPECT_EQ(*t.find(static_cast<int>(i)), static_cast<int>(i));
755
+ }
756
+ }
757
+ }
758
+ }
759
+
760
+ REGISTER_TYPED_TEST_SUITE_P(SmallTableResizeTest, InsertIntoSmallTable,
761
+ ResizeGrowSmallTables, ResizeReduceSmallTables);
762
+ using SmallTableTypes = ::testing::Types<IntTable, TransferableIntTable>;
763
+ INSTANTIATE_TYPED_TEST_SUITE_P(InstanceSmallTableResizeTest,
764
+ SmallTableResizeTest, SmallTableTypes);
765
+
766
+ TEST(Table, LazyEmplace) {
767
+ StringTable t;
768
+ bool called = false;
769
+ auto it = t.lazy_emplace("abc", [&](const StringTable::constructor& f) {
770
+ called = true;
771
+ f("abc", "ABC");
772
+ });
773
+ EXPECT_TRUE(called);
774
+ EXPECT_THAT(*it, Pair("abc", "ABC"));
775
+ called = false;
776
+ it = t.lazy_emplace("abc", [&](const StringTable::constructor& f) {
777
+ called = true;
778
+ f("abc", "DEF");
779
+ });
780
+ EXPECT_FALSE(called);
781
+ EXPECT_THAT(*it, Pair("abc", "ABC"));
782
+ }
783
+
784
+ TEST(Table, ContainsEmpty) {
785
+ IntTable t;
786
+
787
+ EXPECT_FALSE(t.contains(0));
788
+ }
789
+
790
+ TEST(Table, Contains1) {
791
+ IntTable t;
792
+
793
+ EXPECT_TRUE(t.insert(0).second);
794
+ EXPECT_TRUE(t.contains(0));
795
+ EXPECT_FALSE(t.contains(1));
796
+
797
+ EXPECT_EQ(1, t.erase(0));
798
+ EXPECT_FALSE(t.contains(0));
799
+ }
800
+
801
+ TEST(Table, Contains2) {
802
+ IntTable t;
803
+
804
+ EXPECT_TRUE(t.insert(0).second);
805
+ EXPECT_TRUE(t.contains(0));
806
+ EXPECT_FALSE(t.contains(1));
807
+
808
+ t.clear();
809
+ EXPECT_FALSE(t.contains(0));
810
+ }
811
+
812
+ int decompose_constructed;
813
+ int decompose_copy_constructed;
814
+ int decompose_copy_assigned;
815
+ int decompose_move_constructed;
816
+ int decompose_move_assigned;
817
+ struct DecomposeType {
818
+ DecomposeType(int i = 0) : i(i) { // NOLINT
819
+ ++decompose_constructed;
820
+ }
821
+
822
+ explicit DecomposeType(const char* d) : DecomposeType(*d) {}
823
+
824
+ DecomposeType(const DecomposeType& other) : i(other.i) {
825
+ ++decompose_copy_constructed;
826
+ }
827
+ DecomposeType& operator=(const DecomposeType& other) {
828
+ ++decompose_copy_assigned;
829
+ i = other.i;
830
+ return *this;
831
+ }
832
+ DecomposeType(DecomposeType&& other) : i(other.i) {
833
+ ++decompose_move_constructed;
834
+ }
835
+ DecomposeType& operator=(DecomposeType&& other) {
836
+ ++decompose_move_assigned;
837
+ i = other.i;
838
+ return *this;
839
+ }
840
+
841
+ int i;
842
+ };
843
+
844
+ struct DecomposeHash {
845
+ using is_transparent = void;
846
+ size_t operator()(const DecomposeType& a) const { return a.i; }
847
+ size_t operator()(int a) const { return a; }
848
+ size_t operator()(const char* a) const { return *a; }
849
+ };
850
+
851
+ struct DecomposeEq {
852
+ using is_transparent = void;
853
+ bool operator()(const DecomposeType& a, const DecomposeType& b) const {
854
+ return a.i == b.i;
855
+ }
856
+ bool operator()(const DecomposeType& a, int b) const { return a.i == b; }
857
+ bool operator()(const DecomposeType& a, const char* b) const {
858
+ return a.i == *b;
859
+ }
860
+ };
861
+
862
+ struct DecomposePolicy {
863
+ using slot_type = DecomposeType;
864
+ using key_type = DecomposeType;
865
+ using init_type = DecomposeType;
866
+
867
+ template <typename T>
868
+ static void construct(void*, DecomposeType* slot, T&& v) {
869
+ ::new (slot) DecomposeType(std::forward<T>(v));
870
+ }
871
+ static void destroy(void*, DecomposeType* slot) { slot->~DecomposeType(); }
872
+ static DecomposeType& element(slot_type* slot) { return *slot; }
873
+
874
+ template <class F, class T>
875
+ static auto apply(F&& f, const T& x) -> decltype(std::forward<F>(f)(x, x)) {
876
+ return std::forward<F>(f)(x, x);
877
+ }
878
+ };
879
+
880
+ template <typename Hash, typename Eq>
881
+ void TestDecompose(bool construct_three) {
882
+ DecomposeType elem{0};
883
+ const int one = 1;
884
+ const char* three_p = "3";
885
+ const auto& three = three_p;
886
+ const int elem_vector_count = 256;
887
+ std::vector<DecomposeType> elem_vector(elem_vector_count, DecomposeType{0});
888
+ std::iota(elem_vector.begin(), elem_vector.end(), 0);
889
+
890
+ using DecomposeSet =
891
+ raw_hash_set<DecomposePolicy, Hash, Eq, std::allocator<int>>;
892
+ DecomposeSet set1;
893
+
894
+ decompose_constructed = 0;
895
+ int expected_constructed = 0;
896
+ EXPECT_EQ(expected_constructed, decompose_constructed);
897
+ set1.insert(elem);
898
+ EXPECT_EQ(expected_constructed, decompose_constructed);
899
+ set1.insert(1);
900
+ EXPECT_EQ(++expected_constructed, decompose_constructed);
901
+ set1.emplace("3");
902
+ EXPECT_EQ(++expected_constructed, decompose_constructed);
903
+ EXPECT_EQ(expected_constructed, decompose_constructed);
904
+
905
+ { // insert(T&&)
906
+ set1.insert(1);
907
+ EXPECT_EQ(expected_constructed, decompose_constructed);
908
+ }
909
+
910
+ { // insert(const T&)
911
+ set1.insert(one);
912
+ EXPECT_EQ(expected_constructed, decompose_constructed);
913
+ }
914
+
915
+ { // insert(hint, T&&)
916
+ set1.insert(set1.begin(), 1);
917
+ EXPECT_EQ(expected_constructed, decompose_constructed);
918
+ }
919
+
920
+ { // insert(hint, const T&)
921
+ set1.insert(set1.begin(), one);
922
+ EXPECT_EQ(expected_constructed, decompose_constructed);
923
+ }
924
+
925
+ { // emplace(...)
926
+ set1.emplace(1);
927
+ EXPECT_EQ(expected_constructed, decompose_constructed);
928
+ set1.emplace("3");
929
+ expected_constructed += construct_three;
930
+ EXPECT_EQ(expected_constructed, decompose_constructed);
931
+ set1.emplace(one);
932
+ EXPECT_EQ(expected_constructed, decompose_constructed);
933
+ set1.emplace(three);
934
+ expected_constructed += construct_three;
935
+ EXPECT_EQ(expected_constructed, decompose_constructed);
936
+ }
937
+
938
+ { // emplace_hint(...)
939
+ set1.emplace_hint(set1.begin(), 1);
940
+ EXPECT_EQ(expected_constructed, decompose_constructed);
941
+ set1.emplace_hint(set1.begin(), "3");
942
+ expected_constructed += construct_three;
943
+ EXPECT_EQ(expected_constructed, decompose_constructed);
944
+ set1.emplace_hint(set1.begin(), one);
945
+ EXPECT_EQ(expected_constructed, decompose_constructed);
946
+ set1.emplace_hint(set1.begin(), three);
947
+ expected_constructed += construct_three;
948
+ EXPECT_EQ(expected_constructed, decompose_constructed);
949
+ }
950
+
951
+ decompose_copy_constructed = 0;
952
+ decompose_copy_assigned = 0;
953
+ decompose_move_constructed = 0;
954
+ decompose_move_assigned = 0;
955
+ int expected_copy_constructed = 0;
956
+ int expected_move_constructed = 0;
957
+ { // raw_hash_set(first, last) with random-access iterators
958
+ DecomposeSet set2(elem_vector.begin(), elem_vector.end());
959
+ // Expect exactly one copy-constructor call for each element if no
960
+ // rehashing is done.
961
+ expected_copy_constructed += elem_vector_count;
962
+ EXPECT_EQ(expected_copy_constructed, decompose_copy_constructed);
963
+ EXPECT_EQ(expected_move_constructed, decompose_move_constructed);
964
+ EXPECT_EQ(0, decompose_move_assigned);
965
+ EXPECT_EQ(0, decompose_copy_assigned);
966
+ }
967
+
968
+ { // raw_hash_set(first, last) with forward iterators
969
+ std::list<DecomposeType> elem_list(elem_vector.begin(), elem_vector.end());
970
+ expected_copy_constructed = decompose_copy_constructed;
971
+ DecomposeSet set2(elem_list.begin(), elem_list.end());
972
+ // Expect exactly N elements copied into set, expect at most 2*N elements
973
+ // moving internally for all resizing needed (for a growth factor of 2).
974
+ expected_copy_constructed += elem_vector_count;
975
+ EXPECT_EQ(expected_copy_constructed, decompose_copy_constructed);
976
+ expected_move_constructed += elem_vector_count;
977
+ EXPECT_LT(expected_move_constructed, decompose_move_constructed);
978
+ expected_move_constructed += elem_vector_count;
979
+ EXPECT_GE(expected_move_constructed, decompose_move_constructed);
980
+ EXPECT_EQ(0, decompose_move_assigned);
981
+ EXPECT_EQ(0, decompose_copy_assigned);
982
+ expected_copy_constructed = decompose_copy_constructed;
983
+ expected_move_constructed = decompose_move_constructed;
984
+ }
985
+
986
+ { // insert(first, last)
987
+ DecomposeSet set2;
988
+ set2.insert(elem_vector.begin(), elem_vector.end());
989
+ // Expect exactly N elements copied into set, expect at most 2*N elements
990
+ // moving internally for all resizing needed (for a growth factor of 2).
991
+ const int expected_new_elements = elem_vector_count;
992
+ const int expected_max_element_moves = 2 * elem_vector_count;
993
+ expected_copy_constructed += expected_new_elements;
994
+ EXPECT_EQ(expected_copy_constructed, decompose_copy_constructed);
995
+ expected_move_constructed += expected_max_element_moves;
996
+ EXPECT_GE(expected_move_constructed, decompose_move_constructed);
997
+ EXPECT_EQ(0, decompose_move_assigned);
998
+ EXPECT_EQ(0, decompose_copy_assigned);
999
+ expected_copy_constructed = decompose_copy_constructed;
1000
+ expected_move_constructed = decompose_move_constructed;
1001
+ }
1002
+ }
1003
+
1004
+ TEST(Table, Decompose) {
1005
+ if (SwisstableGenerationsEnabled()) {
1006
+ GTEST_SKIP() << "Generations being enabled causes extra rehashes.";
1007
+ }
1008
+
1009
+ TestDecompose<DecomposeHash, DecomposeEq>(false);
1010
+
1011
+ struct TransparentHashIntOverload {
1012
+ size_t operator()(const DecomposeType& a) const { return a.i; }
1013
+ size_t operator()(int a) const { return a; }
1014
+ };
1015
+ struct TransparentEqIntOverload {
1016
+ bool operator()(const DecomposeType& a, const DecomposeType& b) const {
1017
+ return a.i == b.i;
1018
+ }
1019
+ bool operator()(const DecomposeType& a, int b) const { return a.i == b; }
1020
+ };
1021
+ TestDecompose<TransparentHashIntOverload, DecomposeEq>(true);
1022
+ TestDecompose<TransparentHashIntOverload, TransparentEqIntOverload>(true);
1023
+ TestDecompose<DecomposeHash, TransparentEqIntOverload>(true);
1024
+ }
1025
+
1026
+ // Returns the largest m such that a table with m elements has the same number
1027
+ // of buckets as a table with n elements.
1028
+ size_t MaxDensitySize(size_t n) {
1029
+ IntTable t;
1030
+ t.reserve(n);
1031
+ for (size_t i = 0; i != n; ++i) t.emplace(i);
1032
+ const size_t c = t.bucket_count();
1033
+ while (c == t.bucket_count()) t.emplace(n++);
1034
+ return t.size() - 1;
1035
+ }
1036
+
1037
+ struct Modulo1000Hash {
1038
+ size_t operator()(int x) const { return x % 1000; }
1039
+ };
1040
+
1041
+ struct Modulo1000HashTable
1042
+ : public raw_hash_set<IntPolicy, Modulo1000Hash, std::equal_to<int>,
1043
+ std::allocator<int>> {};
1044
+
1045
+ // Test that rehash with no resize happen in case of many deleted slots.
1046
+ TEST(Table, RehashWithNoResize) {
1047
+ if (SwisstableGenerationsEnabled()) {
1048
+ GTEST_SKIP() << "Generations being enabled causes extra rehashes.";
1049
+ }
1050
+
1051
+ Modulo1000HashTable t;
1052
+ // Adding the same length (and the same hash) strings
1053
+ // to have at least kMinFullGroups groups
1054
+ // with Group::kWidth collisions. Then fill up to MaxDensitySize;
1055
+ const size_t kMinFullGroups = 7;
1056
+ std::vector<int> keys;
1057
+ for (size_t i = 0; i < MaxDensitySize(Group::kWidth * kMinFullGroups); ++i) {
1058
+ int k = i * 1000;
1059
+ t.emplace(k);
1060
+ keys.push_back(k);
1061
+ }
1062
+ const size_t capacity = t.capacity();
1063
+
1064
+ // Remove elements from all groups except the first and the last one.
1065
+ // All elements removed from full groups will be marked as ctrl_t::kDeleted.
1066
+ const size_t erase_begin = Group::kWidth / 2;
1067
+ const size_t erase_end = (t.size() / Group::kWidth - 1) * Group::kWidth;
1068
+ for (size_t i = erase_begin; i < erase_end; ++i) {
1069
+ EXPECT_EQ(1, t.erase(keys[i])) << i;
1070
+ }
1071
+ keys.erase(keys.begin() + erase_begin, keys.begin() + erase_end);
1072
+
1073
+ auto last_key = keys.back();
1074
+ size_t last_key_num_probes = GetHashtableDebugNumProbes(t, last_key);
1075
+
1076
+ // Make sure that we have to make a lot of probes for last key.
1077
+ ASSERT_GT(last_key_num_probes, kMinFullGroups);
1078
+
1079
+ int x = 1;
1080
+ // Insert and erase one element, before inplace rehash happen.
1081
+ while (last_key_num_probes == GetHashtableDebugNumProbes(t, last_key)) {
1082
+ t.emplace(x);
1083
+ ASSERT_EQ(capacity, t.capacity());
1084
+ // All elements should be there.
1085
+ ASSERT_TRUE(t.find(x) != t.end()) << x;
1086
+ for (const auto& k : keys) {
1087
+ ASSERT_TRUE(t.find(k) != t.end()) << k;
1088
+ }
1089
+ t.erase(x);
1090
+ ++x;
1091
+ }
1092
+ }
1093
+
1094
+ TEST(Table, InsertEraseStressTest) {
1095
+ IntTable t;
1096
+ const size_t kMinElementCount = 250;
1097
+ std::deque<int> keys;
1098
+ size_t i = 0;
1099
+ for (; i < MaxDensitySize(kMinElementCount); ++i) {
1100
+ t.emplace(i);
1101
+ keys.push_back(i);
1102
+ }
1103
+ const size_t kNumIterations = 1000000;
1104
+ for (; i < kNumIterations; ++i) {
1105
+ ASSERT_EQ(1, t.erase(keys.front()));
1106
+ keys.pop_front();
1107
+ t.emplace(i);
1108
+ keys.push_back(i);
1109
+ }
1110
+ }
1111
+
1112
+ TEST(Table, InsertOverloads) {
1113
+ StringTable t;
1114
+ // These should all trigger the insert(init_type) overload.
1115
+ t.insert({{}, {}});
1116
+ t.insert({"ABC", {}});
1117
+ t.insert({"DEF", "!!!"});
1118
+
1119
+ EXPECT_THAT(t, UnorderedElementsAre(Pair("", ""), Pair("ABC", ""),
1120
+ Pair("DEF", "!!!")));
1121
+ }
1122
+
1123
+ TEST(Table, LargeTable) {
1124
+ IntTable t;
1125
+ for (int64_t i = 0; i != 100000; ++i) t.emplace(i << 40);
1126
+ for (int64_t i = 0; i != 100000; ++i) ASSERT_EQ(i << 40, *t.find(i << 40));
1127
+ }
1128
+
1129
+ // Timeout if copy is quadratic as it was in Rust.
1130
+ TEST(Table, EnsureNonQuadraticAsInRust) {
1131
+ static const size_t kLargeSize = 1 << 15;
1132
+
1133
+ IntTable t;
1134
+ for (size_t i = 0; i != kLargeSize; ++i) {
1135
+ t.insert(i);
1136
+ }
1137
+
1138
+ // If this is quadratic, the test will timeout.
1139
+ IntTable t2;
1140
+ for (const auto& entry : t) t2.insert(entry);
1141
+ }
1142
+
1143
+ TEST(Table, ClearBug) {
1144
+ if (SwisstableGenerationsEnabled()) {
1145
+ GTEST_SKIP() << "Generations being enabled causes extra rehashes.";
1146
+ }
1147
+
1148
+ IntTable t;
1149
+ constexpr size_t capacity = container_internal::Group::kWidth - 1;
1150
+ constexpr size_t max_size = capacity / 2 + 1;
1151
+ for (size_t i = 0; i < max_size; ++i) {
1152
+ t.insert(i);
1153
+ }
1154
+ ASSERT_EQ(capacity, t.capacity());
1155
+ intptr_t original = reinterpret_cast<intptr_t>(&*t.find(2));
1156
+ t.clear();
1157
+ ASSERT_EQ(capacity, t.capacity());
1158
+ for (size_t i = 0; i < max_size; ++i) {
1159
+ t.insert(i);
1160
+ }
1161
+ ASSERT_EQ(capacity, t.capacity());
1162
+ intptr_t second = reinterpret_cast<intptr_t>(&*t.find(2));
1163
+ // We are checking that original and second are close enough to each other
1164
+ // that they are probably still in the same group. This is not strictly
1165
+ // guaranteed.
1166
+ EXPECT_LT(static_cast<size_t>(std::abs(original - second)),
1167
+ capacity * sizeof(IntTable::value_type));
1168
+ }
1169
+
1170
+ TEST(Table, Erase) {
1171
+ IntTable t;
1172
+ EXPECT_TRUE(t.find(0) == t.end());
1173
+ auto res = t.emplace(0);
1174
+ EXPECT_TRUE(res.second);
1175
+ EXPECT_EQ(1, t.size());
1176
+ t.erase(res.first);
1177
+ EXPECT_EQ(0, t.size());
1178
+ EXPECT_TRUE(t.find(0) == t.end());
1179
+ }
1180
+
1181
+ TEST(Table, EraseMaintainsValidIterator) {
1182
+ IntTable t;
1183
+ const int kNumElements = 100;
1184
+ for (int i = 0; i < kNumElements; i++) {
1185
+ EXPECT_TRUE(t.emplace(i).second);
1186
+ }
1187
+ EXPECT_EQ(t.size(), kNumElements);
1188
+
1189
+ int num_erase_calls = 0;
1190
+ auto it = t.begin();
1191
+ while (it != t.end()) {
1192
+ t.erase(it++);
1193
+ num_erase_calls++;
1194
+ }
1195
+
1196
+ EXPECT_TRUE(t.empty());
1197
+ EXPECT_EQ(num_erase_calls, kNumElements);
1198
+ }
1199
+
1200
+ TEST(Table, EraseBeginEnd) {
1201
+ IntTable t;
1202
+ for (int i = 0; i < 10; ++i) t.insert(i);
1203
+ EXPECT_EQ(t.size(), 10);
1204
+ t.erase(t.begin(), t.end());
1205
+ EXPECT_EQ(t.size(), 0);
1206
+ }
1207
+
1208
+ // Collect N bad keys by following algorithm:
1209
+ // 1. Create an empty table and reserve it to 2 * N.
1210
+ // 2. Insert N random elements.
1211
+ // 3. Take first Group::kWidth - 1 to bad_keys array.
1212
+ // 4. Clear the table without resize.
1213
+ // 5. Go to point 2 while N keys not collected
1214
+ std::vector<int64_t> CollectBadMergeKeys(size_t N) {
1215
+ static constexpr int kGroupSize = Group::kWidth - 1;
1216
+
1217
+ auto topk_range = [](size_t b, size_t e,
1218
+ IntTable* t) -> std::vector<int64_t> {
1219
+ for (size_t i = b; i != e; ++i) {
1220
+ t->emplace(i);
1221
+ }
1222
+ std::vector<int64_t> res;
1223
+ res.reserve(kGroupSize);
1224
+ auto it = t->begin();
1225
+ for (size_t i = b; i != e && i != b + kGroupSize; ++i, ++it) {
1226
+ res.push_back(*it);
1227
+ }
1228
+ return res;
1229
+ };
1230
+
1231
+ std::vector<int64_t> bad_keys;
1232
+ bad_keys.reserve(N);
1233
+ IntTable t;
1234
+ t.reserve(N * 2);
1235
+
1236
+ for (size_t b = 0; bad_keys.size() < N; b += N) {
1237
+ auto keys = topk_range(b, b + N, &t);
1238
+ bad_keys.insert(bad_keys.end(), keys.begin(), keys.end());
1239
+ t.erase(t.begin(), t.end());
1240
+ EXPECT_TRUE(t.empty());
1241
+ }
1242
+ return bad_keys;
1243
+ }
1244
+
1245
+ struct ProbeStats {
1246
+ // Number of elements with specific probe length over all tested tables.
1247
+ std::vector<size_t> all_probes_histogram;
1248
+ // Ratios total_probe_length/size for every tested table.
1249
+ std::vector<double> single_table_ratios;
1250
+
1251
+ // Average ratio total_probe_length/size over tables.
1252
+ double AvgRatio() const {
1253
+ return std::accumulate(single_table_ratios.begin(),
1254
+ single_table_ratios.end(), 0.0) /
1255
+ single_table_ratios.size();
1256
+ }
1257
+
1258
+ // Maximum ratio total_probe_length/size over tables.
1259
+ double MaxRatio() const {
1260
+ return *std::max_element(single_table_ratios.begin(),
1261
+ single_table_ratios.end());
1262
+ }
1263
+
1264
+ // Percentile ratio total_probe_length/size over tables.
1265
+ double PercentileRatio(double Percentile = 0.95) const {
1266
+ auto r = single_table_ratios;
1267
+ auto mid = r.begin() + static_cast<size_t>(r.size() * Percentile);
1268
+ if (mid != r.end()) {
1269
+ std::nth_element(r.begin(), mid, r.end());
1270
+ return *mid;
1271
+ } else {
1272
+ return MaxRatio();
1273
+ }
1274
+ }
1275
+
1276
+ // Maximum probe length over all elements and all tables.
1277
+ size_t MaxProbe() const { return all_probes_histogram.size(); }
1278
+
1279
+ // Fraction of elements with specified probe length.
1280
+ std::vector<double> ProbeNormalizedHistogram() const {
1281
+ double total_elements = std::accumulate(all_probes_histogram.begin(),
1282
+ all_probes_histogram.end(), 0ull);
1283
+ std::vector<double> res;
1284
+ for (size_t p : all_probes_histogram) {
1285
+ res.push_back(p / total_elements);
1286
+ }
1287
+ return res;
1288
+ }
1289
+
1290
+ size_t PercentileProbe(double Percentile = 0.99) const {
1291
+ size_t idx = 0;
1292
+ for (double p : ProbeNormalizedHistogram()) {
1293
+ if (Percentile > p) {
1294
+ Percentile -= p;
1295
+ ++idx;
1296
+ } else {
1297
+ return idx;
1298
+ }
1299
+ }
1300
+ return idx;
1301
+ }
1302
+
1303
+ friend std::ostream& operator<<(std::ostream& out, const ProbeStats& s) {
1304
+ out << "{AvgRatio:" << s.AvgRatio() << ", MaxRatio:" << s.MaxRatio()
1305
+ << ", PercentileRatio:" << s.PercentileRatio()
1306
+ << ", MaxProbe:" << s.MaxProbe() << ", Probes=[";
1307
+ for (double p : s.ProbeNormalizedHistogram()) {
1308
+ out << p << ",";
1309
+ }
1310
+ out << "]}";
1311
+
1312
+ return out;
1313
+ }
1314
+ };
1315
+
1316
+ struct ExpectedStats {
1317
+ double avg_ratio;
1318
+ double max_ratio;
1319
+ std::vector<std::pair<double, double>> pecentile_ratios;
1320
+ std::vector<std::pair<double, double>> pecentile_probes;
1321
+
1322
+ friend std::ostream& operator<<(std::ostream& out, const ExpectedStats& s) {
1323
+ out << "{AvgRatio:" << s.avg_ratio << ", MaxRatio:" << s.max_ratio
1324
+ << ", PercentileRatios: [";
1325
+ for (auto el : s.pecentile_ratios) {
1326
+ out << el.first << ":" << el.second << ", ";
1327
+ }
1328
+ out << "], PercentileProbes: [";
1329
+ for (auto el : s.pecentile_probes) {
1330
+ out << el.first << ":" << el.second << ", ";
1331
+ }
1332
+ out << "]}";
1333
+
1334
+ return out;
1335
+ }
1336
+ };
1337
+
1338
+ void VerifyStats(size_t size, const ExpectedStats& exp,
1339
+ const ProbeStats& stats) {
1340
+ EXPECT_LT(stats.AvgRatio(), exp.avg_ratio) << size << " " << stats;
1341
+ EXPECT_LT(stats.MaxRatio(), exp.max_ratio) << size << " " << stats;
1342
+ for (auto pr : exp.pecentile_ratios) {
1343
+ EXPECT_LE(stats.PercentileRatio(pr.first), pr.second)
1344
+ << size << " " << pr.first << " " << stats;
1345
+ }
1346
+
1347
+ for (auto pr : exp.pecentile_probes) {
1348
+ EXPECT_LE(stats.PercentileProbe(pr.first), pr.second)
1349
+ << size << " " << pr.first << " " << stats;
1350
+ }
1351
+ }
1352
+
1353
+ using ProbeStatsPerSize = std::map<size_t, ProbeStats>;
1354
+
1355
+ // Collect total ProbeStats on num_iters iterations of the following algorithm:
1356
+ // 1. Create new table and reserve it to keys.size() * 2
1357
+ // 2. Insert all keys xored with seed
1358
+ // 3. Collect ProbeStats from final table.
1359
+ ProbeStats CollectProbeStatsOnKeysXoredWithSeed(
1360
+ const std::vector<int64_t>& keys, size_t num_iters) {
1361
+ const size_t reserve_size = keys.size() * 2;
1362
+
1363
+ ProbeStats stats;
1364
+
1365
+ int64_t seed = 0x71b1a19b907d6e33;
1366
+ while (num_iters--) {
1367
+ seed = static_cast<int64_t>(static_cast<uint64_t>(seed) * 17 + 13);
1368
+ IntTable t1;
1369
+ t1.reserve(reserve_size);
1370
+ for (const auto& key : keys) {
1371
+ t1.emplace(key ^ seed);
1372
+ }
1373
+
1374
+ auto probe_histogram = GetHashtableDebugNumProbesHistogram(t1);
1375
+ stats.all_probes_histogram.resize(
1376
+ std::max(stats.all_probes_histogram.size(), probe_histogram.size()));
1377
+ std::transform(probe_histogram.begin(), probe_histogram.end(),
1378
+ stats.all_probes_histogram.begin(),
1379
+ stats.all_probes_histogram.begin(), std::plus<size_t>());
1380
+
1381
+ size_t total_probe_seq_length = 0;
1382
+ for (size_t i = 0; i < probe_histogram.size(); ++i) {
1383
+ total_probe_seq_length += i * probe_histogram[i];
1384
+ }
1385
+ stats.single_table_ratios.push_back(total_probe_seq_length * 1.0 /
1386
+ keys.size());
1387
+ t1.erase(t1.begin(), t1.end());
1388
+ }
1389
+ return stats;
1390
+ }
1391
+
1392
+ ExpectedStats XorSeedExpectedStats() {
1393
+ constexpr bool kRandomizesInserts =
1394
+ #ifdef NDEBUG
1395
+ false;
1396
+ #else // NDEBUG
1397
+ true;
1398
+ #endif // NDEBUG
1399
+
1400
+ // The effective load factor is larger in non-opt mode because we insert
1401
+ // elements out of order.
1402
+ switch (container_internal::Group::kWidth) {
1403
+ case 8:
1404
+ if (kRandomizesInserts) {
1405
+ return {0.05,
1406
+ 1.0,
1407
+ {{0.95, 0.5}},
1408
+ {{0.95, 0}, {0.99, 2}, {0.999, 4}, {0.9999, 10}}};
1409
+ } else {
1410
+ return {0.05,
1411
+ 2.0,
1412
+ {{0.95, 0.1}},
1413
+ {{0.95, 0}, {0.99, 2}, {0.999, 4}, {0.9999, 10}}};
1414
+ }
1415
+ case 16:
1416
+ if (kRandomizesInserts) {
1417
+ return {0.1,
1418
+ 2.0,
1419
+ {{0.95, 0.1}},
1420
+ {{0.95, 0}, {0.99, 1}, {0.999, 8}, {0.9999, 15}}};
1421
+ } else {
1422
+ return {0.05,
1423
+ 1.0,
1424
+ {{0.95, 0.05}},
1425
+ {{0.95, 0}, {0.99, 1}, {0.999, 4}, {0.9999, 10}}};
1426
+ }
1427
+ }
1428
+ LOG(FATAL) << "Unknown Group width";
1429
+ return {};
1430
+ }
1431
+
1432
+ // TODO(b/80415403): Figure out why this test is so flaky, esp. on MSVC
1433
+ TEST(Table, DISABLED_EnsureNonQuadraticTopNXorSeedByProbeSeqLength) {
1434
+ ProbeStatsPerSize stats;
1435
+ std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10};
1436
+ for (size_t size : sizes) {
1437
+ stats[size] =
1438
+ CollectProbeStatsOnKeysXoredWithSeed(CollectBadMergeKeys(size), 200);
1439
+ }
1440
+ auto expected = XorSeedExpectedStats();
1441
+ for (size_t size : sizes) {
1442
+ auto& stat = stats[size];
1443
+ VerifyStats(size, expected, stat);
1444
+ LOG(INFO) << size << " " << stat;
1445
+ }
1446
+ }
1447
+
1448
+ // Collect total ProbeStats on num_iters iterations of the following algorithm:
1449
+ // 1. Create new table
1450
+ // 2. Select 10% of keys and insert 10 elements key * 17 + j * 13
1451
+ // 3. Collect ProbeStats from final table
1452
+ ProbeStats CollectProbeStatsOnLinearlyTransformedKeys(
1453
+ const std::vector<int64_t>& keys, size_t num_iters) {
1454
+ ProbeStats stats;
1455
+
1456
+ std::random_device rd;
1457
+ std::mt19937 rng(rd());
1458
+ auto linear_transform = [](size_t x, size_t y) { return x * 17 + y * 13; };
1459
+ std::uniform_int_distribution<size_t> dist(0, keys.size() - 1);
1460
+ while (num_iters--) {
1461
+ IntTable t1;
1462
+ size_t num_keys = keys.size() / 10;
1463
+ size_t start = dist(rng);
1464
+ for (size_t i = 0; i != num_keys; ++i) {
1465
+ for (size_t j = 0; j != 10; ++j) {
1466
+ t1.emplace(linear_transform(keys[(i + start) % keys.size()], j));
1467
+ }
1468
+ }
1469
+
1470
+ auto probe_histogram = GetHashtableDebugNumProbesHistogram(t1);
1471
+ stats.all_probes_histogram.resize(
1472
+ std::max(stats.all_probes_histogram.size(), probe_histogram.size()));
1473
+ std::transform(probe_histogram.begin(), probe_histogram.end(),
1474
+ stats.all_probes_histogram.begin(),
1475
+ stats.all_probes_histogram.begin(), std::plus<size_t>());
1476
+
1477
+ size_t total_probe_seq_length = 0;
1478
+ for (size_t i = 0; i < probe_histogram.size(); ++i) {
1479
+ total_probe_seq_length += i * probe_histogram[i];
1480
+ }
1481
+ stats.single_table_ratios.push_back(total_probe_seq_length * 1.0 /
1482
+ t1.size());
1483
+ t1.erase(t1.begin(), t1.end());
1484
+ }
1485
+ return stats;
1486
+ }
1487
+
1488
+ ExpectedStats LinearTransformExpectedStats() {
1489
+ constexpr bool kRandomizesInserts =
1490
+ #ifdef NDEBUG
1491
+ false;
1492
+ #else // NDEBUG
1493
+ true;
1494
+ #endif // NDEBUG
1495
+
1496
+ // The effective load factor is larger in non-opt mode because we insert
1497
+ // elements out of order.
1498
+ switch (container_internal::Group::kWidth) {
1499
+ case 8:
1500
+ if (kRandomizesInserts) {
1501
+ return {0.1,
1502
+ 0.5,
1503
+ {{0.95, 0.3}},
1504
+ {{0.95, 0}, {0.99, 1}, {0.999, 8}, {0.9999, 15}}};
1505
+ } else {
1506
+ return {0.4,
1507
+ 0.6,
1508
+ {{0.95, 0.5}},
1509
+ {{0.95, 1}, {0.99, 14}, {0.999, 23}, {0.9999, 26}}};
1510
+ }
1511
+ case 16:
1512
+ if (kRandomizesInserts) {
1513
+ return {0.1,
1514
+ 0.4,
1515
+ {{0.95, 0.3}},
1516
+ {{0.95, 1}, {0.99, 2}, {0.999, 9}, {0.9999, 15}}};
1517
+ } else {
1518
+ return {0.05,
1519
+ 0.2,
1520
+ {{0.95, 0.1}},
1521
+ {{0.95, 0}, {0.99, 1}, {0.999, 6}, {0.9999, 10}}};
1522
+ }
1523
+ }
1524
+ LOG(FATAL) << "Unknown Group width";
1525
+ return {};
1526
+ }
1527
+
1528
+ // TODO(b/80415403): Figure out why this test is so flaky.
1529
+ TEST(Table, DISABLED_EnsureNonQuadraticTopNLinearTransformByProbeSeqLength) {
1530
+ ProbeStatsPerSize stats;
1531
+ std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10};
1532
+ for (size_t size : sizes) {
1533
+ stats[size] = CollectProbeStatsOnLinearlyTransformedKeys(
1534
+ CollectBadMergeKeys(size), 300);
1535
+ }
1536
+ auto expected = LinearTransformExpectedStats();
1537
+ for (size_t size : sizes) {
1538
+ auto& stat = stats[size];
1539
+ VerifyStats(size, expected, stat);
1540
+ LOG(INFO) << size << " " << stat;
1541
+ }
1542
+ }
1543
+
1544
+ TEST(Table, EraseCollision) {
1545
+ BadTable t;
1546
+
1547
+ // 1 2 3
1548
+ t.emplace(1);
1549
+ t.emplace(2);
1550
+ t.emplace(3);
1551
+ EXPECT_THAT(*t.find(1), 1);
1552
+ EXPECT_THAT(*t.find(2), 2);
1553
+ EXPECT_THAT(*t.find(3), 3);
1554
+ EXPECT_EQ(3, t.size());
1555
+
1556
+ // 1 DELETED 3
1557
+ t.erase(t.find(2));
1558
+ EXPECT_THAT(*t.find(1), 1);
1559
+ EXPECT_TRUE(t.find(2) == t.end());
1560
+ EXPECT_THAT(*t.find(3), 3);
1561
+ EXPECT_EQ(2, t.size());
1562
+
1563
+ // DELETED DELETED 3
1564
+ t.erase(t.find(1));
1565
+ EXPECT_TRUE(t.find(1) == t.end());
1566
+ EXPECT_TRUE(t.find(2) == t.end());
1567
+ EXPECT_THAT(*t.find(3), 3);
1568
+ EXPECT_EQ(1, t.size());
1569
+
1570
+ // DELETED DELETED DELETED
1571
+ t.erase(t.find(3));
1572
+ EXPECT_TRUE(t.find(1) == t.end());
1573
+ EXPECT_TRUE(t.find(2) == t.end());
1574
+ EXPECT_TRUE(t.find(3) == t.end());
1575
+ EXPECT_EQ(0, t.size());
1576
+ }
1577
+
1578
+ TEST(Table, EraseInsertProbing) {
1579
+ BadTable t(100);
1580
+
1581
+ // 1 2 3 4
1582
+ t.emplace(1);
1583
+ t.emplace(2);
1584
+ t.emplace(3);
1585
+ t.emplace(4);
1586
+
1587
+ // 1 DELETED 3 DELETED
1588
+ t.erase(t.find(2));
1589
+ t.erase(t.find(4));
1590
+
1591
+ // 1 10 3 11 12
1592
+ t.emplace(10);
1593
+ t.emplace(11);
1594
+ t.emplace(12);
1595
+
1596
+ EXPECT_EQ(5, t.size());
1597
+ EXPECT_THAT(t, UnorderedElementsAre(1, 10, 3, 11, 12));
1598
+ }
1599
+
1600
+ TEST(Table, Clear) {
1601
+ IntTable t;
1602
+ EXPECT_TRUE(t.find(0) == t.end());
1603
+ t.clear();
1604
+ EXPECT_TRUE(t.find(0) == t.end());
1605
+ auto res = t.emplace(0);
1606
+ EXPECT_TRUE(res.second);
1607
+ EXPECT_EQ(1, t.size());
1608
+ t.clear();
1609
+ EXPECT_EQ(0, t.size());
1610
+ EXPECT_TRUE(t.find(0) == t.end());
1611
+ }
1612
+
1613
+ TEST(Table, Swap) {
1614
+ IntTable t;
1615
+ EXPECT_TRUE(t.find(0) == t.end());
1616
+ auto res = t.emplace(0);
1617
+ EXPECT_TRUE(res.second);
1618
+ EXPECT_EQ(1, t.size());
1619
+ IntTable u;
1620
+ t.swap(u);
1621
+ EXPECT_EQ(0, t.size());
1622
+ EXPECT_EQ(1, u.size());
1623
+ EXPECT_TRUE(t.find(0) == t.end());
1624
+ EXPECT_THAT(*u.find(0), 0);
1625
+ }
1626
+
1627
+ TEST(Table, Rehash) {
1628
+ IntTable t;
1629
+ EXPECT_TRUE(t.find(0) == t.end());
1630
+ t.emplace(0);
1631
+ t.emplace(1);
1632
+ EXPECT_EQ(2, t.size());
1633
+ t.rehash(128);
1634
+ EXPECT_EQ(2, t.size());
1635
+ EXPECT_THAT(*t.find(0), 0);
1636
+ EXPECT_THAT(*t.find(1), 1);
1637
+ }
1638
+
1639
+ TEST(Table, RehashDoesNotRehashWhenNotNecessary) {
1640
+ IntTable t;
1641
+ t.emplace(0);
1642
+ t.emplace(1);
1643
+ auto* p = &*t.find(0);
1644
+ t.rehash(1);
1645
+ EXPECT_EQ(p, &*t.find(0));
1646
+ }
1647
+
1648
+ TEST(Table, RehashZeroDoesNotAllocateOnEmptyTable) {
1649
+ IntTable t;
1650
+ t.rehash(0);
1651
+ EXPECT_EQ(0, t.bucket_count());
1652
+ }
1653
+
1654
+ TEST(Table, RehashZeroDeallocatesEmptyTable) {
1655
+ IntTable t;
1656
+ t.emplace(0);
1657
+ t.clear();
1658
+ EXPECT_NE(0, t.bucket_count());
1659
+ t.rehash(0);
1660
+ EXPECT_EQ(0, t.bucket_count());
1661
+ }
1662
+
1663
+ TEST(Table, RehashZeroForcesRehash) {
1664
+ IntTable t;
1665
+ t.emplace(0);
1666
+ t.emplace(1);
1667
+ auto* p = &*t.find(0);
1668
+ t.rehash(0);
1669
+ EXPECT_NE(p, &*t.find(0));
1670
+ }
1671
+
1672
+ TEST(Table, ConstructFromInitList) {
1673
+ using P = std::pair<std::string, std::string>;
1674
+ struct Q {
1675
+ operator P() const { return {}; } // NOLINT
1676
+ };
1677
+ StringTable t = {P(), Q(), {}, {{}, {}}};
1678
+ }
1679
+
1680
+ TEST(Table, CopyConstruct) {
1681
+ IntTable t;
1682
+ t.emplace(0);
1683
+ EXPECT_EQ(1, t.size());
1684
+ {
1685
+ IntTable u(t);
1686
+ EXPECT_EQ(1, u.size());
1687
+ EXPECT_THAT(*u.find(0), 0);
1688
+ }
1689
+ {
1690
+ IntTable u{t};
1691
+ EXPECT_EQ(1, u.size());
1692
+ EXPECT_THAT(*u.find(0), 0);
1693
+ }
1694
+ {
1695
+ IntTable u = t;
1696
+ EXPECT_EQ(1, u.size());
1697
+ EXPECT_THAT(*u.find(0), 0);
1698
+ }
1699
+ }
1700
+
1701
+ TEST(Table, CopyConstructWithAlloc) {
1702
+ StringTable t;
1703
+ t.emplace("a", "b");
1704
+ EXPECT_EQ(1, t.size());
1705
+ StringTable u(t, Alloc<std::pair<std::string, std::string>>());
1706
+ EXPECT_EQ(1, u.size());
1707
+ EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1708
+ }
1709
+
1710
+ struct ExplicitAllocIntTable
1711
+ : raw_hash_set<IntPolicy, hash_default_hash<int64_t>,
1712
+ std::equal_to<int64_t>, Alloc<int64_t>> {
1713
+ ExplicitAllocIntTable() = default;
1714
+ };
1715
+
1716
+ TEST(Table, AllocWithExplicitCtor) {
1717
+ ExplicitAllocIntTable t;
1718
+ EXPECT_EQ(0, t.size());
1719
+ }
1720
+
1721
+ TEST(Table, MoveConstruct) {
1722
+ {
1723
+ StringTable t;
1724
+ t.emplace("a", "b");
1725
+ EXPECT_EQ(1, t.size());
1726
+
1727
+ StringTable u(std::move(t));
1728
+ EXPECT_EQ(1, u.size());
1729
+ EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1730
+ }
1731
+ {
1732
+ StringTable t;
1733
+ t.emplace("a", "b");
1734
+ EXPECT_EQ(1, t.size());
1735
+
1736
+ StringTable u{std::move(t)};
1737
+ EXPECT_EQ(1, u.size());
1738
+ EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1739
+ }
1740
+ {
1741
+ StringTable t;
1742
+ t.emplace("a", "b");
1743
+ EXPECT_EQ(1, t.size());
1744
+
1745
+ StringTable u = std::move(t);
1746
+ EXPECT_EQ(1, u.size());
1747
+ EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1748
+ }
1749
+ }
1750
+
1751
+ TEST(Table, MoveConstructWithAlloc) {
1752
+ StringTable t;
1753
+ t.emplace("a", "b");
1754
+ EXPECT_EQ(1, t.size());
1755
+ StringTable u(std::move(t), Alloc<std::pair<std::string, std::string>>());
1756
+ EXPECT_EQ(1, u.size());
1757
+ EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1758
+ }
1759
+
1760
+ TEST(Table, CopyAssign) {
1761
+ StringTable t;
1762
+ t.emplace("a", "b");
1763
+ EXPECT_EQ(1, t.size());
1764
+ StringTable u;
1765
+ u = t;
1766
+ EXPECT_EQ(1, u.size());
1767
+ EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1768
+ }
1769
+
1770
+ TEST(Table, CopySelfAssign) {
1771
+ StringTable t;
1772
+ t.emplace("a", "b");
1773
+ EXPECT_EQ(1, t.size());
1774
+ t = *&t;
1775
+ EXPECT_EQ(1, t.size());
1776
+ EXPECT_THAT(*t.find("a"), Pair("a", "b"));
1777
+ }
1778
+
1779
+ TEST(Table, MoveAssign) {
1780
+ StringTable t;
1781
+ t.emplace("a", "b");
1782
+ EXPECT_EQ(1, t.size());
1783
+ StringTable u;
1784
+ u = std::move(t);
1785
+ EXPECT_EQ(1, u.size());
1786
+ EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1787
+ }
1788
+
1789
+ TEST(Table, MoveSelfAssign) {
1790
+ StringTable t;
1791
+ t.emplace("a", "b");
1792
+ EXPECT_EQ(1, t.size());
1793
+ t = std::move(*&t);
1794
+ // As long as we don't crash, it's fine.
1795
+ }
1796
+
1797
+ TEST(Table, Equality) {
1798
+ StringTable t;
1799
+ std::vector<std::pair<std::string, std::string>> v = {{"a", "b"},
1800
+ {"aa", "bb"}};
1801
+ t.insert(std::begin(v), std::end(v));
1802
+ StringTable u = t;
1803
+ EXPECT_EQ(u, t);
1804
+ }
1805
+
1806
+ TEST(Table, Equality2) {
1807
+ StringTable t;
1808
+ std::vector<std::pair<std::string, std::string>> v1 = {{"a", "b"},
1809
+ {"aa", "bb"}};
1810
+ t.insert(std::begin(v1), std::end(v1));
1811
+ StringTable u;
1812
+ std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"},
1813
+ {"aa", "aa"}};
1814
+ u.insert(std::begin(v2), std::end(v2));
1815
+ EXPECT_NE(u, t);
1816
+ }
1817
+
1818
+ TEST(Table, Equality3) {
1819
+ StringTable t;
1820
+ std::vector<std::pair<std::string, std::string>> v1 = {{"b", "b"},
1821
+ {"bb", "bb"}};
1822
+ t.insert(std::begin(v1), std::end(v1));
1823
+ StringTable u;
1824
+ std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"},
1825
+ {"aa", "aa"}};
1826
+ u.insert(std::begin(v2), std::end(v2));
1827
+ EXPECT_NE(u, t);
1828
+ }
1829
+
1830
+ TEST(Table, NumDeletedRegression) {
1831
+ IntTable t;
1832
+ t.emplace(0);
1833
+ t.erase(t.find(0));
1834
+ // construct over a deleted slot.
1835
+ t.emplace(0);
1836
+ t.clear();
1837
+ }
1838
+
1839
+ TEST(Table, FindFullDeletedRegression) {
1840
+ IntTable t;
1841
+ for (int i = 0; i < 1000; ++i) {
1842
+ t.emplace(i);
1843
+ t.erase(t.find(i));
1844
+ }
1845
+ EXPECT_EQ(0, t.size());
1846
+ }
1847
+
1848
+ TEST(Table, ReplacingDeletedSlotDoesNotRehash) {
1849
+ size_t n;
1850
+ {
1851
+ // Compute n such that n is the maximum number of elements before rehash.
1852
+ IntTable t;
1853
+ t.emplace(0);
1854
+ size_t c = t.bucket_count();
1855
+ for (n = 1; c == t.bucket_count(); ++n) t.emplace(n);
1856
+ --n;
1857
+ }
1858
+ IntTable t;
1859
+ t.rehash(n);
1860
+ const size_t c = t.bucket_count();
1861
+ for (size_t i = 0; i != n; ++i) t.emplace(i);
1862
+ EXPECT_EQ(c, t.bucket_count()) << "rehashing threshold = " << n;
1863
+ t.erase(0);
1864
+ t.emplace(0);
1865
+ EXPECT_EQ(c, t.bucket_count()) << "rehashing threshold = " << n;
1866
+ }
1867
+
1868
+ TEST(Table, NoThrowMoveConstruct) {
1869
+ ASSERT_TRUE(
1870
+ std::is_nothrow_copy_constructible<absl::Hash<absl::string_view>>::value);
1871
+ ASSERT_TRUE(std::is_nothrow_copy_constructible<
1872
+ std::equal_to<absl::string_view>>::value);
1873
+ ASSERT_TRUE(std::is_nothrow_copy_constructible<std::allocator<int>>::value);
1874
+ EXPECT_TRUE(std::is_nothrow_move_constructible<StringTable>::value);
1875
+ }
1876
+
1877
+ TEST(Table, NoThrowMoveAssign) {
1878
+ ASSERT_TRUE(
1879
+ std::is_nothrow_move_assignable<absl::Hash<absl::string_view>>::value);
1880
+ ASSERT_TRUE(
1881
+ std::is_nothrow_move_assignable<std::equal_to<absl::string_view>>::value);
1882
+ ASSERT_TRUE(std::is_nothrow_move_assignable<std::allocator<int>>::value);
1883
+ ASSERT_TRUE(
1884
+ absl::allocator_traits<std::allocator<int>>::is_always_equal::value);
1885
+ EXPECT_TRUE(std::is_nothrow_move_assignable<StringTable>::value);
1886
+ }
1887
+
1888
+ TEST(Table, NoThrowSwappable) {
1889
+ ASSERT_TRUE(
1890
+ container_internal::IsNoThrowSwappable<absl::Hash<absl::string_view>>());
1891
+ ASSERT_TRUE(container_internal::IsNoThrowSwappable<
1892
+ std::equal_to<absl::string_view>>());
1893
+ ASSERT_TRUE(container_internal::IsNoThrowSwappable<std::allocator<int>>());
1894
+ EXPECT_TRUE(container_internal::IsNoThrowSwappable<StringTable>());
1895
+ }
1896
+
1897
+ TEST(Table, HeterogeneousLookup) {
1898
+ struct Hash {
1899
+ size_t operator()(int64_t i) const { return i; }
1900
+ size_t operator()(double i) const {
1901
+ ADD_FAILURE();
1902
+ return i;
1903
+ }
1904
+ };
1905
+ struct Eq {
1906
+ bool operator()(int64_t a, int64_t b) const { return a == b; }
1907
+ bool operator()(double a, int64_t b) const {
1908
+ ADD_FAILURE();
1909
+ return a == b;
1910
+ }
1911
+ bool operator()(int64_t a, double b) const {
1912
+ ADD_FAILURE();
1913
+ return a == b;
1914
+ }
1915
+ bool operator()(double a, double b) const {
1916
+ ADD_FAILURE();
1917
+ return a == b;
1918
+ }
1919
+ };
1920
+
1921
+ struct THash {
1922
+ using is_transparent = void;
1923
+ size_t operator()(int64_t i) const { return i; }
1924
+ size_t operator()(double i) const { return i; }
1925
+ };
1926
+ struct TEq {
1927
+ using is_transparent = void;
1928
+ bool operator()(int64_t a, int64_t b) const { return a == b; }
1929
+ bool operator()(double a, int64_t b) const { return a == b; }
1930
+ bool operator()(int64_t a, double b) const { return a == b; }
1931
+ bool operator()(double a, double b) const { return a == b; }
1932
+ };
1933
+
1934
+ raw_hash_set<IntPolicy, Hash, Eq, Alloc<int64_t>> s{0, 1, 2};
1935
+ // It will convert to int64_t before the query.
1936
+ EXPECT_EQ(1, *s.find(double{1.1}));
1937
+
1938
+ raw_hash_set<IntPolicy, THash, TEq, Alloc<int64_t>> ts{0, 1, 2};
1939
+ // It will try to use the double, and fail to find the object.
1940
+ EXPECT_TRUE(ts.find(1.1) == ts.end());
1941
+ }
1942
+
1943
+ template <class Table>
1944
+ using CallFind = decltype(std::declval<Table&>().find(17));
1945
+
1946
+ template <class Table>
1947
+ using CallErase = decltype(std::declval<Table&>().erase(17));
1948
+
1949
+ template <class Table>
1950
+ using CallExtract = decltype(std::declval<Table&>().extract(17));
1951
+
1952
+ template <class Table>
1953
+ using CallPrefetch = decltype(std::declval<Table&>().prefetch(17));
1954
+
1955
+ template <class Table>
1956
+ using CallCount = decltype(std::declval<Table&>().count(17));
1957
+
1958
+ template <template <typename> class C, class Table, class = void>
1959
+ struct VerifyResultOf : std::false_type {};
1960
+
1961
+ template <template <typename> class C, class Table>
1962
+ struct VerifyResultOf<C, Table, absl::void_t<C<Table>>> : std::true_type {};
1963
+
1964
+ TEST(Table, HeterogeneousLookupOverloads) {
1965
+ using NonTransparentTable =
1966
+ raw_hash_set<StringPolicy, absl::Hash<absl::string_view>,
1967
+ std::equal_to<absl::string_view>, std::allocator<int>>;
1968
+
1969
+ EXPECT_FALSE((VerifyResultOf<CallFind, NonTransparentTable>()));
1970
+ EXPECT_FALSE((VerifyResultOf<CallErase, NonTransparentTable>()));
1971
+ EXPECT_FALSE((VerifyResultOf<CallExtract, NonTransparentTable>()));
1972
+ EXPECT_FALSE((VerifyResultOf<CallPrefetch, NonTransparentTable>()));
1973
+ EXPECT_FALSE((VerifyResultOf<CallCount, NonTransparentTable>()));
1974
+
1975
+ using TransparentTable =
1976
+ raw_hash_set<StringPolicy, hash_default_hash<absl::string_view>,
1977
+ hash_default_eq<absl::string_view>, std::allocator<int>>;
1978
+
1979
+ EXPECT_TRUE((VerifyResultOf<CallFind, TransparentTable>()));
1980
+ EXPECT_TRUE((VerifyResultOf<CallErase, TransparentTable>()));
1981
+ EXPECT_TRUE((VerifyResultOf<CallExtract, TransparentTable>()));
1982
+ EXPECT_TRUE((VerifyResultOf<CallPrefetch, TransparentTable>()));
1983
+ EXPECT_TRUE((VerifyResultOf<CallCount, TransparentTable>()));
1984
+ }
1985
+
1986
+ TEST(Iterator, IsDefaultConstructible) {
1987
+ StringTable::iterator i;
1988
+ EXPECT_TRUE(i == StringTable::iterator());
1989
+ }
1990
+
1991
+ TEST(ConstIterator, IsDefaultConstructible) {
1992
+ StringTable::const_iterator i;
1993
+ EXPECT_TRUE(i == StringTable::const_iterator());
1994
+ }
1995
+
1996
+ TEST(Iterator, ConvertsToConstIterator) {
1997
+ StringTable::iterator i;
1998
+ EXPECT_TRUE(i == StringTable::const_iterator());
1999
+ }
2000
+
2001
+ TEST(Iterator, Iterates) {
2002
+ IntTable t;
2003
+ for (size_t i = 3; i != 6; ++i) EXPECT_TRUE(t.emplace(i).second);
2004
+ EXPECT_THAT(t, UnorderedElementsAre(3, 4, 5));
2005
+ }
2006
+
2007
+ TEST(Table, Merge) {
2008
+ StringTable t1, t2;
2009
+ t1.emplace("0", "-0");
2010
+ t1.emplace("1", "-1");
2011
+ t2.emplace("0", "~0");
2012
+ t2.emplace("2", "~2");
2013
+
2014
+ EXPECT_THAT(t1, UnorderedElementsAre(Pair("0", "-0"), Pair("1", "-1")));
2015
+ EXPECT_THAT(t2, UnorderedElementsAre(Pair("0", "~0"), Pair("2", "~2")));
2016
+
2017
+ t1.merge(t2);
2018
+ EXPECT_THAT(t1, UnorderedElementsAre(Pair("0", "-0"), Pair("1", "-1"),
2019
+ Pair("2", "~2")));
2020
+ EXPECT_THAT(t2, UnorderedElementsAre(Pair("0", "~0")));
2021
+ }
2022
+
2023
+ TEST(Table, IteratorEmplaceConstructibleRequirement) {
2024
+ struct Value {
2025
+ explicit Value(absl::string_view view) : value(view) {}
2026
+ std::string value;
2027
+
2028
+ bool operator==(const Value& other) const { return value == other.value; }
2029
+ };
2030
+ struct H {
2031
+ size_t operator()(const Value& v) const {
2032
+ return absl::Hash<std::string>{}(v.value);
2033
+ }
2034
+ };
2035
+
2036
+ struct Table : raw_hash_set<ValuePolicy<Value>, H, std::equal_to<Value>,
2037
+ std::allocator<Value>> {
2038
+ using Base = typename Table::raw_hash_set;
2039
+ using Base::Base;
2040
+ };
2041
+
2042
+ std::string input[3]{"A", "B", "C"};
2043
+
2044
+ Table t(std::begin(input), std::end(input));
2045
+ EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"}));
2046
+
2047
+ input[0] = "D";
2048
+ input[1] = "E";
2049
+ input[2] = "F";
2050
+ t.insert(std::begin(input), std::end(input));
2051
+ EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"},
2052
+ Value{"D"}, Value{"E"}, Value{"F"}));
2053
+ }
2054
+
2055
+ TEST(Nodes, EmptyNodeType) {
2056
+ using node_type = StringTable::node_type;
2057
+ node_type n;
2058
+ EXPECT_FALSE(n);
2059
+ EXPECT_TRUE(n.empty());
2060
+
2061
+ EXPECT_TRUE((std::is_same<node_type::allocator_type,
2062
+ StringTable::allocator_type>::value));
2063
+ }
2064
+
2065
+ TEST(Nodes, ExtractInsert) {
2066
+ constexpr char k0[] = "Very long string zero.";
2067
+ constexpr char k1[] = "Very long string one.";
2068
+ constexpr char k2[] = "Very long string two.";
2069
+ StringTable t = {{k0, ""}, {k1, ""}, {k2, ""}};
2070
+ EXPECT_THAT(t,
2071
+ UnorderedElementsAre(Pair(k0, ""), Pair(k1, ""), Pair(k2, "")));
2072
+
2073
+ auto node = t.extract(k0);
2074
+ EXPECT_THAT(t, UnorderedElementsAre(Pair(k1, ""), Pair(k2, "")));
2075
+ EXPECT_TRUE(node);
2076
+ EXPECT_FALSE(node.empty());
2077
+
2078
+ StringTable t2;
2079
+ StringTable::insert_return_type res = t2.insert(std::move(node));
2080
+ EXPECT_TRUE(res.inserted);
2081
+ EXPECT_THAT(*res.position, Pair(k0, ""));
2082
+ EXPECT_FALSE(res.node);
2083
+ EXPECT_THAT(t2, UnorderedElementsAre(Pair(k0, "")));
2084
+
2085
+ // Not there.
2086
+ EXPECT_THAT(t, UnorderedElementsAre(Pair(k1, ""), Pair(k2, "")));
2087
+ node = t.extract("Not there!");
2088
+ EXPECT_THAT(t, UnorderedElementsAre(Pair(k1, ""), Pair(k2, "")));
2089
+ EXPECT_FALSE(node);
2090
+
2091
+ // Inserting nothing.
2092
+ res = t2.insert(std::move(node));
2093
+ EXPECT_FALSE(res.inserted);
2094
+ EXPECT_EQ(res.position, t2.end());
2095
+ EXPECT_FALSE(res.node);
2096
+ EXPECT_THAT(t2, UnorderedElementsAre(Pair(k0, "")));
2097
+
2098
+ t.emplace(k0, "1");
2099
+ node = t.extract(k0);
2100
+
2101
+ // Insert duplicate.
2102
+ res = t2.insert(std::move(node));
2103
+ EXPECT_FALSE(res.inserted);
2104
+ EXPECT_THAT(*res.position, Pair(k0, ""));
2105
+ EXPECT_TRUE(res.node);
2106
+ EXPECT_FALSE(node); // NOLINT(bugprone-use-after-move)
2107
+ }
2108
+
2109
+ TEST(Nodes, HintInsert) {
2110
+ IntTable t = {1, 2, 3};
2111
+ auto node = t.extract(1);
2112
+ EXPECT_THAT(t, UnorderedElementsAre(2, 3));
2113
+ auto it = t.insert(t.begin(), std::move(node));
2114
+ EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3));
2115
+ EXPECT_EQ(*it, 1);
2116
+ EXPECT_FALSE(node); // NOLINT(bugprone-use-after-move)
2117
+
2118
+ node = t.extract(2);
2119
+ EXPECT_THAT(t, UnorderedElementsAre(1, 3));
2120
+ // reinsert 2 to make the next insert fail.
2121
+ t.insert(2);
2122
+ EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3));
2123
+ it = t.insert(t.begin(), std::move(node));
2124
+ EXPECT_EQ(*it, 2);
2125
+ // The node was not emptied by the insert call.
2126
+ EXPECT_TRUE(node); // NOLINT(bugprone-use-after-move)
2127
+ }
2128
+
2129
+ IntTable MakeSimpleTable(size_t size) {
2130
+ IntTable t;
2131
+ while (t.size() < size) t.insert(t.size());
2132
+ return t;
2133
+ }
2134
+
2135
+ std::vector<int> OrderOfIteration(const IntTable& t) {
2136
+ return {t.begin(), t.end()};
2137
+ }
2138
+
2139
+ // These IterationOrderChanges tests depend on non-deterministic behavior.
2140
+ // We are injecting non-determinism from the pointer of the table, but do so in
2141
+ // a way that only the page matters. We have to retry enough times to make sure
2142
+ // we are touching different memory pages to cause the ordering to change.
2143
+ // We also need to keep the old tables around to avoid getting the same memory
2144
+ // blocks over and over.
2145
+ TEST(Table, IterationOrderChangesByInstance) {
2146
+ for (size_t size : {2, 6, 12, 20}) {
2147
+ const auto reference_table = MakeSimpleTable(size);
2148
+ const auto reference = OrderOfIteration(reference_table);
2149
+
2150
+ std::vector<IntTable> tables;
2151
+ bool found_difference = false;
2152
+ for (int i = 0; !found_difference && i < 5000; ++i) {
2153
+ tables.push_back(MakeSimpleTable(size));
2154
+ found_difference = OrderOfIteration(tables.back()) != reference;
2155
+ }
2156
+ if (!found_difference) {
2157
+ FAIL()
2158
+ << "Iteration order remained the same across many attempts with size "
2159
+ << size;
2160
+ }
2161
+ }
2162
+ }
2163
+
2164
+ TEST(Table, IterationOrderChangesOnRehash) {
2165
+ std::vector<IntTable> garbage;
2166
+ for (int i = 0; i < 5000; ++i) {
2167
+ auto t = MakeSimpleTable(20);
2168
+ const auto reference = OrderOfIteration(t);
2169
+ // Force rehash to the same size.
2170
+ t.rehash(0);
2171
+ auto trial = OrderOfIteration(t);
2172
+ if (trial != reference) {
2173
+ // We are done.
2174
+ return;
2175
+ }
2176
+ garbage.push_back(std::move(t));
2177
+ }
2178
+ FAIL() << "Iteration order remained the same across many attempts.";
2179
+ }
2180
+
2181
+ // Verify that pointers are invalidated as soon as a second element is inserted.
2182
+ // This prevents dependency on pointer stability on small tables.
2183
+ TEST(Table, UnstablePointers) {
2184
+ IntTable table;
2185
+
2186
+ const auto addr = [&](int i) {
2187
+ return reinterpret_cast<uintptr_t>(&*table.find(i));
2188
+ };
2189
+
2190
+ table.insert(0);
2191
+ const uintptr_t old_ptr = addr(0);
2192
+
2193
+ // This causes a rehash.
2194
+ table.insert(1);
2195
+
2196
+ EXPECT_NE(old_ptr, addr(0));
2197
+ }
2198
+
2199
+ TEST(TableDeathTest, InvalidIteratorAsserts) {
2200
+ if (!IsAssertEnabled() && !SwisstableGenerationsEnabled())
2201
+ GTEST_SKIP() << "Assertions not enabled.";
2202
+
2203
+ IntTable t;
2204
+ // Extra simple "regexp" as regexp support is highly varied across platforms.
2205
+ EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()),
2206
+ "erase.* called on end.. iterator.");
2207
+ typename IntTable::iterator iter;
2208
+ EXPECT_DEATH_IF_SUPPORTED(
2209
+ ++iter, "operator.* called on default-constructed iterator.");
2210
+ t.insert(0);
2211
+ iter = t.begin();
2212
+ t.erase(iter);
2213
+ const char* const kErasedDeathMessage =
2214
+ SwisstableGenerationsEnabled()
2215
+ ? "operator.* called on invalid iterator.*was likely erased"
2216
+ : "operator.* called on invalid iterator.*might have been "
2217
+ "erased.*config=asan";
2218
+ EXPECT_DEATH_IF_SUPPORTED(++iter, kErasedDeathMessage);
2219
+ }
2220
+
2221
+ // Invalid iterator use can trigger use-after-free in asan/hwasan,
2222
+ // use-of-uninitialized-value in msan, or invalidated iterator assertions.
2223
+ constexpr const char* kInvalidIteratorDeathMessage =
2224
+ "use-after-free|use-of-uninitialized-value|invalidated "
2225
+ "iterator|Invalid iterator|invalid iterator";
2226
+
2227
+ // MSVC doesn't support | in regex.
2228
+ #if defined(_MSC_VER)
2229
+ constexpr bool kMsvc = true;
2230
+ #else
2231
+ constexpr bool kMsvc = false;
2232
+ #endif
2233
+
2234
+ TEST(TableDeathTest, IteratorInvalidAssertsEqualityOperator) {
2235
+ if (!IsAssertEnabled() && !SwisstableGenerationsEnabled())
2236
+ GTEST_SKIP() << "Assertions not enabled.";
2237
+
2238
+ IntTable t;
2239
+ t.insert(1);
2240
+ t.insert(2);
2241
+ t.insert(3);
2242
+ auto iter1 = t.begin();
2243
+ auto iter2 = std::next(iter1);
2244
+ ASSERT_NE(iter1, t.end());
2245
+ ASSERT_NE(iter2, t.end());
2246
+ t.erase(iter1);
2247
+ // Extra simple "regexp" as regexp support is highly varied across platforms.
2248
+ const char* const kErasedDeathMessage =
2249
+ SwisstableGenerationsEnabled()
2250
+ ? "Invalid iterator comparison.*was likely erased"
2251
+ : "Invalid iterator comparison.*might have been erased.*config=asan";
2252
+ EXPECT_DEATH_IF_SUPPORTED(void(iter1 == iter2), kErasedDeathMessage);
2253
+ EXPECT_DEATH_IF_SUPPORTED(void(iter2 != iter1), kErasedDeathMessage);
2254
+ t.erase(iter2);
2255
+ EXPECT_DEATH_IF_SUPPORTED(void(iter1 == iter2), kErasedDeathMessage);
2256
+
2257
+ IntTable t1, t2;
2258
+ t1.insert(0);
2259
+ t2.insert(0);
2260
+ iter1 = t1.begin();
2261
+ iter2 = t2.begin();
2262
+ const char* const kContainerDiffDeathMessage =
2263
+ SwisstableGenerationsEnabled()
2264
+ ? "Invalid iterator comparison.*iterators from different hashtables"
2265
+ : "Invalid iterator comparison.*may be from different "
2266
+ ".*containers.*config=asan";
2267
+ EXPECT_DEATH_IF_SUPPORTED(void(iter1 == iter2), kContainerDiffDeathMessage);
2268
+ EXPECT_DEATH_IF_SUPPORTED(void(iter2 == iter1), kContainerDiffDeathMessage);
2269
+
2270
+ for (int i = 0; i < 10; ++i) t1.insert(i);
2271
+ // There should have been a rehash in t1.
2272
+ if (kMsvc) return; // MSVC doesn't support | in regex.
2273
+
2274
+ // NOTE(b/293887834): After rehashing, iterators will contain pointers to
2275
+ // freed memory, which may be detected by ThreadSanitizer.
2276
+ const char* const kRehashedDeathMessage =
2277
+ SwisstableGenerationsEnabled()
2278
+ ? kInvalidIteratorDeathMessage
2279
+ : "Invalid iterator comparison.*might have rehashed.*config=asan"
2280
+ "|ThreadSanitizer: heap-use-after-free";
2281
+ EXPECT_DEATH_IF_SUPPORTED(void(iter1 == t1.begin()), kRehashedDeathMessage);
2282
+ }
2283
+
2284
+ #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
2285
+ TEST(RawHashSamplerTest, Sample) {
2286
+ // Enable the feature even if the prod default is off.
2287
+ SetHashtablezEnabled(true);
2288
+ SetHashtablezSampleParameter(100);
2289
+
2290
+ auto& sampler = GlobalHashtablezSampler();
2291
+ size_t start_size = 0;
2292
+ absl::flat_hash_set<const HashtablezInfo*> preexisting_info;
2293
+ start_size += sampler.Iterate([&](const HashtablezInfo& info) {
2294
+ preexisting_info.insert(&info);
2295
+ ++start_size;
2296
+ });
2297
+
2298
+ std::vector<IntTable> tables;
2299
+ for (int i = 0; i < 1000000; ++i) {
2300
+ tables.emplace_back();
2301
+
2302
+ const bool do_reserve = (i % 10 > 5);
2303
+ const bool do_rehash = !do_reserve && (i % 10 > 0);
2304
+
2305
+ if (do_reserve) {
2306
+ // Don't reserve on all tables.
2307
+ tables.back().reserve(10 * (i % 10));
2308
+ }
2309
+
2310
+ tables.back().insert(1);
2311
+ tables.back().insert(i % 5);
2312
+
2313
+ if (do_rehash) {
2314
+ // Rehash some other tables.
2315
+ tables.back().rehash(10 * (i % 10));
2316
+ }
2317
+ }
2318
+ size_t end_size = 0;
2319
+ absl::flat_hash_map<size_t, int> observed_checksums;
2320
+ absl::flat_hash_map<ssize_t, int> reservations;
2321
+ end_size += sampler.Iterate([&](const HashtablezInfo& info) {
2322
+ if (preexisting_info.count(&info) == 0) {
2323
+ observed_checksums[info.hashes_bitwise_xor.load(
2324
+ std::memory_order_relaxed)]++;
2325
+ reservations[info.max_reserve.load(std::memory_order_relaxed)]++;
2326
+ }
2327
+ EXPECT_EQ(info.inline_element_size, sizeof(int64_t));
2328
+ ++end_size;
2329
+ });
2330
+
2331
+ EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
2332
+ 0.01, 0.005);
2333
+ EXPECT_EQ(observed_checksums.size(), 5);
2334
+ for (const auto& [_, count] : observed_checksums) {
2335
+ EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.2, 0.05);
2336
+ }
2337
+
2338
+ EXPECT_EQ(reservations.size(), 10);
2339
+ for (const auto& [reservation, count] : reservations) {
2340
+ EXPECT_GE(reservation, 0);
2341
+ EXPECT_LT(reservation, 100);
2342
+
2343
+ EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.1, 0.05)
2344
+ << reservation;
2345
+ }
2346
+ }
2347
+ #endif // ABSL_INTERNAL_HASHTABLEZ_SAMPLE
2348
+
2349
+ TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) {
2350
+ // Enable the feature even if the prod default is off.
2351
+ SetHashtablezEnabled(true);
2352
+ SetHashtablezSampleParameter(100);
2353
+
2354
+ auto& sampler = GlobalHashtablezSampler();
2355
+ size_t start_size = 0;
2356
+ start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; });
2357
+
2358
+ std::vector<CustomAllocIntTable> tables;
2359
+ for (int i = 0; i < 1000000; ++i) {
2360
+ tables.emplace_back();
2361
+ tables.back().insert(1);
2362
+ }
2363
+ size_t end_size = 0;
2364
+ end_size += sampler.Iterate([&](const HashtablezInfo&) { ++end_size; });
2365
+
2366
+ EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
2367
+ 0.00, 0.001);
2368
+ }
2369
+
2370
+ #ifdef ABSL_HAVE_ADDRESS_SANITIZER
2371
+ template <class TableType>
2372
+ class SanitizerTest : public testing::Test {};
2373
+
2374
+ TYPED_TEST_SUITE_P(SanitizerTest);
2375
+
2376
+ TYPED_TEST_P(SanitizerTest, PoisoningUnused) {
2377
+ TypeParam t;
2378
+ for (size_t reserve_size = 2; reserve_size < 1024;
2379
+ reserve_size = reserve_size * 3 / 2) {
2380
+ t.reserve(reserve_size);
2381
+ // Insert something to force an allocation.
2382
+ int64_t& v = *t.insert(0).first;
2383
+
2384
+ // Make sure there is something to test.
2385
+ ASSERT_GT(t.capacity(), 1);
2386
+
2387
+ int64_t* slots = RawHashSetTestOnlyAccess::GetSlots(t);
2388
+ for (size_t i = 0; i < t.capacity(); ++i) {
2389
+ EXPECT_EQ(slots + i != &v, __asan_address_is_poisoned(slots + i)) << i;
2390
+ }
2391
+ }
2392
+ }
2393
+
2394
+ REGISTER_TYPED_TEST_SUITE_P(SanitizerTest, PoisoningUnused);
2395
+ using SanitizerTableTypes = ::testing::Types<IntTable, TransferableIntTable>;
2396
+ INSTANTIATE_TYPED_TEST_SUITE_P(InstanceSanitizerTest, SanitizerTest,
2397
+ SanitizerTableTypes);
2398
+
2399
+ TEST(Sanitizer, PoisoningOnErase) {
2400
+ IntTable t;
2401
+ int64_t& v = *t.insert(0).first;
2402
+
2403
+ EXPECT_FALSE(__asan_address_is_poisoned(&v));
2404
+ t.erase(0);
2405
+ EXPECT_TRUE(__asan_address_is_poisoned(&v));
2406
+ }
2407
+ #endif // ABSL_HAVE_ADDRESS_SANITIZER
2408
+
2409
+ template <typename T>
2410
+ class AlignOneTest : public ::testing::Test {};
2411
+ using AlignOneTestTypes =
2412
+ ::testing::Types<Uint8Table, MinimumAlignmentUint8Table>;
2413
+ TYPED_TEST_SUITE(AlignOneTest, AlignOneTestTypes);
2414
+
2415
+ TYPED_TEST(AlignOneTest, AlignOne) {
2416
+ // We previously had a bug in which we were copying a control byte over the
2417
+ // first slot when alignof(value_type) is 1. We test repeated
2418
+ // insertions/erases and verify that the behavior is correct.
2419
+ TypeParam t;
2420
+ std::unordered_set<uint8_t> verifier; // NOLINT
2421
+
2422
+ // Do repeated insertions/erases from the table.
2423
+ for (int64_t i = 0; i < 100000; ++i) {
2424
+ SCOPED_TRACE(i);
2425
+ const uint8_t u = (i * -i) & 0xFF;
2426
+ auto it = t.find(u);
2427
+ auto verifier_it = verifier.find(u);
2428
+ if (it == t.end()) {
2429
+ ASSERT_EQ(verifier_it, verifier.end());
2430
+ t.insert(u);
2431
+ verifier.insert(u);
2432
+ } else {
2433
+ ASSERT_NE(verifier_it, verifier.end());
2434
+ t.erase(it);
2435
+ verifier.erase(verifier_it);
2436
+ }
2437
+ }
2438
+
2439
+ EXPECT_EQ(t.size(), verifier.size());
2440
+ for (uint8_t u : t) {
2441
+ EXPECT_EQ(verifier.count(u), 1);
2442
+ }
2443
+ }
2444
+
2445
+ TEST(Iterator, InvalidUseCrashesWithSanitizers) {
2446
+ if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
2447
+ if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp.";
2448
+
2449
+ IntTable t;
2450
+ // Start with 1 element so that `it` is never an end iterator.
2451
+ t.insert(-1);
2452
+ for (int i = 0; i < 10; ++i) {
2453
+ auto it = t.begin();
2454
+ t.insert(i);
2455
+ EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
2456
+ EXPECT_DEATH_IF_SUPPORTED(void(it == t.begin()),
2457
+ kInvalidIteratorDeathMessage);
2458
+ }
2459
+ }
2460
+
2461
+ TEST(Iterator, InvalidUseWithReserveCrashesWithSanitizers) {
2462
+ if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
2463
+ if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp.";
2464
+
2465
+ IntTable t;
2466
+ t.reserve(10);
2467
+ t.insert(0);
2468
+ auto it = t.begin();
2469
+ // Reserved growth can't rehash.
2470
+ for (int i = 1; i < 10; ++i) {
2471
+ t.insert(i);
2472
+ EXPECT_EQ(*it, 0);
2473
+ }
2474
+ // ptr will become invalidated on rehash.
2475
+ const int64_t* ptr = &*it;
2476
+ (void)ptr;
2477
+
2478
+ // erase decreases size but does not decrease reserved growth so the next
2479
+ // insertion still invalidates iterators.
2480
+ t.erase(0);
2481
+ // The first insert after reserved growth is 0 is guaranteed to rehash when
2482
+ // generations are enabled.
2483
+ t.insert(10);
2484
+ EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
2485
+ EXPECT_DEATH_IF_SUPPORTED(void(it == t.begin()),
2486
+ kInvalidIteratorDeathMessage);
2487
+ #ifdef ABSL_HAVE_ADDRESS_SANITIZER
2488
+ EXPECT_DEATH_IF_SUPPORTED(std::cout << *ptr, "heap-use-after-free");
2489
+ #endif
2490
+ }
2491
+
2492
+ TEST(Iterator, InvalidUseWithMoveCrashesWithSanitizers) {
2493
+ if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
2494
+ if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp.";
2495
+
2496
+ IntTable t1, t2;
2497
+ t1.insert(1);
2498
+ auto it = t1.begin();
2499
+ // ptr will become invalidated on rehash.
2500
+ const int64_t* ptr = &*it;
2501
+ (void)ptr;
2502
+
2503
+ t2 = std::move(t1);
2504
+ EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
2505
+ EXPECT_DEATH_IF_SUPPORTED(void(it == t2.begin()),
2506
+ kInvalidIteratorDeathMessage);
2507
+ #ifdef ABSL_HAVE_ADDRESS_SANITIZER
2508
+ EXPECT_DEATH_IF_SUPPORTED(std::cout << *ptr, "heap-use-after-free");
2509
+ #endif
2510
+ }
2511
+
2512
+ TEST(Table, ReservedGrowthUpdatesWhenTableDoesntGrow) {
2513
+ IntTable t;
2514
+ for (int i = 0; i < 8; ++i) t.insert(i);
2515
+ // Want to insert twice without invalidating iterators so reserve.
2516
+ const size_t cap = t.capacity();
2517
+ t.reserve(t.size() + 2);
2518
+ // We want to be testing the case in which the reserve doesn't grow the table.
2519
+ ASSERT_EQ(cap, t.capacity());
2520
+ auto it = t.find(0);
2521
+ t.insert(100);
2522
+ t.insert(200);
2523
+ // `it` shouldn't have been invalidated.
2524
+ EXPECT_EQ(*it, 0);
2525
+ }
2526
+
2527
+ TEST(Table, EraseBeginEndResetsReservedGrowth) {
2528
+ bool frozen = false;
2529
+ BadHashFreezableIntTable t{FreezableAlloc<int64_t>(&frozen)};
2530
+ t.reserve(100);
2531
+ const size_t cap = t.capacity();
2532
+ frozen = true; // no further allocs allowed
2533
+
2534
+ for (int i = 0; i < 10; ++i) {
2535
+ // Create a long run (hash function returns constant).
2536
+ for (int j = 0; j < 100; ++j) t.insert(j);
2537
+ // Erase elements from the middle of the long run, which creates tombstones.
2538
+ for (int j = 30; j < 60; ++j) t.erase(j);
2539
+ EXPECT_EQ(t.size(), 70);
2540
+ EXPECT_EQ(t.capacity(), cap);
2541
+ ASSERT_EQ(RawHashSetTestOnlyAccess::CountTombstones(t), 30);
2542
+
2543
+ t.erase(t.begin(), t.end());
2544
+
2545
+ EXPECT_EQ(t.size(), 0);
2546
+ EXPECT_EQ(t.capacity(), cap);
2547
+ ASSERT_EQ(RawHashSetTestOnlyAccess::CountTombstones(t), 0);
2548
+ }
2549
+ }
2550
+
2551
+ TEST(Table, GenerationInfoResetsOnClear) {
2552
+ if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
2553
+ if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp.";
2554
+
2555
+ IntTable t;
2556
+ for (int i = 0; i < 1000; ++i) t.insert(i);
2557
+ t.reserve(t.size() + 100);
2558
+
2559
+ t.clear();
2560
+
2561
+ t.insert(0);
2562
+ auto it = t.begin();
2563
+ t.insert(1);
2564
+ EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
2565
+ }
2566
+
2567
+ TEST(Table, InvalidReferenceUseCrashesWithSanitizers) {
2568
+ if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
2569
+ #ifdef ABSL_HAVE_MEMORY_SANITIZER
2570
+ GTEST_SKIP() << "MSan fails to detect some of these rehashes.";
2571
+ #endif
2572
+
2573
+ IntTable t;
2574
+ t.insert(0);
2575
+ // Rehashing is guaranteed on every insertion while capacity is less than
2576
+ // RehashProbabilityConstant().
2577
+ int64_t i = 0;
2578
+ while (t.capacity() <= RehashProbabilityConstant()) {
2579
+ // ptr will become invalidated on rehash.
2580
+ const int64_t* ptr = &*t.begin();
2581
+ t.insert(++i);
2582
+ EXPECT_DEATH_IF_SUPPORTED(std::cout << *ptr, "use-after-free") << i;
2583
+ }
2584
+ }
2585
+
2586
+ TEST(Iterator, InvalidComparisonDifferentTables) {
2587
+ if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
2588
+
2589
+ IntTable t1, t2;
2590
+ IntTable::iterator default_constructed_iter;
2591
+ // We randomly use one of N empty generations for generations from empty
2592
+ // hashtables. In general, we won't always detect when iterators from
2593
+ // different empty hashtables are compared, but in this test case, we
2594
+ // should deterministically detect the error due to our randomness yielding
2595
+ // consecutive random generations.
2596
+ EXPECT_DEATH_IF_SUPPORTED(void(t1.end() == t2.end()),
2597
+ "Invalid iterator comparison.*empty hashtables");
2598
+ EXPECT_DEATH_IF_SUPPORTED(void(t1.end() == default_constructed_iter),
2599
+ "Invalid iterator comparison.*default-constructed");
2600
+ t1.insert(0);
2601
+ EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == t2.end()),
2602
+ "Invalid iterator comparison.*empty hashtable");
2603
+ EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == default_constructed_iter),
2604
+ "Invalid iterator comparison.*default-constructed");
2605
+ t2.insert(0);
2606
+ EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == t2.end()),
2607
+ "Invalid iterator comparison.*end.. iterator");
2608
+ EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == t2.begin()),
2609
+ "Invalid iterator comparison.*non-end");
2610
+ }
2611
+
2612
+ template <typename Alloc>
2613
+ using RawHashSetAlloc = raw_hash_set<IntPolicy, hash_default_hash<int64_t>,
2614
+ std::equal_to<int64_t>, Alloc>;
2615
+
2616
+ TEST(Table, AllocatorPropagation) { TestAllocPropagation<RawHashSetAlloc>(); }
2617
+
2618
+ struct CountedHash {
2619
+ size_t operator()(int value) const {
2620
+ ++count;
2621
+ return static_cast<size_t>(value);
2622
+ }
2623
+ mutable int count = 0;
2624
+ };
2625
+
2626
+ struct CountedHashIntTable
2627
+ : raw_hash_set<IntPolicy, CountedHash, std::equal_to<int>,
2628
+ std::allocator<int>> {
2629
+ using Base = typename CountedHashIntTable::raw_hash_set;
2630
+ using Base::Base;
2631
+ };
2632
+
2633
+ TEST(Table, CountedHash) {
2634
+ // Verify that raw_hash_set does not compute redundant hashes.
2635
+ #ifdef NDEBUG
2636
+ constexpr bool kExpectMinimumHashes = true;
2637
+ #else
2638
+ constexpr bool kExpectMinimumHashes = false;
2639
+ #endif
2640
+ if (!kExpectMinimumHashes) {
2641
+ GTEST_SKIP() << "Only run under NDEBUG: `assert` statements may cause "
2642
+ "redundant hashing.";
2643
+ }
2644
+
2645
+ using Table = CountedHashIntTable;
2646
+ auto HashCount = [](const Table& t) { return t.hash_function().count; };
2647
+ {
2648
+ Table t;
2649
+ EXPECT_EQ(HashCount(t), 0);
2650
+ }
2651
+ {
2652
+ Table t;
2653
+ t.insert(1);
2654
+ EXPECT_EQ(HashCount(t), 1);
2655
+ t.erase(1);
2656
+ EXPECT_EQ(HashCount(t), 2);
2657
+ }
2658
+ {
2659
+ Table t;
2660
+ t.insert(3);
2661
+ EXPECT_EQ(HashCount(t), 1);
2662
+ auto node = t.extract(3);
2663
+ EXPECT_EQ(HashCount(t), 2);
2664
+ t.insert(std::move(node));
2665
+ EXPECT_EQ(HashCount(t), 3);
2666
+ }
2667
+ {
2668
+ Table t;
2669
+ t.emplace(5);
2670
+ EXPECT_EQ(HashCount(t), 1);
2671
+ }
2672
+ {
2673
+ Table src;
2674
+ src.insert(7);
2675
+ Table dst;
2676
+ dst.merge(src);
2677
+ EXPECT_EQ(HashCount(dst), 1);
2678
+ }
2679
+ }
2680
+
2681
+ } // namespace
2682
+ } // namespace container_internal
2683
+ ABSL_NAMESPACE_END
2684
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/unordered_map_constructor_test.h ADDED
@@ -0,0 +1,494 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
16
+ #define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
17
+
18
+ #include <algorithm>
19
+ #include <unordered_map>
20
+ #include <vector>
21
+
22
+ #include "gmock/gmock.h"
23
+ #include "gtest/gtest.h"
24
+ #include "absl/container/internal/hash_generator_testing.h"
25
+ #include "absl/container/internal/hash_policy_testing.h"
26
+
27
+ namespace absl {
28
+ ABSL_NAMESPACE_BEGIN
29
+ namespace container_internal {
30
+
31
+ template <class UnordMap>
32
+ class ConstructorTest : public ::testing::Test {};
33
+
34
+ TYPED_TEST_SUITE_P(ConstructorTest);
35
+
36
+ TYPED_TEST_P(ConstructorTest, NoArgs) {
37
+ TypeParam m;
38
+ EXPECT_TRUE(m.empty());
39
+ EXPECT_THAT(m, ::testing::UnorderedElementsAre());
40
+ }
41
+
42
+ TYPED_TEST_P(ConstructorTest, BucketCount) {
43
+ TypeParam m(123);
44
+ EXPECT_TRUE(m.empty());
45
+ EXPECT_THAT(m, ::testing::UnorderedElementsAre());
46
+ EXPECT_GE(m.bucket_count(), 123);
47
+ }
48
+
49
+ TYPED_TEST_P(ConstructorTest, BucketCountHash) {
50
+ using H = typename TypeParam::hasher;
51
+ H hasher;
52
+ TypeParam m(123, hasher);
53
+ EXPECT_EQ(m.hash_function(), hasher);
54
+ EXPECT_TRUE(m.empty());
55
+ EXPECT_THAT(m, ::testing::UnorderedElementsAre());
56
+ EXPECT_GE(m.bucket_count(), 123);
57
+ }
58
+
59
+ TYPED_TEST_P(ConstructorTest, BucketCountHashEqual) {
60
+ using H = typename TypeParam::hasher;
61
+ using E = typename TypeParam::key_equal;
62
+ H hasher;
63
+ E equal;
64
+ TypeParam m(123, hasher, equal);
65
+ EXPECT_EQ(m.hash_function(), hasher);
66
+ EXPECT_EQ(m.key_eq(), equal);
67
+ EXPECT_TRUE(m.empty());
68
+ EXPECT_THAT(m, ::testing::UnorderedElementsAre());
69
+ EXPECT_GE(m.bucket_count(), 123);
70
+ }
71
+
72
+ TYPED_TEST_P(ConstructorTest, BucketCountHashEqualAlloc) {
73
+ using H = typename TypeParam::hasher;
74
+ using E = typename TypeParam::key_equal;
75
+ using A = typename TypeParam::allocator_type;
76
+ H hasher;
77
+ E equal;
78
+ A alloc(0);
79
+ TypeParam m(123, hasher, equal, alloc);
80
+ EXPECT_EQ(m.hash_function(), hasher);
81
+ EXPECT_EQ(m.key_eq(), equal);
82
+ EXPECT_EQ(m.get_allocator(), alloc);
83
+ EXPECT_TRUE(m.empty());
84
+ EXPECT_THAT(m, ::testing::UnorderedElementsAre());
85
+ EXPECT_GE(m.bucket_count(), 123);
86
+ }
87
+
88
+ template <typename T>
89
+ struct is_std_unordered_map : std::false_type {};
90
+
91
+ template <typename... T>
92
+ struct is_std_unordered_map<std::unordered_map<T...>> : std::true_type {};
93
+
94
+ #if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
95
+ using has_cxx14_std_apis = std::true_type;
96
+ #else
97
+ using has_cxx14_std_apis = std::false_type;
98
+ #endif
99
+
100
+ template <typename T>
101
+ using expect_cxx14_apis =
102
+ absl::disjunction<absl::negation<is_std_unordered_map<T>>,
103
+ has_cxx14_std_apis>;
104
+
105
+ template <typename TypeParam>
106
+ void BucketCountAllocTest(std::false_type) {}
107
+
108
+ template <typename TypeParam>
109
+ void BucketCountAllocTest(std::true_type) {
110
+ using A = typename TypeParam::allocator_type;
111
+ A alloc(0);
112
+ TypeParam m(123, alloc);
113
+ EXPECT_EQ(m.get_allocator(), alloc);
114
+ EXPECT_TRUE(m.empty());
115
+ EXPECT_THAT(m, ::testing::UnorderedElementsAre());
116
+ EXPECT_GE(m.bucket_count(), 123);
117
+ }
118
+
119
+ TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
120
+ BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
121
+ }
122
+
123
+ template <typename TypeParam>
124
+ void BucketCountHashAllocTest(std::false_type) {}
125
+
126
+ template <typename TypeParam>
127
+ void BucketCountHashAllocTest(std::true_type) {
128
+ using H = typename TypeParam::hasher;
129
+ using A = typename TypeParam::allocator_type;
130
+ H hasher;
131
+ A alloc(0);
132
+ TypeParam m(123, hasher, alloc);
133
+ EXPECT_EQ(m.hash_function(), hasher);
134
+ EXPECT_EQ(m.get_allocator(), alloc);
135
+ EXPECT_TRUE(m.empty());
136
+ EXPECT_THAT(m, ::testing::UnorderedElementsAre());
137
+ EXPECT_GE(m.bucket_count(), 123);
138
+ }
139
+
140
+ TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
141
+ BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
142
+ }
143
+
144
+ #if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
145
+ using has_alloc_std_constructors = std::true_type;
146
+ #else
147
+ using has_alloc_std_constructors = std::false_type;
148
+ #endif
149
+
150
+ template <typename T>
151
+ using expect_alloc_constructors =
152
+ absl::disjunction<absl::negation<is_std_unordered_map<T>>,
153
+ has_alloc_std_constructors>;
154
+
155
+ template <typename TypeParam>
156
+ void AllocTest(std::false_type) {}
157
+
158
+ template <typename TypeParam>
159
+ void AllocTest(std::true_type) {
160
+ using A = typename TypeParam::allocator_type;
161
+ A alloc(0);
162
+ TypeParam m(alloc);
163
+ EXPECT_EQ(m.get_allocator(), alloc);
164
+ EXPECT_TRUE(m.empty());
165
+ EXPECT_THAT(m, ::testing::UnorderedElementsAre());
166
+ }
167
+
168
+ TYPED_TEST_P(ConstructorTest, Alloc) {
169
+ AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
170
+ }
171
+
172
+ TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
173
+ using T = hash_internal::GeneratedType<TypeParam>;
174
+ using H = typename TypeParam::hasher;
175
+ using E = typename TypeParam::key_equal;
176
+ using A = typename TypeParam::allocator_type;
177
+ H hasher;
178
+ E equal;
179
+ A alloc(0);
180
+ std::vector<T> values;
181
+ std::generate_n(std::back_inserter(values), 10,
182
+ hash_internal::UniqueGenerator<T>());
183
+ TypeParam m(values.begin(), values.end(), 123, hasher, equal, alloc);
184
+ EXPECT_EQ(m.hash_function(), hasher);
185
+ EXPECT_EQ(m.key_eq(), equal);
186
+ EXPECT_EQ(m.get_allocator(), alloc);
187
+ EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
188
+ EXPECT_GE(m.bucket_count(), 123);
189
+ }
190
+
191
+ template <typename TypeParam>
192
+ void InputIteratorBucketAllocTest(std::false_type) {}
193
+
194
+ template <typename TypeParam>
195
+ void InputIteratorBucketAllocTest(std::true_type) {
196
+ using T = hash_internal::GeneratedType<TypeParam>;
197
+ using A = typename TypeParam::allocator_type;
198
+ A alloc(0);
199
+ std::vector<T> values;
200
+ std::generate_n(std::back_inserter(values), 10,
201
+ hash_internal::UniqueGenerator<T>());
202
+ TypeParam m(values.begin(), values.end(), 123, alloc);
203
+ EXPECT_EQ(m.get_allocator(), alloc);
204
+ EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
205
+ EXPECT_GE(m.bucket_count(), 123);
206
+ }
207
+
208
+ TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
209
+ InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
210
+ }
211
+
212
+ template <typename TypeParam>
213
+ void InputIteratorBucketHashAllocTest(std::false_type) {}
214
+
215
+ template <typename TypeParam>
216
+ void InputIteratorBucketHashAllocTest(std::true_type) {
217
+ using T = hash_internal::GeneratedType<TypeParam>;
218
+ using H = typename TypeParam::hasher;
219
+ using A = typename TypeParam::allocator_type;
220
+ H hasher;
221
+ A alloc(0);
222
+ std::vector<T> values;
223
+ std::generate_n(std::back_inserter(values), 10,
224
+ hash_internal::UniqueGenerator<T>());
225
+ TypeParam m(values.begin(), values.end(), 123, hasher, alloc);
226
+ EXPECT_EQ(m.hash_function(), hasher);
227
+ EXPECT_EQ(m.get_allocator(), alloc);
228
+ EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
229
+ EXPECT_GE(m.bucket_count(), 123);
230
+ }
231
+
232
+ TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
233
+ InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
234
+ }
235
+
236
+ TYPED_TEST_P(ConstructorTest, CopyConstructor) {
237
+ using T = hash_internal::GeneratedType<TypeParam>;
238
+ using H = typename TypeParam::hasher;
239
+ using E = typename TypeParam::key_equal;
240
+ using A = typename TypeParam::allocator_type;
241
+ H hasher;
242
+ E equal;
243
+ A alloc(0);
244
+ hash_internal::UniqueGenerator<T> gen;
245
+ TypeParam m(123, hasher, equal, alloc);
246
+ for (size_t i = 0; i != 10; ++i) m.insert(gen());
247
+ TypeParam n(m);
248
+ EXPECT_EQ(m.hash_function(), n.hash_function());
249
+ EXPECT_EQ(m.key_eq(), n.key_eq());
250
+ EXPECT_EQ(m.get_allocator(), n.get_allocator());
251
+ EXPECT_EQ(m, n);
252
+ }
253
+
254
+ template <typename TypeParam>
255
+ void CopyConstructorAllocTest(std::false_type) {}
256
+
257
+ template <typename TypeParam>
258
+ void CopyConstructorAllocTest(std::true_type) {
259
+ using T = hash_internal::GeneratedType<TypeParam>;
260
+ using H = typename TypeParam::hasher;
261
+ using E = typename TypeParam::key_equal;
262
+ using A = typename TypeParam::allocator_type;
263
+ H hasher;
264
+ E equal;
265
+ A alloc(0);
266
+ hash_internal::UniqueGenerator<T> gen;
267
+ TypeParam m(123, hasher, equal, alloc);
268
+ for (size_t i = 0; i != 10; ++i) m.insert(gen());
269
+ TypeParam n(m, A(11));
270
+ EXPECT_EQ(m.hash_function(), n.hash_function());
271
+ EXPECT_EQ(m.key_eq(), n.key_eq());
272
+ EXPECT_NE(m.get_allocator(), n.get_allocator());
273
+ EXPECT_EQ(m, n);
274
+ }
275
+
276
+ TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
277
+ CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
278
+ }
279
+
280
+ // TODO(alkis): Test non-propagating allocators on copy constructors.
281
+
282
+ TYPED_TEST_P(ConstructorTest, MoveConstructor) {
283
+ using T = hash_internal::GeneratedType<TypeParam>;
284
+ using H = typename TypeParam::hasher;
285
+ using E = typename TypeParam::key_equal;
286
+ using A = typename TypeParam::allocator_type;
287
+ H hasher;
288
+ E equal;
289
+ A alloc(0);
290
+ hash_internal::UniqueGenerator<T> gen;
291
+ TypeParam m(123, hasher, equal, alloc);
292
+ for (size_t i = 0; i != 10; ++i) m.insert(gen());
293
+ TypeParam t(m);
294
+ TypeParam n(std::move(t));
295
+ EXPECT_EQ(m.hash_function(), n.hash_function());
296
+ EXPECT_EQ(m.key_eq(), n.key_eq());
297
+ EXPECT_EQ(m.get_allocator(), n.get_allocator());
298
+ EXPECT_EQ(m, n);
299
+ }
300
+
301
+ template <typename TypeParam>
302
+ void MoveConstructorAllocTest(std::false_type) {}
303
+
304
+ template <typename TypeParam>
305
+ void MoveConstructorAllocTest(std::true_type) {
306
+ using T = hash_internal::GeneratedType<TypeParam>;
307
+ using H = typename TypeParam::hasher;
308
+ using E = typename TypeParam::key_equal;
309
+ using A = typename TypeParam::allocator_type;
310
+ H hasher;
311
+ E equal;
312
+ A alloc(0);
313
+ hash_internal::UniqueGenerator<T> gen;
314
+ TypeParam m(123, hasher, equal, alloc);
315
+ for (size_t i = 0; i != 10; ++i) m.insert(gen());
316
+ TypeParam t(m);
317
+ TypeParam n(std::move(t), A(1));
318
+ EXPECT_EQ(m.hash_function(), n.hash_function());
319
+ EXPECT_EQ(m.key_eq(), n.key_eq());
320
+ EXPECT_NE(m.get_allocator(), n.get_allocator());
321
+ EXPECT_EQ(m, n);
322
+ }
323
+
324
+ TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
325
+ MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
326
+ }
327
+
328
+ // TODO(alkis): Test non-propagating allocators on move constructors.
329
+
330
+ TYPED_TEST_P(ConstructorTest, InitializerListBucketHashEqualAlloc) {
331
+ using T = hash_internal::GeneratedType<TypeParam>;
332
+ hash_internal::UniqueGenerator<T> gen;
333
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
334
+ using H = typename TypeParam::hasher;
335
+ using E = typename TypeParam::key_equal;
336
+ using A = typename TypeParam::allocator_type;
337
+ H hasher;
338
+ E equal;
339
+ A alloc(0);
340
+ TypeParam m(values, 123, hasher, equal, alloc);
341
+ EXPECT_EQ(m.hash_function(), hasher);
342
+ EXPECT_EQ(m.key_eq(), equal);
343
+ EXPECT_EQ(m.get_allocator(), alloc);
344
+ EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
345
+ EXPECT_GE(m.bucket_count(), 123);
346
+ }
347
+
348
+ template <typename TypeParam>
349
+ void InitializerListBucketAllocTest(std::false_type) {}
350
+
351
+ template <typename TypeParam>
352
+ void InitializerListBucketAllocTest(std::true_type) {
353
+ using T = hash_internal::GeneratedType<TypeParam>;
354
+ using A = typename TypeParam::allocator_type;
355
+ hash_internal::UniqueGenerator<T> gen;
356
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
357
+ A alloc(0);
358
+ TypeParam m(values, 123, alloc);
359
+ EXPECT_EQ(m.get_allocator(), alloc);
360
+ EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
361
+ EXPECT_GE(m.bucket_count(), 123);
362
+ }
363
+
364
+ TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
365
+ InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
366
+ }
367
+
368
+ template <typename TypeParam>
369
+ void InitializerListBucketHashAllocTest(std::false_type) {}
370
+
371
+ template <typename TypeParam>
372
+ void InitializerListBucketHashAllocTest(std::true_type) {
373
+ using T = hash_internal::GeneratedType<TypeParam>;
374
+ using H = typename TypeParam::hasher;
375
+ using A = typename TypeParam::allocator_type;
376
+ H hasher;
377
+ A alloc(0);
378
+ hash_internal::UniqueGenerator<T> gen;
379
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
380
+ TypeParam m(values, 123, hasher, alloc);
381
+ EXPECT_EQ(m.hash_function(), hasher);
382
+ EXPECT_EQ(m.get_allocator(), alloc);
383
+ EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
384
+ EXPECT_GE(m.bucket_count(), 123);
385
+ }
386
+
387
+ TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
388
+ InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
389
+ }
390
+
391
+ TYPED_TEST_P(ConstructorTest, Assignment) {
392
+ using T = hash_internal::GeneratedType<TypeParam>;
393
+ using H = typename TypeParam::hasher;
394
+ using E = typename TypeParam::key_equal;
395
+ using A = typename TypeParam::allocator_type;
396
+ H hasher;
397
+ E equal;
398
+ A alloc(0);
399
+ hash_internal::UniqueGenerator<T> gen;
400
+ TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
401
+ TypeParam n;
402
+ n = m;
403
+ EXPECT_EQ(m.hash_function(), n.hash_function());
404
+ EXPECT_EQ(m.key_eq(), n.key_eq());
405
+ EXPECT_EQ(m, n);
406
+ }
407
+
408
+ // TODO(alkis): Test [non-]propagating allocators on move/copy assignments
409
+ // (it depends on traits).
410
+
411
+ TYPED_TEST_P(ConstructorTest, MoveAssignment) {
412
+ using T = hash_internal::GeneratedType<TypeParam>;
413
+ using H = typename TypeParam::hasher;
414
+ using E = typename TypeParam::key_equal;
415
+ using A = typename TypeParam::allocator_type;
416
+ H hasher;
417
+ E equal;
418
+ A alloc(0);
419
+ hash_internal::UniqueGenerator<T> gen;
420
+ TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
421
+ TypeParam t(m);
422
+ TypeParam n;
423
+ n = std::move(t);
424
+ EXPECT_EQ(m.hash_function(), n.hash_function());
425
+ EXPECT_EQ(m.key_eq(), n.key_eq());
426
+ EXPECT_EQ(m, n);
427
+ }
428
+
429
+ TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerList) {
430
+ using T = hash_internal::GeneratedType<TypeParam>;
431
+ hash_internal::UniqueGenerator<T> gen;
432
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
433
+ TypeParam m;
434
+ m = values;
435
+ EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
436
+ }
437
+
438
+ TYPED_TEST_P(ConstructorTest, AssignmentOverwritesExisting) {
439
+ using T = hash_internal::GeneratedType<TypeParam>;
440
+ hash_internal::UniqueGenerator<T> gen;
441
+ TypeParam m({gen(), gen(), gen()});
442
+ TypeParam n({gen()});
443
+ n = m;
444
+ EXPECT_EQ(m, n);
445
+ }
446
+
447
+ TYPED_TEST_P(ConstructorTest, MoveAssignmentOverwritesExisting) {
448
+ using T = hash_internal::GeneratedType<TypeParam>;
449
+ hash_internal::UniqueGenerator<T> gen;
450
+ TypeParam m({gen(), gen(), gen()});
451
+ TypeParam t(m);
452
+ TypeParam n({gen()});
453
+ n = std::move(t);
454
+ EXPECT_EQ(m, n);
455
+ }
456
+
457
+ TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerListOverwritesExisting) {
458
+ using T = hash_internal::GeneratedType<TypeParam>;
459
+ hash_internal::UniqueGenerator<T> gen;
460
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
461
+ TypeParam m;
462
+ m = values;
463
+ EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
464
+ }
465
+
466
+ TYPED_TEST_P(ConstructorTest, AssignmentOnSelf) {
467
+ using T = hash_internal::GeneratedType<TypeParam>;
468
+ hash_internal::UniqueGenerator<T> gen;
469
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
470
+ TypeParam m(values);
471
+ m = *&m; // Avoid -Wself-assign
472
+ EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
473
+ }
474
+
475
+ // We cannot test self move as standard states that it leaves standard
476
+ // containers in unspecified state (and in practice in causes memory-leak
477
+ // according to heap-checker!).
478
+
479
+ REGISTER_TYPED_TEST_SUITE_P(
480
+ ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual,
481
+ BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc,
482
+ InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
483
+ InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc,
484
+ MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc,
485
+ InitializerListBucketAlloc, InitializerListBucketHashAlloc, Assignment,
486
+ MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting,
487
+ MoveAssignmentOverwritesExisting,
488
+ AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf);
489
+
490
+ } // namespace container_internal
491
+ ABSL_NAMESPACE_END
492
+ } // namespace absl
493
+
494
+ #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
weight/_dep/abseil-cpp/absl/container/internal/unordered_map_members_test.h ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2019 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
16
+ #define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
17
+
18
+ #include <type_traits>
19
+ #include "gmock/gmock.h"
20
+ #include "gtest/gtest.h"
21
+ #include "absl/meta/type_traits.h"
22
+
23
+ namespace absl {
24
+ ABSL_NAMESPACE_BEGIN
25
+ namespace container_internal {
26
+
27
+ template <class UnordMap>
28
+ class MembersTest : public ::testing::Test {};
29
+
30
+ TYPED_TEST_SUITE_P(MembersTest);
31
+
32
+ template <typename T>
33
+ void UseType() {}
34
+
35
+ TYPED_TEST_P(MembersTest, Typedefs) {
36
+ EXPECT_TRUE((std::is_same<std::pair<const typename TypeParam::key_type,
37
+ typename TypeParam::mapped_type>,
38
+ typename TypeParam::value_type>()));
39
+ EXPECT_TRUE((absl::conjunction<
40
+ absl::negation<std::is_signed<typename TypeParam::size_type>>,
41
+ std::is_integral<typename TypeParam::size_type>>()));
42
+ EXPECT_TRUE((absl::conjunction<
43
+ std::is_signed<typename TypeParam::difference_type>,
44
+ std::is_integral<typename TypeParam::difference_type>>()));
45
+ EXPECT_TRUE((std::is_convertible<
46
+ decltype(std::declval<const typename TypeParam::hasher&>()(
47
+ std::declval<const typename TypeParam::key_type&>())),
48
+ size_t>()));
49
+ EXPECT_TRUE((std::is_convertible<
50
+ decltype(std::declval<const typename TypeParam::key_equal&>()(
51
+ std::declval<const typename TypeParam::key_type&>(),
52
+ std::declval<const typename TypeParam::key_type&>())),
53
+ bool>()));
54
+ EXPECT_TRUE((std::is_same<typename TypeParam::allocator_type::value_type,
55
+ typename TypeParam::value_type>()));
56
+ EXPECT_TRUE((std::is_same<typename TypeParam::value_type&,
57
+ typename TypeParam::reference>()));
58
+ EXPECT_TRUE((std::is_same<const typename TypeParam::value_type&,
59
+ typename TypeParam::const_reference>()));
60
+ EXPECT_TRUE((std::is_same<typename std::allocator_traits<
61
+ typename TypeParam::allocator_type>::pointer,
62
+ typename TypeParam::pointer>()));
63
+ EXPECT_TRUE(
64
+ (std::is_same<typename std::allocator_traits<
65
+ typename TypeParam::allocator_type>::const_pointer,
66
+ typename TypeParam::const_pointer>()));
67
+ }
68
+
69
+ TYPED_TEST_P(MembersTest, SimpleFunctions) {
70
+ EXPECT_GT(TypeParam().max_size(), 0);
71
+ }
72
+
73
+ TYPED_TEST_P(MembersTest, BeginEnd) {
74
+ TypeParam t = {typename TypeParam::value_type{}};
75
+ EXPECT_EQ(t.begin(), t.cbegin());
76
+ EXPECT_EQ(t.end(), t.cend());
77
+ EXPECT_NE(t.begin(), t.end());
78
+ EXPECT_NE(t.cbegin(), t.cend());
79
+ }
80
+
81
+ REGISTER_TYPED_TEST_SUITE_P(MembersTest, Typedefs, SimpleFunctions, BeginEnd);
82
+
83
+ } // namespace container_internal
84
+ ABSL_NAMESPACE_END
85
+ } // namespace absl
86
+
87
+ #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
weight/_dep/abseil-cpp/absl/container/internal/unordered_map_test.cc ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include <memory>
16
+ #include <unordered_map>
17
+
18
+ #include "absl/container/internal/unordered_map_constructor_test.h"
19
+ #include "absl/container/internal/unordered_map_lookup_test.h"
20
+ #include "absl/container/internal/unordered_map_members_test.h"
21
+ #include "absl/container/internal/unordered_map_modifiers_test.h"
22
+
23
+ namespace absl {
24
+ ABSL_NAMESPACE_BEGIN
25
+ namespace container_internal {
26
+ namespace {
27
+
28
+ using MapTypes = ::testing::Types<
29
+ std::unordered_map<int, int, StatefulTestingHash, StatefulTestingEqual,
30
+ Alloc<std::pair<const int, int>>>,
31
+ std::unordered_map<std::string, std::string, StatefulTestingHash,
32
+ StatefulTestingEqual,
33
+ Alloc<std::pair<const std::string, std::string>>>>;
34
+
35
+ INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, ConstructorTest, MapTypes);
36
+ INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, LookupTest, MapTypes);
37
+ INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, MembersTest, MapTypes);
38
+ INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, ModifiersTest, MapTypes);
39
+
40
+ using UniquePtrMapTypes = ::testing::Types<std::unordered_map<
41
+ int, std::unique_ptr<int>, StatefulTestingHash, StatefulTestingEqual,
42
+ Alloc<std::pair<const int, std::unique_ptr<int>>>>>;
43
+
44
+ INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, UniquePtrModifiersTest,
45
+ UniquePtrMapTypes);
46
+
47
+ } // namespace
48
+ } // namespace container_internal
49
+ ABSL_NAMESPACE_END
50
+ } // namespace absl
weight/_dep/abseil-cpp/absl/container/internal/unordered_set_constructor_test.h ADDED
@@ -0,0 +1,496 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_
16
+ #define ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_
17
+
18
+ #include <algorithm>
19
+ #include <unordered_set>
20
+ #include <vector>
21
+
22
+ #include "gmock/gmock.h"
23
+ #include "gtest/gtest.h"
24
+ #include "absl/container/internal/hash_generator_testing.h"
25
+ #include "absl/container/internal/hash_policy_testing.h"
26
+ #include "absl/meta/type_traits.h"
27
+
28
+ namespace absl {
29
+ ABSL_NAMESPACE_BEGIN
30
+ namespace container_internal {
31
+
32
+ template <class UnordMap>
33
+ class ConstructorTest : public ::testing::Test {};
34
+
35
+ TYPED_TEST_SUITE_P(ConstructorTest);
36
+
37
+ TYPED_TEST_P(ConstructorTest, NoArgs) {
38
+ TypeParam m;
39
+ EXPECT_TRUE(m.empty());
40
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
41
+ }
42
+
43
+ TYPED_TEST_P(ConstructorTest, BucketCount) {
44
+ TypeParam m(123);
45
+ EXPECT_TRUE(m.empty());
46
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
47
+ EXPECT_GE(m.bucket_count(), 123);
48
+ }
49
+
50
+ TYPED_TEST_P(ConstructorTest, BucketCountHash) {
51
+ using H = typename TypeParam::hasher;
52
+ H hasher;
53
+ TypeParam m(123, hasher);
54
+ EXPECT_EQ(m.hash_function(), hasher);
55
+ EXPECT_TRUE(m.empty());
56
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
57
+ EXPECT_GE(m.bucket_count(), 123);
58
+ }
59
+
60
+ TYPED_TEST_P(ConstructorTest, BucketCountHashEqual) {
61
+ using H = typename TypeParam::hasher;
62
+ using E = typename TypeParam::key_equal;
63
+ H hasher;
64
+ E equal;
65
+ TypeParam m(123, hasher, equal);
66
+ EXPECT_EQ(m.hash_function(), hasher);
67
+ EXPECT_EQ(m.key_eq(), equal);
68
+ EXPECT_TRUE(m.empty());
69
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
70
+ EXPECT_GE(m.bucket_count(), 123);
71
+ }
72
+
73
+ TYPED_TEST_P(ConstructorTest, BucketCountHashEqualAlloc) {
74
+ using H = typename TypeParam::hasher;
75
+ using E = typename TypeParam::key_equal;
76
+ using A = typename TypeParam::allocator_type;
77
+ H hasher;
78
+ E equal;
79
+ A alloc(0);
80
+ TypeParam m(123, hasher, equal, alloc);
81
+ EXPECT_EQ(m.hash_function(), hasher);
82
+ EXPECT_EQ(m.key_eq(), equal);
83
+ EXPECT_EQ(m.get_allocator(), alloc);
84
+ EXPECT_TRUE(m.empty());
85
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
86
+ EXPECT_GE(m.bucket_count(), 123);
87
+
88
+ const auto& cm = m;
89
+ EXPECT_EQ(cm.hash_function(), hasher);
90
+ EXPECT_EQ(cm.key_eq(), equal);
91
+ EXPECT_EQ(cm.get_allocator(), alloc);
92
+ EXPECT_TRUE(cm.empty());
93
+ EXPECT_THAT(keys(cm), ::testing::UnorderedElementsAre());
94
+ EXPECT_GE(cm.bucket_count(), 123);
95
+ }
96
+
97
+ template <typename T>
98
+ struct is_std_unordered_set : std::false_type {};
99
+
100
+ template <typename... T>
101
+ struct is_std_unordered_set<std::unordered_set<T...>> : std::true_type {};
102
+
103
+ #if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
104
+ using has_cxx14_std_apis = std::true_type;
105
+ #else
106
+ using has_cxx14_std_apis = std::false_type;
107
+ #endif
108
+
109
+ template <typename T>
110
+ using expect_cxx14_apis =
111
+ absl::disjunction<absl::negation<is_std_unordered_set<T>>,
112
+ has_cxx14_std_apis>;
113
+
114
+ template <typename TypeParam>
115
+ void BucketCountAllocTest(std::false_type) {}
116
+
117
+ template <typename TypeParam>
118
+ void BucketCountAllocTest(std::true_type) {
119
+ using A = typename TypeParam::allocator_type;
120
+ A alloc(0);
121
+ TypeParam m(123, alloc);
122
+ EXPECT_EQ(m.get_allocator(), alloc);
123
+ EXPECT_TRUE(m.empty());
124
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
125
+ EXPECT_GE(m.bucket_count(), 123);
126
+ }
127
+
128
+ TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
129
+ BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
130
+ }
131
+
132
+ template <typename TypeParam>
133
+ void BucketCountHashAllocTest(std::false_type) {}
134
+
135
+ template <typename TypeParam>
136
+ void BucketCountHashAllocTest(std::true_type) {
137
+ using H = typename TypeParam::hasher;
138
+ using A = typename TypeParam::allocator_type;
139
+ H hasher;
140
+ A alloc(0);
141
+ TypeParam m(123, hasher, alloc);
142
+ EXPECT_EQ(m.hash_function(), hasher);
143
+ EXPECT_EQ(m.get_allocator(), alloc);
144
+ EXPECT_TRUE(m.empty());
145
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
146
+ EXPECT_GE(m.bucket_count(), 123);
147
+ }
148
+
149
+ TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
150
+ BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
151
+ }
152
+
153
+ #if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
154
+ using has_alloc_std_constructors = std::true_type;
155
+ #else
156
+ using has_alloc_std_constructors = std::false_type;
157
+ #endif
158
+
159
+ template <typename T>
160
+ using expect_alloc_constructors =
161
+ absl::disjunction<absl::negation<is_std_unordered_set<T>>,
162
+ has_alloc_std_constructors>;
163
+
164
+ template <typename TypeParam>
165
+ void AllocTest(std::false_type) {}
166
+
167
+ template <typename TypeParam>
168
+ void AllocTest(std::true_type) {
169
+ using A = typename TypeParam::allocator_type;
170
+ A alloc(0);
171
+ TypeParam m(alloc);
172
+ EXPECT_EQ(m.get_allocator(), alloc);
173
+ EXPECT_TRUE(m.empty());
174
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
175
+ }
176
+
177
+ TYPED_TEST_P(ConstructorTest, Alloc) {
178
+ AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
179
+ }
180
+
181
+ TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
182
+ using T = hash_internal::GeneratedType<TypeParam>;
183
+ using H = typename TypeParam::hasher;
184
+ using E = typename TypeParam::key_equal;
185
+ using A = typename TypeParam::allocator_type;
186
+ H hasher;
187
+ E equal;
188
+ A alloc(0);
189
+ std::vector<T> values;
190
+ for (size_t i = 0; i != 10; ++i)
191
+ values.push_back(hash_internal::Generator<T>()());
192
+ TypeParam m(values.begin(), values.end(), 123, hasher, equal, alloc);
193
+ EXPECT_EQ(m.hash_function(), hasher);
194
+ EXPECT_EQ(m.key_eq(), equal);
195
+ EXPECT_EQ(m.get_allocator(), alloc);
196
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
197
+ EXPECT_GE(m.bucket_count(), 123);
198
+ }
199
+
200
+ template <typename TypeParam>
201
+ void InputIteratorBucketAllocTest(std::false_type) {}
202
+
203
+ template <typename TypeParam>
204
+ void InputIteratorBucketAllocTest(std::true_type) {
205
+ using T = hash_internal::GeneratedType<TypeParam>;
206
+ using A = typename TypeParam::allocator_type;
207
+ A alloc(0);
208
+ std::vector<T> values;
209
+ for (size_t i = 0; i != 10; ++i)
210
+ values.push_back(hash_internal::Generator<T>()());
211
+ TypeParam m(values.begin(), values.end(), 123, alloc);
212
+ EXPECT_EQ(m.get_allocator(), alloc);
213
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
214
+ EXPECT_GE(m.bucket_count(), 123);
215
+ }
216
+
217
+ TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
218
+ InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
219
+ }
220
+
221
+ template <typename TypeParam>
222
+ void InputIteratorBucketHashAllocTest(std::false_type) {}
223
+
224
+ template <typename TypeParam>
225
+ void InputIteratorBucketHashAllocTest(std::true_type) {
226
+ using T = hash_internal::GeneratedType<TypeParam>;
227
+ using H = typename TypeParam::hasher;
228
+ using A = typename TypeParam::allocator_type;
229
+ H hasher;
230
+ A alloc(0);
231
+ std::vector<T> values;
232
+ for (size_t i = 0; i != 10; ++i)
233
+ values.push_back(hash_internal::Generator<T>()());
234
+ TypeParam m(values.begin(), values.end(), 123, hasher, alloc);
235
+ EXPECT_EQ(m.hash_function(), hasher);
236
+ EXPECT_EQ(m.get_allocator(), alloc);
237
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
238
+ EXPECT_GE(m.bucket_count(), 123);
239
+ }
240
+
241
+ TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
242
+ InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
243
+ }
244
+
245
+ TYPED_TEST_P(ConstructorTest, CopyConstructor) {
246
+ using T = hash_internal::GeneratedType<TypeParam>;
247
+ using H = typename TypeParam::hasher;
248
+ using E = typename TypeParam::key_equal;
249
+ using A = typename TypeParam::allocator_type;
250
+ H hasher;
251
+ E equal;
252
+ A alloc(0);
253
+ TypeParam m(123, hasher, equal, alloc);
254
+ for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
255
+ TypeParam n(m);
256
+ EXPECT_EQ(m.hash_function(), n.hash_function());
257
+ EXPECT_EQ(m.key_eq(), n.key_eq());
258
+ EXPECT_EQ(m.get_allocator(), n.get_allocator());
259
+ EXPECT_EQ(m, n);
260
+ EXPECT_NE(TypeParam(0, hasher, equal, alloc), n);
261
+ }
262
+
263
+ template <typename TypeParam>
264
+ void CopyConstructorAllocTest(std::false_type) {}
265
+
266
+ template <typename TypeParam>
267
+ void CopyConstructorAllocTest(std::true_type) {
268
+ using T = hash_internal::GeneratedType<TypeParam>;
269
+ using H = typename TypeParam::hasher;
270
+ using E = typename TypeParam::key_equal;
271
+ using A = typename TypeParam::allocator_type;
272
+ H hasher;
273
+ E equal;
274
+ A alloc(0);
275
+ TypeParam m(123, hasher, equal, alloc);
276
+ for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
277
+ TypeParam n(m, A(11));
278
+ EXPECT_EQ(m.hash_function(), n.hash_function());
279
+ EXPECT_EQ(m.key_eq(), n.key_eq());
280
+ EXPECT_NE(m.get_allocator(), n.get_allocator());
281
+ EXPECT_EQ(m, n);
282
+ }
283
+
284
+ TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
285
+ CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
286
+ }
287
+
288
+ // TODO(alkis): Test non-propagating allocators on copy constructors.
289
+
290
+ TYPED_TEST_P(ConstructorTest, MoveConstructor) {
291
+ using T = hash_internal::GeneratedType<TypeParam>;
292
+ using H = typename TypeParam::hasher;
293
+ using E = typename TypeParam::key_equal;
294
+ using A = typename TypeParam::allocator_type;
295
+ H hasher;
296
+ E equal;
297
+ A alloc(0);
298
+ TypeParam m(123, hasher, equal, alloc);
299
+ for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
300
+ TypeParam t(m);
301
+ TypeParam n(std::move(t));
302
+ EXPECT_EQ(m.hash_function(), n.hash_function());
303
+ EXPECT_EQ(m.key_eq(), n.key_eq());
304
+ EXPECT_EQ(m.get_allocator(), n.get_allocator());
305
+ EXPECT_EQ(m, n);
306
+ }
307
+
308
+ template <typename TypeParam>
309
+ void MoveConstructorAllocTest(std::false_type) {}
310
+
311
+ template <typename TypeParam>
312
+ void MoveConstructorAllocTest(std::true_type) {
313
+ using T = hash_internal::GeneratedType<TypeParam>;
314
+ using H = typename TypeParam::hasher;
315
+ using E = typename TypeParam::key_equal;
316
+ using A = typename TypeParam::allocator_type;
317
+ H hasher;
318
+ E equal;
319
+ A alloc(0);
320
+ TypeParam m(123, hasher, equal, alloc);
321
+ for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
322
+ TypeParam t(m);
323
+ TypeParam n(std::move(t), A(1));
324
+ EXPECT_EQ(m.hash_function(), n.hash_function());
325
+ EXPECT_EQ(m.key_eq(), n.key_eq());
326
+ EXPECT_NE(m.get_allocator(), n.get_allocator());
327
+ EXPECT_EQ(m, n);
328
+ }
329
+
330
+ TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
331
+ MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
332
+ }
333
+
334
+ // TODO(alkis): Test non-propagating allocators on move constructors.
335
+
336
+ TYPED_TEST_P(ConstructorTest, InitializerListBucketHashEqualAlloc) {
337
+ using T = hash_internal::GeneratedType<TypeParam>;
338
+ hash_internal::Generator<T> gen;
339
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
340
+ using H = typename TypeParam::hasher;
341
+ using E = typename TypeParam::key_equal;
342
+ using A = typename TypeParam::allocator_type;
343
+ H hasher;
344
+ E equal;
345
+ A alloc(0);
346
+ TypeParam m(values, 123, hasher, equal, alloc);
347
+ EXPECT_EQ(m.hash_function(), hasher);
348
+ EXPECT_EQ(m.key_eq(), equal);
349
+ EXPECT_EQ(m.get_allocator(), alloc);
350
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
351
+ EXPECT_GE(m.bucket_count(), 123);
352
+ }
353
+
354
+ template <typename TypeParam>
355
+ void InitializerListBucketAllocTest(std::false_type) {}
356
+
357
+ template <typename TypeParam>
358
+ void InitializerListBucketAllocTest(std::true_type) {
359
+ using T = hash_internal::GeneratedType<TypeParam>;
360
+ using A = typename TypeParam::allocator_type;
361
+ hash_internal::Generator<T> gen;
362
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
363
+ A alloc(0);
364
+ TypeParam m(values, 123, alloc);
365
+ EXPECT_EQ(m.get_allocator(), alloc);
366
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
367
+ EXPECT_GE(m.bucket_count(), 123);
368
+ }
369
+
370
+ TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
371
+ InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
372
+ }
373
+
374
+ template <typename TypeParam>
375
+ void InitializerListBucketHashAllocTest(std::false_type) {}
376
+
377
+ template <typename TypeParam>
378
+ void InitializerListBucketHashAllocTest(std::true_type) {
379
+ using T = hash_internal::GeneratedType<TypeParam>;
380
+ using H = typename TypeParam::hasher;
381
+ using A = typename TypeParam::allocator_type;
382
+ H hasher;
383
+ A alloc(0);
384
+ hash_internal::Generator<T> gen;
385
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
386
+ TypeParam m(values, 123, hasher, alloc);
387
+ EXPECT_EQ(m.hash_function(), hasher);
388
+ EXPECT_EQ(m.get_allocator(), alloc);
389
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
390
+ EXPECT_GE(m.bucket_count(), 123);
391
+ }
392
+
393
+ TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
394
+ InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
395
+ }
396
+
397
+ TYPED_TEST_P(ConstructorTest, CopyAssignment) {
398
+ using T = hash_internal::GeneratedType<TypeParam>;
399
+ using H = typename TypeParam::hasher;
400
+ using E = typename TypeParam::key_equal;
401
+ using A = typename TypeParam::allocator_type;
402
+ H hasher;
403
+ E equal;
404
+ A alloc(0);
405
+ hash_internal::Generator<T> gen;
406
+ TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
407
+ TypeParam n;
408
+ n = m;
409
+ EXPECT_EQ(m.hash_function(), n.hash_function());
410
+ EXPECT_EQ(m.key_eq(), n.key_eq());
411
+ EXPECT_EQ(m, n);
412
+ }
413
+
414
+ // TODO(alkis): Test [non-]propagating allocators on move/copy assignments
415
+ // (it depends on traits).
416
+
417
+ TYPED_TEST_P(ConstructorTest, MoveAssignment) {
418
+ using T = hash_internal::GeneratedType<TypeParam>;
419
+ using H = typename TypeParam::hasher;
420
+ using E = typename TypeParam::key_equal;
421
+ using A = typename TypeParam::allocator_type;
422
+ H hasher;
423
+ E equal;
424
+ A alloc(0);
425
+ hash_internal::Generator<T> gen;
426
+ TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
427
+ TypeParam t(m);
428
+ TypeParam n;
429
+ n = std::move(t);
430
+ EXPECT_EQ(m.hash_function(), n.hash_function());
431
+ EXPECT_EQ(m.key_eq(), n.key_eq());
432
+ EXPECT_EQ(m, n);
433
+ }
434
+
435
+ TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerList) {
436
+ using T = hash_internal::GeneratedType<TypeParam>;
437
+ hash_internal::Generator<T> gen;
438
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
439
+ TypeParam m;
440
+ m = values;
441
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
442
+ }
443
+
444
+ TYPED_TEST_P(ConstructorTest, AssignmentOverwritesExisting) {
445
+ using T = hash_internal::GeneratedType<TypeParam>;
446
+ hash_internal::Generator<T> gen;
447
+ TypeParam m({gen(), gen(), gen()});
448
+ TypeParam n({gen()});
449
+ n = m;
450
+ EXPECT_EQ(m, n);
451
+ }
452
+
453
+ TYPED_TEST_P(ConstructorTest, MoveAssignmentOverwritesExisting) {
454
+ using T = hash_internal::GeneratedType<TypeParam>;
455
+ hash_internal::Generator<T> gen;
456
+ TypeParam m({gen(), gen(), gen()});
457
+ TypeParam t(m);
458
+ TypeParam n({gen()});
459
+ n = std::move(t);
460
+ EXPECT_EQ(m, n);
461
+ }
462
+
463
+ TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerListOverwritesExisting) {
464
+ using T = hash_internal::GeneratedType<TypeParam>;
465
+ hash_internal::Generator<T> gen;
466
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
467
+ TypeParam m;
468
+ m = values;
469
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
470
+ }
471
+
472
+ TYPED_TEST_P(ConstructorTest, AssignmentOnSelf) {
473
+ using T = hash_internal::GeneratedType<TypeParam>;
474
+ hash_internal::Generator<T> gen;
475
+ std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
476
+ TypeParam m(values);
477
+ m = *&m; // Avoid -Wself-assign.
478
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
479
+ }
480
+
481
+ REGISTER_TYPED_TEST_SUITE_P(
482
+ ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual,
483
+ BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc,
484
+ InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
485
+ InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc,
486
+ MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc,
487
+ InitializerListBucketAlloc, InitializerListBucketHashAlloc, CopyAssignment,
488
+ MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting,
489
+ MoveAssignmentOverwritesExisting,
490
+ AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf);
491
+
492
+ } // namespace container_internal
493
+ ABSL_NAMESPACE_END
494
+ } // namespace absl
495
+
496
+ #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_
weight/_dep/abseil-cpp/absl/container/internal/unordered_set_lookup_test.h ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_SET_LOOKUP_TEST_H_
16
+ #define ABSL_CONTAINER_INTERNAL_UNORDERED_SET_LOOKUP_TEST_H_
17
+
18
+ #include "gmock/gmock.h"
19
+ #include "gtest/gtest.h"
20
+ #include "absl/container/internal/hash_generator_testing.h"
21
+ #include "absl/container/internal/hash_policy_testing.h"
22
+
23
+ namespace absl {
24
+ ABSL_NAMESPACE_BEGIN
25
+ namespace container_internal {
26
+
27
+ template <class UnordSet>
28
+ class LookupTest : public ::testing::Test {};
29
+
30
+ TYPED_TEST_SUITE_P(LookupTest);
31
+
32
+ TYPED_TEST_P(LookupTest, Count) {
33
+ using T = hash_internal::GeneratedType<TypeParam>;
34
+ std::vector<T> values;
35
+ std::generate_n(std::back_inserter(values), 10,
36
+ hash_internal::Generator<T>());
37
+ TypeParam m;
38
+ for (const auto& v : values)
39
+ EXPECT_EQ(0, m.count(v)) << ::testing::PrintToString(v);
40
+ m.insert(values.begin(), values.end());
41
+ for (const auto& v : values)
42
+ EXPECT_EQ(1, m.count(v)) << ::testing::PrintToString(v);
43
+ }
44
+
45
+ TYPED_TEST_P(LookupTest, Find) {
46
+ using T = hash_internal::GeneratedType<TypeParam>;
47
+ std::vector<T> values;
48
+ std::generate_n(std::back_inserter(values), 10,
49
+ hash_internal::Generator<T>());
50
+ TypeParam m;
51
+ for (const auto& v : values)
52
+ EXPECT_TRUE(m.end() == m.find(v)) << ::testing::PrintToString(v);
53
+ m.insert(values.begin(), values.end());
54
+ for (const auto& v : values) {
55
+ typename TypeParam::iterator it = m.find(v);
56
+ static_assert(std::is_same<const typename TypeParam::value_type&,
57
+ decltype(*it)>::value,
58
+ "");
59
+ static_assert(std::is_same<const typename TypeParam::value_type*,
60
+ decltype(it.operator->())>::value,
61
+ "");
62
+ EXPECT_TRUE(m.end() != it) << ::testing::PrintToString(v);
63
+ EXPECT_EQ(v, *it) << ::testing::PrintToString(v);
64
+ }
65
+ }
66
+
67
+ TYPED_TEST_P(LookupTest, EqualRange) {
68
+ using T = hash_internal::GeneratedType<TypeParam>;
69
+ std::vector<T> values;
70
+ std::generate_n(std::back_inserter(values), 10,
71
+ hash_internal::Generator<T>());
72
+ TypeParam m;
73
+ for (const auto& v : values) {
74
+ auto r = m.equal_range(v);
75
+ ASSERT_EQ(0, std::distance(r.first, r.second));
76
+ }
77
+ m.insert(values.begin(), values.end());
78
+ for (const auto& v : values) {
79
+ auto r = m.equal_range(v);
80
+ ASSERT_EQ(1, std::distance(r.first, r.second));
81
+ EXPECT_EQ(v, *r.first);
82
+ }
83
+ }
84
+
85
+ REGISTER_TYPED_TEST_SUITE_P(LookupTest, Count, Find, EqualRange);
86
+
87
+ } // namespace container_internal
88
+ ABSL_NAMESPACE_END
89
+ } // namespace absl
90
+
91
+ #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_LOOKUP_TEST_H_
weight/_dep/abseil-cpp/absl/container/internal/unordered_set_modifiers_test.h ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MODIFIERS_TEST_H_
16
+ #define ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MODIFIERS_TEST_H_
17
+
18
+ #include "gmock/gmock.h"
19
+ #include "gtest/gtest.h"
20
+ #include "absl/container/internal/hash_generator_testing.h"
21
+ #include "absl/container/internal/hash_policy_testing.h"
22
+
23
+ namespace absl {
24
+ ABSL_NAMESPACE_BEGIN
25
+ namespace container_internal {
26
+
27
+ template <class UnordSet>
28
+ class ModifiersTest : public ::testing::Test {};
29
+
30
+ TYPED_TEST_SUITE_P(ModifiersTest);
31
+
32
+ TYPED_TEST_P(ModifiersTest, Clear) {
33
+ using T = hash_internal::GeneratedType<TypeParam>;
34
+ std::vector<T> values;
35
+ std::generate_n(std::back_inserter(values), 10,
36
+ hash_internal::Generator<T>());
37
+ TypeParam m(values.begin(), values.end());
38
+ ASSERT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
39
+ m.clear();
40
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
41
+ EXPECT_TRUE(m.empty());
42
+ }
43
+
44
+ TYPED_TEST_P(ModifiersTest, Insert) {
45
+ using T = hash_internal::GeneratedType<TypeParam>;
46
+ T val = hash_internal::Generator<T>()();
47
+ TypeParam m;
48
+ auto p = m.insert(val);
49
+ EXPECT_TRUE(p.second);
50
+ EXPECT_EQ(val, *p.first);
51
+ p = m.insert(val);
52
+ EXPECT_FALSE(p.second);
53
+ }
54
+
55
+ TYPED_TEST_P(ModifiersTest, InsertHint) {
56
+ using T = hash_internal::GeneratedType<TypeParam>;
57
+ T val = hash_internal::Generator<T>()();
58
+ TypeParam m;
59
+ auto it = m.insert(m.end(), val);
60
+ EXPECT_TRUE(it != m.end());
61
+ EXPECT_EQ(val, *it);
62
+ it = m.insert(it, val);
63
+ EXPECT_TRUE(it != m.end());
64
+ EXPECT_EQ(val, *it);
65
+ }
66
+
67
+ TYPED_TEST_P(ModifiersTest, InsertRange) {
68
+ using T = hash_internal::GeneratedType<TypeParam>;
69
+ std::vector<T> values;
70
+ std::generate_n(std::back_inserter(values), 10,
71
+ hash_internal::Generator<T>());
72
+ TypeParam m;
73
+ m.insert(values.begin(), values.end());
74
+ ASSERT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
75
+ }
76
+
77
+ TYPED_TEST_P(ModifiersTest, InsertWithinCapacity) {
78
+ using T = hash_internal::GeneratedType<TypeParam>;
79
+ T val = hash_internal::Generator<T>()();
80
+ TypeParam m;
81
+ m.reserve(10);
82
+ const size_t original_capacity = m.bucket_count();
83
+ m.insert(val);
84
+ EXPECT_EQ(m.bucket_count(), original_capacity);
85
+ m.insert(val);
86
+ EXPECT_EQ(m.bucket_count(), original_capacity);
87
+ }
88
+
89
+ TYPED_TEST_P(ModifiersTest, InsertRangeWithinCapacity) {
90
+ #if !defined(__GLIBCXX__)
91
+ using T = hash_internal::GeneratedType<TypeParam>;
92
+ std::vector<T> base_values;
93
+ std::generate_n(std::back_inserter(base_values), 10,
94
+ hash_internal::Generator<T>());
95
+ std::vector<T> values;
96
+ while (values.size() != 100) {
97
+ values.insert(values.end(), base_values.begin(), base_values.end());
98
+ }
99
+ TypeParam m;
100
+ m.reserve(10);
101
+ const size_t original_capacity = m.bucket_count();
102
+ m.insert(values.begin(), values.end());
103
+ EXPECT_EQ(m.bucket_count(), original_capacity);
104
+ #endif
105
+ }
106
+
107
+ TYPED_TEST_P(ModifiersTest, Emplace) {
108
+ using T = hash_internal::GeneratedType<TypeParam>;
109
+ T val = hash_internal::Generator<T>()();
110
+ TypeParam m;
111
+ // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
112
+ // with test traits/policy.
113
+ auto p = m.emplace(val);
114
+ EXPECT_TRUE(p.second);
115
+ EXPECT_EQ(val, *p.first);
116
+ p = m.emplace(val);
117
+ EXPECT_FALSE(p.second);
118
+ EXPECT_EQ(val, *p.first);
119
+ }
120
+
121
+ TYPED_TEST_P(ModifiersTest, EmplaceHint) {
122
+ using T = hash_internal::GeneratedType<TypeParam>;
123
+ T val = hash_internal::Generator<T>()();
124
+ TypeParam m;
125
+ // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
126
+ // with test traits/policy.
127
+ auto it = m.emplace_hint(m.end(), val);
128
+ EXPECT_EQ(val, *it);
129
+ it = m.emplace_hint(it, val);
130
+ EXPECT_EQ(val, *it);
131
+ }
132
+
133
+ template <class V>
134
+ using IfNotVoid = typename std::enable_if<!std::is_void<V>::value, V>::type;
135
+
136
+ // In openmap we chose not to return the iterator from erase because that's
137
+ // more expensive. As such we adapt erase to return an iterator here.
138
+ struct EraseFirst {
139
+ template <class Map>
140
+ auto operator()(Map* m, int) const
141
+ -> IfNotVoid<decltype(m->erase(m->begin()))> {
142
+ return m->erase(m->begin());
143
+ }
144
+ template <class Map>
145
+ typename Map::iterator operator()(Map* m, ...) const {
146
+ auto it = m->begin();
147
+ m->erase(it++);
148
+ return it;
149
+ }
150
+ };
151
+
152
+ TYPED_TEST_P(ModifiersTest, Erase) {
153
+ using T = hash_internal::GeneratedType<TypeParam>;
154
+ std::vector<T> values;
155
+ std::generate_n(std::back_inserter(values), 10,
156
+ hash_internal::Generator<T>());
157
+ TypeParam m(values.begin(), values.end());
158
+ ASSERT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
159
+ std::vector<T> values2;
160
+ for (const auto& val : values)
161
+ if (val != *m.begin()) values2.push_back(val);
162
+ auto it = EraseFirst()(&m, 0);
163
+ ASSERT_TRUE(it != m.end());
164
+ EXPECT_EQ(1, std::count(values2.begin(), values2.end(), *it));
165
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values2.begin(),
166
+ values2.end()));
167
+ }
168
+
169
+ TYPED_TEST_P(ModifiersTest, EraseRange) {
170
+ using T = hash_internal::GeneratedType<TypeParam>;
171
+ std::vector<T> values;
172
+ std::generate_n(std::back_inserter(values), 10,
173
+ hash_internal::Generator<T>());
174
+ TypeParam m(values.begin(), values.end());
175
+ ASSERT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
176
+ auto it = m.erase(m.begin(), m.end());
177
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
178
+ EXPECT_TRUE(it == m.end());
179
+ }
180
+
181
+ TYPED_TEST_P(ModifiersTest, EraseKey) {
182
+ using T = hash_internal::GeneratedType<TypeParam>;
183
+ std::vector<T> values;
184
+ std::generate_n(std::back_inserter(values), 10,
185
+ hash_internal::Generator<T>());
186
+ TypeParam m(values.begin(), values.end());
187
+ ASSERT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
188
+ EXPECT_EQ(1, m.erase(values[0]));
189
+ EXPECT_EQ(0, std::count(m.begin(), m.end(), values[0]));
190
+ EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values.begin() + 1,
191
+ values.end()));
192
+ }
193
+
194
+ TYPED_TEST_P(ModifiersTest, Swap) {
195
+ using T = hash_internal::GeneratedType<TypeParam>;
196
+ std::vector<T> v1;
197
+ std::vector<T> v2;
198
+ std::generate_n(std::back_inserter(v1), 5, hash_internal::Generator<T>());
199
+ std::generate_n(std::back_inserter(v2), 5, hash_internal::Generator<T>());
200
+ TypeParam m1(v1.begin(), v1.end());
201
+ TypeParam m2(v2.begin(), v2.end());
202
+ EXPECT_THAT(keys(m1), ::testing::UnorderedElementsAreArray(v1));
203
+ EXPECT_THAT(keys(m2), ::testing::UnorderedElementsAreArray(v2));
204
+ m1.swap(m2);
205
+ EXPECT_THAT(keys(m1), ::testing::UnorderedElementsAreArray(v2));
206
+ EXPECT_THAT(keys(m2), ::testing::UnorderedElementsAreArray(v1));
207
+ }
208
+
209
+ // TODO(alkis): Write tests for extract.
210
+ // TODO(alkis): Write tests for merge.
211
+
212
+ REGISTER_TYPED_TEST_SUITE_P(ModifiersTest, Clear, Insert, InsertHint,
213
+ InsertRange, InsertWithinCapacity,
214
+ InsertRangeWithinCapacity, Emplace, EmplaceHint,
215
+ Erase, EraseRange, EraseKey, Swap);
216
+
217
+ } // namespace container_internal
218
+ ABSL_NAMESPACE_END
219
+ } // namespace absl
220
+
221
+ #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MODIFIERS_TEST_H_
weight/_dep/abseil-cpp/absl/container/internal/unordered_set_test.cc ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include <unordered_set>
16
+
17
+ #include "absl/container/internal/unordered_set_constructor_test.h"
18
+ #include "absl/container/internal/unordered_set_lookup_test.h"
19
+ #include "absl/container/internal/unordered_set_members_test.h"
20
+ #include "absl/container/internal/unordered_set_modifiers_test.h"
21
+
22
+ namespace absl {
23
+ ABSL_NAMESPACE_BEGIN
24
+ namespace container_internal {
25
+ namespace {
26
+
27
+ using SetTypes = ::testing::Types<
28
+ std::unordered_set<int, StatefulTestingHash, StatefulTestingEqual,
29
+ Alloc<int>>,
30
+ std::unordered_set<std::string, StatefulTestingHash, StatefulTestingEqual,
31
+ Alloc<std::string>>>;
32
+
33
+ INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, ConstructorTest, SetTypes);
34
+ INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, LookupTest, SetTypes);
35
+ INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, MembersTest, SetTypes);
36
+ INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, ModifiersTest, SetTypes);
37
+
38
+ } // namespace
39
+ } // namespace container_internal
40
+ ABSL_NAMESPACE_END
41
+ } // namespace absl
weight/_dep/abseil-cpp/absl/crc/crc32c.h ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // -----------------------------------------------------------------------------
16
+ // File: crc32c.h
17
+ // -----------------------------------------------------------------------------
18
+ //
19
+ // This header file defines the API for computing CRC32C values as checksums
20
+ // for arbitrary sequences of bytes provided as a string buffer.
21
+ //
22
+ // The API includes the basic functions for computing such CRC32C values and
23
+ // some utility functions for performing more efficient mathematical
24
+ // computations using an existing checksum.
25
+ #ifndef ABSL_CRC_CRC32C_H_
26
+ #define ABSL_CRC_CRC32C_H_
27
+
28
+ #include <cstdint>
29
+ #include <ostream>
30
+
31
+ #include "absl/crc/internal/crc32c_inline.h"
32
+ #include "absl/strings/str_format.h"
33
+ #include "absl/strings/string_view.h"
34
+
35
+ namespace absl {
36
+ ABSL_NAMESPACE_BEGIN
37
+
38
+ //-----------------------------------------------------------------------------
39
+ // crc32c_t
40
+ //-----------------------------------------------------------------------------
41
+
42
+ // `crc32c_t` defines a strongly-typed integer for holding a CRC32C value.
43
+ //
44
+ // Some operators are intentionally omitted. Only equality operators are defined
45
+ // so that `crc32c_t` can be directly compared. Methods for putting `crc32c_t`
46
+ // directly into a set are omitted because this is bug-prone due to checksum
47
+ // collisions. Use an explicit conversion to the `uint32_t` space for operations
48
+ // that treat `crc32c_t` as an integer.
49
+ class crc32c_t final {
50
+ public:
51
+ crc32c_t() = default;
52
+ constexpr explicit crc32c_t(uint32_t crc) : crc_(crc) {}
53
+
54
+ crc32c_t(const crc32c_t&) = default;
55
+ crc32c_t& operator=(const crc32c_t&) = default;
56
+
57
+ explicit operator uint32_t() const { return crc_; }
58
+
59
+ friend bool operator==(crc32c_t lhs, crc32c_t rhs) {
60
+ return static_cast<uint32_t>(lhs) == static_cast<uint32_t>(rhs);
61
+ }
62
+
63
+ friend bool operator!=(crc32c_t lhs, crc32c_t rhs) { return !(lhs == rhs); }
64
+
65
+ template <typename Sink>
66
+ friend void AbslStringify(Sink& sink, crc32c_t crc) {
67
+ absl::Format(&sink, "%08x", static_cast<uint32_t>(crc));
68
+ }
69
+
70
+ private:
71
+ uint32_t crc_;
72
+ };
73
+
74
+
75
+ namespace crc_internal {
76
+ // Non-inline code path for `absl::ExtendCrc32c()`. Do not call directly.
77
+ // Call `absl::ExtendCrc32c()` (defined below) instead.
78
+ crc32c_t ExtendCrc32cInternal(crc32c_t initial_crc,
79
+ absl::string_view buf_to_add);
80
+ } // namespace crc_internal
81
+
82
+ // -----------------------------------------------------------------------------
83
+ // CRC32C Computation Functions
84
+ // -----------------------------------------------------------------------------
85
+
86
+ // ComputeCrc32c()
87
+ //
88
+ // Returns the CRC32C value of the provided string.
89
+ crc32c_t ComputeCrc32c(absl::string_view buf);
90
+
91
+ // ExtendCrc32c()
92
+ //
93
+ // Computes a CRC32C value from an `initial_crc` CRC32C value including the
94
+ // `buf_to_add` bytes of an additional buffer. Using this function is more
95
+ // efficient than computing a CRC32C value for the combined buffer from
96
+ // scratch.
97
+ //
98
+ // Note: `ExtendCrc32c` with an initial_crc of 0 is equivalent to
99
+ // `ComputeCrc32c`.
100
+ //
101
+ // This operation has a runtime cost of O(`buf_to_add.size()`)
102
+ inline crc32c_t ExtendCrc32c(crc32c_t initial_crc,
103
+ absl::string_view buf_to_add) {
104
+ // Approximately 75% of calls have size <= 64.
105
+ if (buf_to_add.size() <= 64) {
106
+ uint32_t crc = static_cast<uint32_t>(initial_crc);
107
+ if (crc_internal::ExtendCrc32cInline(&crc, buf_to_add.data(),
108
+ buf_to_add.size())) {
109
+ return crc32c_t{crc};
110
+ }
111
+ }
112
+ return crc_internal::ExtendCrc32cInternal(initial_crc, buf_to_add);
113
+ }
114
+
115
+ // ExtendCrc32cByZeroes()
116
+ //
117
+ // Computes a CRC32C value for a buffer with an `initial_crc` CRC32C value,
118
+ // where `length` bytes with a value of 0 are appended to the buffer. Using this
119
+ // function is more efficient than computing a CRC32C value for the combined
120
+ // buffer from scratch.
121
+ //
122
+ // This operation has a runtime cost of O(log(`length`))
123
+ crc32c_t ExtendCrc32cByZeroes(crc32c_t initial_crc, size_t length);
124
+
125
+ // MemcpyCrc32c()
126
+ //
127
+ // Copies `src` to `dest` using `memcpy()` semantics, returning the CRC32C
128
+ // value of the copied buffer.
129
+ //
130
+ // Using `MemcpyCrc32c()` is potentially faster than performing the `memcpy()`
131
+ // and `ComputeCrc32c()` operations separately.
132
+ crc32c_t MemcpyCrc32c(void* dest, const void* src, size_t count,
133
+ crc32c_t initial_crc = crc32c_t{0});
134
+
135
+ // -----------------------------------------------------------------------------
136
+ // CRC32C Arithmetic Functions
137
+ // -----------------------------------------------------------------------------
138
+
139
+ // The following functions perform arithmetic on CRC32C values, which are
140
+ // generally more efficient than recalculating any given result's CRC32C value.
141
+
142
+ // ConcatCrc32c()
143
+ //
144
+ // Calculates the CRC32C value of two buffers with known CRC32C values
145
+ // concatenated together.
146
+ //
147
+ // Given a buffer with CRC32C value `crc1` and a buffer with
148
+ // CRC32C value `crc2` and length, `crc2_length`, returns the CRC32C value of
149
+ // the concatenation of these two buffers.
150
+ //
151
+ // This operation has a runtime cost of O(log(`crc2_length`)).
152
+ crc32c_t ConcatCrc32c(crc32c_t crc1, crc32c_t crc2, size_t crc2_length);
153
+
154
+ // RemoveCrc32cPrefix()
155
+ //
156
+ // Calculates the CRC32C value of an existing buffer with a series of bytes
157
+ // (the prefix) removed from the beginning of that buffer.
158
+ //
159
+ // Given the CRC32C value of an existing buffer, `full_string_crc`; The CRC32C
160
+ // value of a prefix of that buffer, `prefix_crc`; and the length of the buffer
161
+ // with the prefix removed, `remaining_string_length` , return the CRC32C
162
+ // value of the buffer with the prefix removed.
163
+ //
164
+ // This operation has a runtime cost of O(log(`remaining_string_length`)).
165
+ crc32c_t RemoveCrc32cPrefix(crc32c_t prefix_crc, crc32c_t full_string_crc,
166
+ size_t remaining_string_length);
167
+ // RemoveCrc32cSuffix()
168
+ //
169
+ // Calculates the CRC32C value of an existing buffer with a series of bytes
170
+ // (the suffix) removed from the end of that buffer.
171
+ //
172
+ // Given a CRC32C value of an existing buffer `full_string_crc`, the CRC32C
173
+ // value of the suffix to remove `suffix_crc`, and the length of that suffix
174
+ // `suffix_len`, returns the CRC32C value of the buffer with suffix removed.
175
+ //
176
+ // This operation has a runtime cost of O(log(`suffix_len`))
177
+ crc32c_t RemoveCrc32cSuffix(crc32c_t full_string_crc, crc32c_t suffix_crc,
178
+ size_t suffix_length);
179
+
180
+ // operator<<
181
+ //
182
+ // Streams the CRC32C value `crc` to the stream `os`.
183
+ inline std::ostream& operator<<(std::ostream& os, crc32c_t crc) {
184
+ return os << absl::StreamFormat("%08x", static_cast<uint32_t>(crc));
185
+ }
186
+
187
+ ABSL_NAMESPACE_END
188
+ } // namespace absl
189
+
190
+ #endif // ABSL_CRC_CRC32C_H_
weight/_dep/abseil-cpp/absl/crc/internal/crc32c.h ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_CRC_INTERNAL_CRC32C_H_
16
+ #define ABSL_CRC_INTERNAL_CRC32C_H_
17
+
18
+ #include "absl/base/config.h"
19
+ #include "absl/crc/crc32c.h"
20
+
21
+ namespace absl {
22
+ ABSL_NAMESPACE_BEGIN
23
+ namespace crc_internal {
24
+
25
+ // Modifies a CRC32 value by removing `length` bytes with a value of 0 from
26
+ // the end of the string.
27
+ //
28
+ // This is the inverse operation of ExtendCrc32cByZeroes().
29
+ //
30
+ // This operation has a runtime cost of O(log(`length`))
31
+ //
32
+ // Internal implementation detail, exposed for testing only.
33
+ crc32c_t UnextendCrc32cByZeroes(crc32c_t initial_crc, size_t length);
34
+
35
+ } // namespace crc_internal
36
+ ABSL_NAMESPACE_END
37
+ } // namespace absl
38
+
39
+ #endif // ABSL_CRC_INTERNAL_CRC32C_H_
weight/_dep/abseil-cpp/absl/crc/internal/crc_cord_state.h ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_CRC_INTERNAL_CRC_CORD_STATE_H_
16
+ #define ABSL_CRC_INTERNAL_CRC_CORD_STATE_H_
17
+
18
+ #include <atomic>
19
+ #include <cstddef>
20
+ #include <deque>
21
+
22
+ #include "absl/base/config.h"
23
+ #include "absl/crc/crc32c.h"
24
+
25
+ namespace absl {
26
+ ABSL_NAMESPACE_BEGIN
27
+ namespace crc_internal {
28
+
29
+ // CrcCordState is a copy-on-write class that holds the chunked CRC32C data
30
+ // that allows CrcCord to perform efficient substring operations. CrcCordState
31
+ // is used as a member variable in CrcCord. When a CrcCord is converted to a
32
+ // Cord, the CrcCordState is shallow-copied into the root node of the Cord. If
33
+ // the converted Cord is modified outside of CrcCord, the CrcCordState is
34
+ // discarded from the Cord. If the Cord is converted back to a CrcCord, and the
35
+ // Cord is still carrying the CrcCordState in its root node, the CrcCord can
36
+ // re-use the CrcCordState, making the construction of the CrcCord cheap.
37
+ //
38
+ // CrcCordState does not try to encapsulate the CRC32C state (CrcCord requires
39
+ // knowledge of how CrcCordState represents the CRC32C state). It does
40
+ // encapsulate the copy-on-write nature of the state.
41
+ class CrcCordState {
42
+ public:
43
+ // Constructors.
44
+ CrcCordState();
45
+ CrcCordState(const CrcCordState&);
46
+ CrcCordState(CrcCordState&&);
47
+
48
+ // Destructor. Atomically unreferences the data.
49
+ ~CrcCordState();
50
+
51
+ // Copy and move operators.
52
+ CrcCordState& operator=(const CrcCordState&);
53
+ CrcCordState& operator=(CrcCordState&&);
54
+
55
+ // A (length, crc) pair.
56
+ struct PrefixCrc {
57
+ PrefixCrc() = default;
58
+ PrefixCrc(size_t length_arg, absl::crc32c_t crc_arg)
59
+ : length(length_arg), crc(crc_arg) {}
60
+
61
+ size_t length = 0;
62
+
63
+ // TODO(absl-team): Memory stomping often zeros out memory. If this struct
64
+ // gets overwritten, we could end up with {0, 0}, which is the correct CRC
65
+ // for a string of length 0. Consider storing a scrambled value and
66
+ // unscrambling it before verifying it.
67
+ absl::crc32c_t crc = absl::crc32c_t{0};
68
+ };
69
+
70
+ // The representation of the chunked CRC32C data.
71
+ struct Rep {
72
+ // `removed_prefix` is the crc and length of any prefix that has been
73
+ // removed from the Cord (for example, by calling
74
+ // `CrcCord::RemovePrefix()`). To get the checksum of any prefix of the
75
+ // cord, this value must be subtracted from `prefix_crc`. See `Checksum()`
76
+ // for an example.
77
+ //
78
+ // CrcCordState is said to be "normalized" if removed_prefix.length == 0.
79
+ PrefixCrc removed_prefix;
80
+
81
+ // A deque of (length, crc) pairs, representing length and crc of a prefix
82
+ // of the Cord, before removed_prefix has been subtracted. The lengths of
83
+ // the prefixes are stored in increasing order. If the Cord is not empty,
84
+ // the last value in deque is the contains the CRC32C of the entire Cord
85
+ // when removed_prefix is subtracted from it.
86
+ std::deque<PrefixCrc> prefix_crc;
87
+ };
88
+
89
+ // Returns a reference to the representation of the chunked CRC32C data.
90
+ const Rep& rep() const { return refcounted_rep_->rep; }
91
+
92
+ // Returns a mutable reference to the representation of the chunked CRC32C
93
+ // data. Calling this function will copy the data if another instance also
94
+ // holds a reference to the data, so it is important to call rep() instead if
95
+ // the data may not be mutated.
96
+ Rep* mutable_rep() {
97
+ if (refcounted_rep_->count.load(std::memory_order_acquire) != 1) {
98
+ RefcountedRep* copy = new RefcountedRep;
99
+ copy->rep = refcounted_rep_->rep;
100
+ Unref(refcounted_rep_);
101
+ refcounted_rep_ = copy;
102
+ }
103
+ return &refcounted_rep_->rep;
104
+ }
105
+
106
+ // Returns the CRC32C of the entire Cord.
107
+ absl::crc32c_t Checksum() const;
108
+
109
+ // Returns true if the chunked CRC32C cached is normalized.
110
+ bool IsNormalized() const { return rep().removed_prefix.length == 0; }
111
+
112
+ // Normalizes the chunked CRC32C checksum cache by subtracting any removed
113
+ // prefix from the chunks.
114
+ void Normalize();
115
+
116
+ // Returns the number of cached chunks.
117
+ size_t NumChunks() const { return rep().prefix_crc.size(); }
118
+
119
+ // Helper that returns the (length, crc) of the `n`-th cached chunked.
120
+ PrefixCrc NormalizedPrefixCrcAtNthChunk(size_t n) const;
121
+
122
+ // Poisons all chunks to so that Checksum() will likely be incorrect with high
123
+ // probability.
124
+ void Poison();
125
+
126
+ private:
127
+ struct RefcountedRep {
128
+ std::atomic<int32_t> count{1};
129
+ Rep rep;
130
+ };
131
+
132
+ // Adds a reference to the shared global empty `RefcountedRep`, and returns a
133
+ // pointer to the `RefcountedRep`. This is an optimization to avoid unneeded
134
+ // allocations when the allocation is unlikely to ever be used. The returned
135
+ // pointer can be `Unref()`ed when it is no longer needed. Since the returned
136
+ // instance will always have a reference counter greater than 1, attempts to
137
+ // modify it (by calling `mutable_rep()`) will create a new unshared copy.
138
+ static RefcountedRep* RefSharedEmptyRep();
139
+
140
+ static void Ref(RefcountedRep* r) {
141
+ assert(r != nullptr);
142
+ r->count.fetch_add(1, std::memory_order_relaxed);
143
+ }
144
+
145
+ static void Unref(RefcountedRep* r) {
146
+ assert(r != nullptr);
147
+ if (r->count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
148
+ delete r;
149
+ }
150
+ }
151
+
152
+ RefcountedRep* refcounted_rep_;
153
+ };
154
+
155
+ } // namespace crc_internal
156
+ ABSL_NAMESPACE_END
157
+ } // namespace absl
158
+
159
+ #endif // ABSL_CRC_INTERNAL_CRC_CORD_STATE_H_
weight/_dep/abseil-cpp/absl/crc/internal/crc_cord_state_test.cc ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/crc/internal/crc_cord_state.h"
16
+
17
+ #include <algorithm>
18
+ #include <cstdint>
19
+ #include <string>
20
+ #include <utility>
21
+
22
+ #include "gtest/gtest.h"
23
+ #include "absl/crc/crc32c.h"
24
+
25
+ namespace {
26
+
27
+ TEST(CrcCordState, Default) {
28
+ absl::crc_internal::CrcCordState state;
29
+ EXPECT_TRUE(state.IsNormalized());
30
+ EXPECT_EQ(state.Checksum(), absl::crc32c_t{0});
31
+ state.Normalize();
32
+ EXPECT_EQ(state.Checksum(), absl::crc32c_t{0});
33
+ }
34
+
35
+ TEST(CrcCordState, Normalize) {
36
+ absl::crc_internal::CrcCordState state;
37
+ auto* rep = state.mutable_rep();
38
+ rep->prefix_crc.push_back(
39
+ absl::crc_internal::CrcCordState::PrefixCrc(1000, absl::crc32c_t{1000}));
40
+ rep->prefix_crc.push_back(
41
+ absl::crc_internal::CrcCordState::PrefixCrc(2000, absl::crc32c_t{2000}));
42
+ rep->removed_prefix =
43
+ absl::crc_internal::CrcCordState::PrefixCrc(500, absl::crc32c_t{500});
44
+
45
+ // The removed_prefix means state is not normalized.
46
+ EXPECT_FALSE(state.IsNormalized());
47
+
48
+ absl::crc32c_t crc = state.Checksum();
49
+ state.Normalize();
50
+ EXPECT_TRUE(state.IsNormalized());
51
+
52
+ // The checksum should not change as a result of calling Normalize().
53
+ EXPECT_EQ(state.Checksum(), crc);
54
+ EXPECT_EQ(rep->removed_prefix.length, 0);
55
+ }
56
+
57
+ TEST(CrcCordState, Copy) {
58
+ absl::crc_internal::CrcCordState state;
59
+ auto* rep = state.mutable_rep();
60
+ rep->prefix_crc.push_back(
61
+ absl::crc_internal::CrcCordState::PrefixCrc(1000, absl::crc32c_t{1000}));
62
+
63
+ absl::crc_internal::CrcCordState copy = state;
64
+
65
+ EXPECT_EQ(state.Checksum(), absl::crc32c_t{1000});
66
+ EXPECT_EQ(copy.Checksum(), absl::crc32c_t{1000});
67
+ }
68
+
69
+ TEST(CrcCordState, UnsharedSelfCopy) {
70
+ absl::crc_internal::CrcCordState state;
71
+ auto* rep = state.mutable_rep();
72
+ rep->prefix_crc.push_back(
73
+ absl::crc_internal::CrcCordState::PrefixCrc(1000, absl::crc32c_t{1000}));
74
+
75
+ const absl::crc_internal::CrcCordState& ref = state;
76
+ state = ref;
77
+
78
+ EXPECT_EQ(state.Checksum(), absl::crc32c_t{1000});
79
+ }
80
+
81
+ TEST(CrcCordState, Move) {
82
+ absl::crc_internal::CrcCordState state;
83
+ auto* rep = state.mutable_rep();
84
+ rep->prefix_crc.push_back(
85
+ absl::crc_internal::CrcCordState::PrefixCrc(1000, absl::crc32c_t{1000}));
86
+
87
+ absl::crc_internal::CrcCordState moved = std::move(state);
88
+ EXPECT_EQ(moved.Checksum(), absl::crc32c_t{1000});
89
+ }
90
+
91
+ TEST(CrcCordState, UnsharedSelfMove) {
92
+ absl::crc_internal::CrcCordState state;
93
+ auto* rep = state.mutable_rep();
94
+ rep->prefix_crc.push_back(
95
+ absl::crc_internal::CrcCordState::PrefixCrc(1000, absl::crc32c_t{1000}));
96
+
97
+ absl::crc_internal::CrcCordState& ref = state;
98
+ state = std::move(ref);
99
+
100
+ EXPECT_EQ(state.Checksum(), absl::crc32c_t{1000});
101
+ }
102
+
103
+ TEST(CrcCordState, PoisonDefault) {
104
+ absl::crc_internal::CrcCordState state;
105
+ state.Poison();
106
+ EXPECT_NE(state.Checksum(), absl::crc32c_t{0});
107
+ }
108
+
109
+ TEST(CrcCordState, PoisonData) {
110
+ absl::crc_internal::CrcCordState state;
111
+ auto* rep = state.mutable_rep();
112
+ rep->prefix_crc.push_back(
113
+ absl::crc_internal::CrcCordState::PrefixCrc(1000, absl::crc32c_t{1000}));
114
+ rep->prefix_crc.push_back(
115
+ absl::crc_internal::CrcCordState::PrefixCrc(2000, absl::crc32c_t{2000}));
116
+ rep->removed_prefix =
117
+ absl::crc_internal::CrcCordState::PrefixCrc(500, absl::crc32c_t{500});
118
+
119
+ absl::crc32c_t crc = state.Checksum();
120
+ state.Poison();
121
+ EXPECT_NE(state.Checksum(), crc);
122
+ }
123
+
124
+ } // namespace
weight/_dep/abseil-cpp/absl/crc/internal/crc_memcpy.h ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_CRC_INTERNAL_CRC_MEMCPY_H_
16
+ #define ABSL_CRC_INTERNAL_CRC_MEMCPY_H_
17
+
18
+ #include <cstddef>
19
+ #include <memory>
20
+
21
+ #include "absl/base/config.h"
22
+ #include "absl/crc/crc32c.h"
23
+ #include "absl/crc/internal/crc32_x86_arm_combined_simd.h"
24
+
25
+ // Defined if the class AcceleratedCrcMemcpyEngine exists.
26
+ // TODO(b/299127771): Consider relaxing the pclmul requirement once the other
27
+ // intrinsics are conditionally compiled without it.
28
+ #if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD)
29
+ #define ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE 1
30
+ #elif defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD)
31
+ #define ABSL_INTERNAL_HAVE_ARM_ACCELERATED_CRC_MEMCPY_ENGINE 1
32
+ #endif
33
+
34
+ namespace absl {
35
+ ABSL_NAMESPACE_BEGIN
36
+ namespace crc_internal {
37
+
38
+ class CrcMemcpyEngine {
39
+ public:
40
+ virtual ~CrcMemcpyEngine() = default;
41
+
42
+ virtual crc32c_t Compute(void* __restrict dst, const void* __restrict src,
43
+ std::size_t length, crc32c_t initial_crc) const = 0;
44
+
45
+ protected:
46
+ CrcMemcpyEngine() = default;
47
+ };
48
+
49
+ class CrcMemcpy {
50
+ public:
51
+ static crc32c_t CrcAndCopy(void* __restrict dst, const void* __restrict src,
52
+ std::size_t length,
53
+ crc32c_t initial_crc = crc32c_t{0},
54
+ bool non_temporal = false) {
55
+ static const ArchSpecificEngines engines = GetArchSpecificEngines();
56
+ auto* engine = non_temporal ? engines.non_temporal : engines.temporal;
57
+ return engine->Compute(dst, src, length, initial_crc);
58
+ }
59
+
60
+ // For testing only: get an architecture-specific engine for tests.
61
+ static std::unique_ptr<CrcMemcpyEngine> GetTestEngine(int vector,
62
+ int integer);
63
+
64
+ private:
65
+ struct ArchSpecificEngines {
66
+ CrcMemcpyEngine* temporal;
67
+ CrcMemcpyEngine* non_temporal;
68
+ };
69
+
70
+ static ArchSpecificEngines GetArchSpecificEngines();
71
+ };
72
+
73
+ // Fallback CRC-memcpy engine.
74
+ class FallbackCrcMemcpyEngine : public CrcMemcpyEngine {
75
+ public:
76
+ FallbackCrcMemcpyEngine() = default;
77
+ FallbackCrcMemcpyEngine(const FallbackCrcMemcpyEngine&) = delete;
78
+ FallbackCrcMemcpyEngine operator=(const FallbackCrcMemcpyEngine&) = delete;
79
+
80
+ crc32c_t Compute(void* __restrict dst, const void* __restrict src,
81
+ std::size_t length, crc32c_t initial_crc) const override;
82
+ };
83
+
84
+ // CRC Non-Temporal-Memcpy engine.
85
+ class CrcNonTemporalMemcpyEngine : public CrcMemcpyEngine {
86
+ public:
87
+ CrcNonTemporalMemcpyEngine() = default;
88
+ CrcNonTemporalMemcpyEngine(const CrcNonTemporalMemcpyEngine&) = delete;
89
+ CrcNonTemporalMemcpyEngine operator=(const CrcNonTemporalMemcpyEngine&) =
90
+ delete;
91
+
92
+ crc32c_t Compute(void* __restrict dst, const void* __restrict src,
93
+ std::size_t length, crc32c_t initial_crc) const override;
94
+ };
95
+
96
+ // CRC Non-Temporal-Memcpy AVX engine.
97
+ class CrcNonTemporalMemcpyAVXEngine : public CrcMemcpyEngine {
98
+ public:
99
+ CrcNonTemporalMemcpyAVXEngine() = default;
100
+ CrcNonTemporalMemcpyAVXEngine(const CrcNonTemporalMemcpyAVXEngine&) = delete;
101
+ CrcNonTemporalMemcpyAVXEngine operator=(
102
+ const CrcNonTemporalMemcpyAVXEngine&) = delete;
103
+
104
+ crc32c_t Compute(void* __restrict dst, const void* __restrict src,
105
+ std::size_t length, crc32c_t initial_crc) const override;
106
+ };
107
+
108
+ // Copy source to destination and return the CRC32C of the data copied. If an
109
+ // accelerated version is available, use the accelerated version, otherwise use
110
+ // the generic fallback version.
111
+ inline crc32c_t Crc32CAndCopy(void* __restrict dst, const void* __restrict src,
112
+ std::size_t length,
113
+ crc32c_t initial_crc = crc32c_t{0},
114
+ bool non_temporal = false) {
115
+ return CrcMemcpy::CrcAndCopy(dst, src, length, initial_crc, non_temporal);
116
+ }
117
+
118
+ } // namespace crc_internal
119
+ ABSL_NAMESPACE_END
120
+ } // namespace absl
121
+
122
+ #endif // ABSL_CRC_INTERNAL_CRC_MEMCPY_H_
weight/_dep/abseil-cpp/absl/crc/internal/crc_memcpy_fallback.cc ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include <cstdint>
16
+ #include <memory>
17
+
18
+ #include "absl/base/config.h"
19
+ #include "absl/crc/crc32c.h"
20
+ #include "absl/crc/internal/crc_memcpy.h"
21
+
22
+ namespace absl {
23
+ ABSL_NAMESPACE_BEGIN
24
+ namespace crc_internal {
25
+
26
+ absl::crc32c_t FallbackCrcMemcpyEngine::Compute(void* __restrict dst,
27
+ const void* __restrict src,
28
+ std::size_t length,
29
+ crc32c_t initial_crc) const {
30
+ constexpr size_t kBlockSize = 8192;
31
+ absl::crc32c_t crc = initial_crc;
32
+
33
+ const char* src_bytes = reinterpret_cast<const char*>(src);
34
+ char* dst_bytes = reinterpret_cast<char*>(dst);
35
+
36
+ // Copy + CRC loop - run 8k chunks until we are out of full chunks. CRC
37
+ // then copy was found to be slightly more efficient in our test cases.
38
+ std::size_t offset = 0;
39
+ for (; offset + kBlockSize < length; offset += kBlockSize) {
40
+ crc = absl::ExtendCrc32c(crc,
41
+ absl::string_view(src_bytes + offset, kBlockSize));
42
+ memcpy(dst_bytes + offset, src_bytes + offset, kBlockSize);
43
+ }
44
+
45
+ // Save some work if length is 0.
46
+ if (offset < length) {
47
+ std::size_t final_copy_size = length - offset;
48
+ crc = absl::ExtendCrc32c(
49
+ crc, absl::string_view(src_bytes + offset, final_copy_size));
50
+ memcpy(dst_bytes + offset, src_bytes + offset, final_copy_size);
51
+ }
52
+
53
+ return crc;
54
+ }
55
+
56
+ // Compile the following only if we don't have
57
+ #if !defined(ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE) && \
58
+ !defined(ABSL_INTERNAL_HAVE_ARM_ACCELERATED_CRC_MEMCPY_ENGINE)
59
+
60
+ CrcMemcpy::ArchSpecificEngines CrcMemcpy::GetArchSpecificEngines() {
61
+ CrcMemcpy::ArchSpecificEngines engines;
62
+ engines.temporal = new FallbackCrcMemcpyEngine();
63
+ engines.non_temporal = new FallbackCrcMemcpyEngine();
64
+ return engines;
65
+ }
66
+
67
+ std::unique_ptr<CrcMemcpyEngine> CrcMemcpy::GetTestEngine(int /*vector*/,
68
+ int /*integer*/) {
69
+ return std::make_unique<FallbackCrcMemcpyEngine>();
70
+ }
71
+
72
+ #endif // !ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE &&
73
+ // !ABSL_INTERNAL_HAVE_ARM_ACCELERATED_CRC_MEMCPY_ENGINE
74
+
75
+ } // namespace crc_internal
76
+ ABSL_NAMESPACE_END
77
+ } // namespace absl
weight/_dep/abseil-cpp/absl/crc/internal/crc_memcpy_test.cc ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/crc/internal/crc_memcpy.h"
16
+
17
+ #include <cstddef>
18
+ #include <cstdint>
19
+ #include <cstring>
20
+ #include <limits>
21
+ #include <memory>
22
+ #include <string>
23
+ #include <utility>
24
+
25
+ #include "gtest/gtest.h"
26
+ #include "absl/crc/crc32c.h"
27
+ #include "absl/memory/memory.h"
28
+ #include "absl/random/distributions.h"
29
+ #include "absl/random/random.h"
30
+ #include "absl/strings/str_cat.h"
31
+ #include "absl/strings/string_view.h"
32
+
33
+ namespace {
34
+
35
+ enum CrcEngine {
36
+ ACCELERATED = 0,
37
+ NONTEMPORAL = 1,
38
+ FALLBACK = 2,
39
+ };
40
+
41
+ // Correctness tests:
42
+ // - Every source/destination byte alignment 0-15, every size 0-511 bytes
43
+ // - Arbitrarily aligned source, large size
44
+ template <size_t max_size>
45
+ class CrcMemcpyTest : public testing::Test {
46
+ protected:
47
+ CrcMemcpyTest() {
48
+ source_ = std::make_unique<char[]>(kSize);
49
+ destination_ = std::make_unique<char[]>(kSize);
50
+ }
51
+ static constexpr size_t kAlignment = 16;
52
+ static constexpr size_t kMaxCopySize = max_size;
53
+ static constexpr size_t kSize = kAlignment + kMaxCopySize;
54
+ std::unique_ptr<char[]> source_;
55
+ std::unique_ptr<char[]> destination_;
56
+
57
+ absl::BitGen gen_;
58
+ };
59
+
60
+ // Small test is slightly larger 4096 bytes to allow coverage of the "large"
61
+ // copy function. The minimum size to exercise all code paths in that function
62
+ // would be around 256 consecutive tests (getting every possible tail value
63
+ // and 0-2 small copy loops after the main block), so testing from 4096-4500
64
+ // will cover all of those code paths multiple times.
65
+ typedef CrcMemcpyTest<4500> CrcSmallTest;
66
+ typedef CrcMemcpyTest<(1 << 24)> CrcLargeTest;
67
+ // Parametrize the small test so that it can be done with all configurations.
68
+ template <typename ParamsT>
69
+ class EngineParamTestTemplate : public CrcSmallTest,
70
+ public ::testing::WithParamInterface<ParamsT> {
71
+ protected:
72
+ EngineParamTestTemplate() {
73
+ if (GetParam().crc_engine_selector == FALLBACK) {
74
+ engine_ = std::make_unique<absl::crc_internal::FallbackCrcMemcpyEngine>();
75
+ } else if (GetParam().crc_engine_selector == NONTEMPORAL) {
76
+ engine_ =
77
+ std::make_unique<absl::crc_internal::CrcNonTemporalMemcpyEngine>();
78
+ } else {
79
+ engine_ = absl::crc_internal::CrcMemcpy::GetTestEngine(
80
+ GetParam().vector_lanes, GetParam().integer_lanes);
81
+ }
82
+ }
83
+
84
+ // Convenience method.
85
+ ParamsT GetParam() const {
86
+ return ::testing::WithParamInterface<ParamsT>::GetParam();
87
+ }
88
+
89
+ std::unique_ptr<absl::crc_internal::CrcMemcpyEngine> engine_;
90
+ };
91
+ struct TestParams {
92
+ CrcEngine crc_engine_selector = ACCELERATED;
93
+ int vector_lanes = 0;
94
+ int integer_lanes = 0;
95
+ };
96
+ using EngineParamTest = EngineParamTestTemplate<TestParams>;
97
+ // SmallCorrectness is designed to exercise every possible set of code paths
98
+ // in the memcpy code, not including the loop.
99
+ TEST_P(EngineParamTest, SmallCorrectnessCheckSourceAlignment) {
100
+ constexpr size_t kTestSizes[] = {0, 100, 255, 512, 1024, 4000, kMaxCopySize};
101
+
102
+ for (size_t source_alignment = 0; source_alignment < kAlignment;
103
+ source_alignment++) {
104
+ for (auto size : kTestSizes) {
105
+ char* base_data = static_cast<char*>(source_.get()) + source_alignment;
106
+ for (size_t i = 0; i < size; i++) {
107
+ *(base_data + i) =
108
+ static_cast<char>(absl::Uniform<unsigned char>(gen_));
109
+ }
110
+ SCOPED_TRACE(absl::StrCat("engine=<", GetParam().vector_lanes, ",",
111
+ GetParam().integer_lanes, ">, ", "size=", size,
112
+ ", source_alignment=", source_alignment));
113
+ absl::crc32c_t initial_crc =
114
+ absl::crc32c_t{absl::Uniform<uint32_t>(gen_)};
115
+ absl::crc32c_t experiment_crc =
116
+ engine_->Compute(destination_.get(), source_.get() + source_alignment,
117
+ size, initial_crc);
118
+ // Check the memory region to make sure it is the same
119
+ int mem_comparison =
120
+ memcmp(destination_.get(), source_.get() + source_alignment, size);
121
+ SCOPED_TRACE(absl::StrCat("Error in memcpy of size: ", size,
122
+ " with source alignment: ", source_alignment));
123
+ ASSERT_EQ(mem_comparison, 0);
124
+ absl::crc32c_t baseline_crc = absl::ExtendCrc32c(
125
+ initial_crc,
126
+ absl::string_view(
127
+ static_cast<char*>(source_.get()) + source_alignment, size));
128
+ ASSERT_EQ(baseline_crc, experiment_crc);
129
+ }
130
+ }
131
+ }
132
+
133
+ TEST_P(EngineParamTest, SmallCorrectnessCheckDestAlignment) {
134
+ constexpr size_t kTestSizes[] = {0, 100, 255, 512, 1024, 4000, kMaxCopySize};
135
+
136
+ for (size_t dest_alignment = 0; dest_alignment < kAlignment;
137
+ dest_alignment++) {
138
+ for (auto size : kTestSizes) {
139
+ char* base_data = static_cast<char*>(source_.get());
140
+ for (size_t i = 0; i < size; i++) {
141
+ *(base_data + i) =
142
+ static_cast<char>(absl::Uniform<unsigned char>(gen_));
143
+ }
144
+ SCOPED_TRACE(absl::StrCat("engine=<", GetParam().vector_lanes, ",",
145
+ GetParam().integer_lanes, ">, ", "size=", size,
146
+ ", destination_alignment=", dest_alignment));
147
+ absl::crc32c_t initial_crc =
148
+ absl::crc32c_t{absl::Uniform<uint32_t>(gen_)};
149
+ absl::crc32c_t experiment_crc =
150
+ engine_->Compute(destination_.get() + dest_alignment, source_.get(),
151
+ size, initial_crc);
152
+ // Check the memory region to make sure it is the same
153
+ int mem_comparison =
154
+ memcmp(destination_.get() + dest_alignment, source_.get(), size);
155
+ SCOPED_TRACE(absl::StrCat("Error in memcpy of size: ", size,
156
+ " with dest alignment: ", dest_alignment));
157
+ ASSERT_EQ(mem_comparison, 0);
158
+ absl::crc32c_t baseline_crc = absl::ExtendCrc32c(
159
+ initial_crc,
160
+ absl::string_view(static_cast<char*>(source_.get()), size));
161
+ ASSERT_EQ(baseline_crc, experiment_crc);
162
+ }
163
+ }
164
+ }
165
+
166
+ INSTANTIATE_TEST_SUITE_P(EngineParamTest, EngineParamTest,
167
+ ::testing::Values(
168
+ // Tests for configurations that may occur in prod.
169
+ TestParams{ACCELERATED, 3, 0},
170
+ TestParams{ACCELERATED, 1, 2},
171
+ TestParams{ACCELERATED, 1, 0},
172
+ // Fallback test.
173
+ TestParams{FALLBACK, 0, 0},
174
+ // Non Temporal
175
+ TestParams{NONTEMPORAL, 0, 0}));
176
+
177
+ } // namespace
weight/_dep/abseil-cpp/absl/crc/internal/crc_memcpy_x86_arm_combined.cc ADDED
@@ -0,0 +1,450 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ // Simultaneous memcopy and CRC-32C for x86-64 and ARM 64. Uses integer
16
+ // registers because XMM registers do not support the CRC instruction (yet).
17
+ // While copying, compute the running CRC of the data being copied.
18
+ //
19
+ // It is assumed that any CPU running this code has SSE4.2 instructions
20
+ // available (for CRC32C). This file will do nothing if that is not true.
21
+ //
22
+ // The CRC instruction has a 3-byte latency, and we are stressing the ALU ports
23
+ // here (unlike a traditional memcopy, which has almost no ALU use), so we will
24
+ // need to copy in such a way that the CRC unit is used efficiently. We have two
25
+ // regimes in this code:
26
+ // 1. For operations of size < kCrcSmallSize, do the CRC then the memcpy
27
+ // 2. For operations of size > kCrcSmallSize:
28
+ // a) compute an initial CRC + copy on a small amount of data to align the
29
+ // destination pointer on a 16-byte boundary.
30
+ // b) Split the data into 3 main regions and a tail (smaller than 48 bytes)
31
+ // c) Do the copy and CRC of the 3 main regions, interleaving (start with
32
+ // full cache line copies for each region, then move to single 16 byte
33
+ // pieces per region).
34
+ // d) Combine the CRCs with CRC32C::Concat.
35
+ // e) Copy the tail and extend the CRC with the CRC of the tail.
36
+ // This method is not ideal for op sizes between ~1k and ~8k because CRC::Concat
37
+ // takes a significant amount of time. A medium-sized approach could be added
38
+ // using 3 CRCs over fixed-size blocks where the zero-extensions required for
39
+ // CRC32C::Concat can be precomputed.
40
+
41
+ #ifdef __SSE4_2__
42
+ #include <immintrin.h>
43
+ #endif
44
+
45
+ #ifdef _MSC_VER
46
+ #include <intrin.h>
47
+ #endif
48
+
49
+ #include <array>
50
+ #include <cstddef>
51
+ #include <cstdint>
52
+ #include <cstring>
53
+ #include <memory>
54
+
55
+ #include "absl/base/config.h"
56
+ #include "absl/base/optimization.h"
57
+ #include "absl/base/prefetch.h"
58
+ #include "absl/crc/crc32c.h"
59
+ #include "absl/crc/internal/cpu_detect.h"
60
+ #include "absl/crc/internal/crc32_x86_arm_combined_simd.h"
61
+ #include "absl/crc/internal/crc_memcpy.h"
62
+ #include "absl/strings/string_view.h"
63
+
64
+ #if defined(ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE) || \
65
+ defined(ABSL_INTERNAL_HAVE_ARM_ACCELERATED_CRC_MEMCPY_ENGINE)
66
+
67
+ namespace absl {
68
+ ABSL_NAMESPACE_BEGIN
69
+ namespace crc_internal {
70
+
71
+ namespace {
72
+
73
+ inline crc32c_t ShortCrcCopy(char* dst, const char* src, std::size_t length,
74
+ crc32c_t crc) {
75
+ // Small copy: just go 1 byte at a time: being nice to the branch predictor
76
+ // is more important here than anything else
77
+ uint32_t crc_uint32 = static_cast<uint32_t>(crc);
78
+ for (std::size_t i = 0; i < length; i++) {
79
+ uint8_t data = *reinterpret_cast<const uint8_t*>(src);
80
+ crc_uint32 = CRC32_u8(crc_uint32, data);
81
+ *reinterpret_cast<uint8_t*>(dst) = data;
82
+ ++src;
83
+ ++dst;
84
+ }
85
+ return crc32c_t{crc_uint32};
86
+ }
87
+
88
+ constexpr size_t kIntLoadsPerVec = sizeof(V128) / sizeof(uint64_t);
89
+
90
+ // Common function for copying the tails of multiple large regions.
91
+ template <size_t vec_regions, size_t int_regions>
92
+ inline void LargeTailCopy(crc32c_t* crcs, char** dst, const char** src,
93
+ size_t region_size, size_t copy_rounds) {
94
+ std::array<V128, vec_regions> data;
95
+ std::array<uint64_t, kIntLoadsPerVec * int_regions> int_data;
96
+
97
+ while (copy_rounds > 0) {
98
+ for (size_t i = 0; i < vec_regions; i++) {
99
+ size_t region = i;
100
+
101
+ auto* vsrc = reinterpret_cast<const V128*>(*src + region_size * region);
102
+ auto* vdst = reinterpret_cast<V128*>(*dst + region_size * region);
103
+
104
+ // Load the blocks, unaligned
105
+ data[i] = V128_LoadU(vsrc);
106
+
107
+ // Store the blocks, aligned
108
+ V128_Store(vdst, data[i]);
109
+
110
+ // Compute the running CRC
111
+ crcs[region] = crc32c_t{static_cast<uint32_t>(
112
+ CRC32_u64(static_cast<uint32_t>(crcs[region]),
113
+ static_cast<uint64_t>(V128_Extract64<0>(data[i]))))};
114
+ crcs[region] = crc32c_t{static_cast<uint32_t>(
115
+ CRC32_u64(static_cast<uint32_t>(crcs[region]),
116
+ static_cast<uint64_t>(V128_Extract64<1>(data[i]))))};
117
+ }
118
+
119
+ for (size_t i = 0; i < int_regions; i++) {
120
+ size_t region = vec_regions + i;
121
+
122
+ auto* usrc =
123
+ reinterpret_cast<const uint64_t*>(*src + region_size * region);
124
+ auto* udst = reinterpret_cast<uint64_t*>(*dst + region_size * region);
125
+
126
+ for (size_t j = 0; j < kIntLoadsPerVec; j++) {
127
+ size_t data_index = i * kIntLoadsPerVec + j;
128
+
129
+ int_data[data_index] = *(usrc + j);
130
+ crcs[region] = crc32c_t{static_cast<uint32_t>(CRC32_u64(
131
+ static_cast<uint32_t>(crcs[region]), int_data[data_index]))};
132
+
133
+ *(udst + j) = int_data[data_index];
134
+ }
135
+ }
136
+
137
+ // Increment pointers
138
+ *src += sizeof(V128);
139
+ *dst += sizeof(V128);
140
+ --copy_rounds;
141
+ }
142
+ }
143
+
144
+ } // namespace
145
+
146
+ template <size_t vec_regions, size_t int_regions>
147
+ class AcceleratedCrcMemcpyEngine : public CrcMemcpyEngine {
148
+ public:
149
+ AcceleratedCrcMemcpyEngine() = default;
150
+ AcceleratedCrcMemcpyEngine(const AcceleratedCrcMemcpyEngine&) = delete;
151
+ AcceleratedCrcMemcpyEngine operator=(const AcceleratedCrcMemcpyEngine&) =
152
+ delete;
153
+
154
+ crc32c_t Compute(void* __restrict dst, const void* __restrict src,
155
+ std::size_t length, crc32c_t initial_crc) const override;
156
+ };
157
+
158
+ template <size_t vec_regions, size_t int_regions>
159
+ crc32c_t AcceleratedCrcMemcpyEngine<vec_regions, int_regions>::Compute(
160
+ void* __restrict dst, const void* __restrict src, std::size_t length,
161
+ crc32c_t initial_crc) const {
162
+ constexpr std::size_t kRegions = vec_regions + int_regions;
163
+ static_assert(kRegions > 0, "Must specify at least one region.");
164
+ constexpr uint32_t kCrcDataXor = uint32_t{0xffffffff};
165
+ constexpr std::size_t kBlockSize = sizeof(V128);
166
+ constexpr std::size_t kCopyRoundSize = kRegions * kBlockSize;
167
+
168
+ // Number of blocks per cacheline.
169
+ constexpr std::size_t kBlocksPerCacheLine = ABSL_CACHELINE_SIZE / kBlockSize;
170
+
171
+ char* dst_bytes = static_cast<char*>(dst);
172
+ const char* src_bytes = static_cast<const char*>(src);
173
+
174
+ // Make sure that one prefetch per big block is enough to cover the whole
175
+ // dataset, and we don't prefetch too much.
176
+ static_assert(ABSL_CACHELINE_SIZE % kBlockSize == 0,
177
+ "Cache lines are not divided evenly into blocks, may have "
178
+ "unintended behavior!");
179
+
180
+ // Experimentally-determined boundary between a small and large copy.
181
+ // Below this number, spin-up and concatenation of CRCs takes enough time that
182
+ // it kills the throughput gains of using 3 regions and wide vectors.
183
+ constexpr size_t kCrcSmallSize = 256;
184
+
185
+ // Experimentally-determined prefetch distance. Main loop copies will
186
+ // prefeth data 2 cache lines ahead.
187
+ constexpr std::size_t kPrefetchAhead = 2 * ABSL_CACHELINE_SIZE;
188
+
189
+ // Small-size CRC-memcpy : just do CRC + memcpy
190
+ if (length < kCrcSmallSize) {
191
+ crc32c_t crc =
192
+ ExtendCrc32c(initial_crc, absl::string_view(src_bytes, length));
193
+ memcpy(dst, src, length);
194
+ return crc;
195
+ }
196
+
197
+ // Start work on the CRC: undo the XOR from the previous calculation or set up
198
+ // the initial value of the CRC.
199
+ // initial_crc ^= kCrcDataXor;
200
+ initial_crc = crc32c_t{static_cast<uint32_t>(initial_crc) ^ kCrcDataXor};
201
+
202
+ // Do an initial alignment copy, so we can use aligned store instructions to
203
+ // the destination pointer. We align the destination pointer because the
204
+ // penalty for an unaligned load is small compared to the penalty of an
205
+ // unaligned store on modern CPUs.
206
+ std::size_t bytes_from_last_aligned =
207
+ reinterpret_cast<uintptr_t>(dst) & (kBlockSize - 1);
208
+ if (bytes_from_last_aligned != 0) {
209
+ std::size_t bytes_for_alignment = kBlockSize - bytes_from_last_aligned;
210
+
211
+ // Do the short-sized copy and CRC.
212
+ initial_crc =
213
+ ShortCrcCopy(dst_bytes, src_bytes, bytes_for_alignment, initial_crc);
214
+ src_bytes += bytes_for_alignment;
215
+ dst_bytes += bytes_for_alignment;
216
+ length -= bytes_for_alignment;
217
+ }
218
+
219
+ // We are going to do the copy and CRC in kRegions regions to make sure that
220
+ // we can saturate the CRC unit. The CRCs will be combined at the end of the
221
+ // run. Copying will use the SSE registers, and we will extract words from
222
+ // the SSE registers to add to the CRC. Initially, we run the loop one full
223
+ // cache line per region at a time, in order to insert prefetches.
224
+
225
+ // Initialize CRCs for kRegions regions.
226
+ crc32c_t crcs[kRegions];
227
+ crcs[0] = initial_crc;
228
+ for (size_t i = 1; i < kRegions; i++) {
229
+ crcs[i] = crc32c_t{kCrcDataXor};
230
+ }
231
+
232
+ // Find the number of rounds to copy and the region size. Also compute the
233
+ // tail size here.
234
+ size_t copy_rounds = length / kCopyRoundSize;
235
+
236
+ // Find the size of each region and the size of the tail.
237
+ const std::size_t region_size = copy_rounds * kBlockSize;
238
+ const std::size_t tail_size = length - (kRegions * region_size);
239
+
240
+ // Holding registers for data in each region.
241
+ std::array<V128, vec_regions> vec_data;
242
+ std::array<uint64_t, int_regions * kIntLoadsPerVec> int_data;
243
+
244
+ // Main loop.
245
+ while (copy_rounds > kBlocksPerCacheLine) {
246
+ // Prefetch kPrefetchAhead bytes ahead of each pointer.
247
+ for (size_t i = 0; i < kRegions; i++) {
248
+ absl::PrefetchToLocalCache(src_bytes + kPrefetchAhead + region_size * i);
249
+ #ifdef ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE
250
+ // TODO(b/297082454): investigate dropping prefetch on x86.
251
+ absl::PrefetchToLocalCache(dst_bytes + kPrefetchAhead + region_size * i);
252
+ #endif
253
+ }
254
+
255
+ // Load and store data, computing CRC on the way.
256
+ for (size_t i = 0; i < kBlocksPerCacheLine; i++) {
257
+ // Copy and CRC the data for the CRC regions.
258
+ for (size_t j = 0; j < vec_regions; j++) {
259
+ // Cycle which regions get vector load/store and integer load/store, to
260
+ // engage prefetching logic around vector load/stores and save issue
261
+ // slots by using the integer registers.
262
+ size_t region = (j + i) % kRegions;
263
+
264
+ auto* vsrc =
265
+ reinterpret_cast<const V128*>(src_bytes + region_size * region);
266
+ auto* vdst = reinterpret_cast<V128*>(dst_bytes + region_size * region);
267
+
268
+ // Load and CRC data.
269
+ vec_data[j] = V128_LoadU(vsrc + i);
270
+ crcs[region] = crc32c_t{static_cast<uint32_t>(
271
+ CRC32_u64(static_cast<uint32_t>(crcs[region]),
272
+ static_cast<uint64_t>(V128_Extract64<0>(vec_data[j]))))};
273
+ crcs[region] = crc32c_t{static_cast<uint32_t>(
274
+ CRC32_u64(static_cast<uint32_t>(crcs[region]),
275
+ static_cast<uint64_t>(V128_Extract64<1>(vec_data[j]))))};
276
+
277
+ // Store the data.
278
+ V128_Store(vdst + i, vec_data[j]);
279
+ }
280
+
281
+ // Preload the partial CRCs for the CLMUL subregions.
282
+ for (size_t j = 0; j < int_regions; j++) {
283
+ // Cycle which regions get vector load/store and integer load/store, to
284
+ // engage prefetching logic around vector load/stores and save issue
285
+ // slots by using the integer registers.
286
+ size_t region = (j + vec_regions + i) % kRegions;
287
+
288
+ auto* usrc =
289
+ reinterpret_cast<const uint64_t*>(src_bytes + region_size * region);
290
+ auto* udst =
291
+ reinterpret_cast<uint64_t*>(dst_bytes + region_size * region);
292
+
293
+ for (size_t k = 0; k < kIntLoadsPerVec; k++) {
294
+ size_t data_index = j * kIntLoadsPerVec + k;
295
+
296
+ // Load and CRC the data.
297
+ int_data[data_index] = *(usrc + i * kIntLoadsPerVec + k);
298
+ crcs[region] = crc32c_t{static_cast<uint32_t>(CRC32_u64(
299
+ static_cast<uint32_t>(crcs[region]), int_data[data_index]))};
300
+
301
+ // Store the data.
302
+ *(udst + i * kIntLoadsPerVec + k) = int_data[data_index];
303
+ }
304
+ }
305
+ }
306
+
307
+ // Increment pointers
308
+ src_bytes += kBlockSize * kBlocksPerCacheLine;
309
+ dst_bytes += kBlockSize * kBlocksPerCacheLine;
310
+ copy_rounds -= kBlocksPerCacheLine;
311
+ }
312
+
313
+ // Copy and CRC the tails of each region.
314
+ LargeTailCopy<vec_regions, int_regions>(crcs, &dst_bytes, &src_bytes,
315
+ region_size, copy_rounds);
316
+
317
+ // Move the source and destination pointers to the end of the region
318
+ src_bytes += region_size * (kRegions - 1);
319
+ dst_bytes += region_size * (kRegions - 1);
320
+
321
+ // Copy and CRC the tail through the XMM registers.
322
+ std::size_t tail_blocks = tail_size / kBlockSize;
323
+ LargeTailCopy<0, 1>(&crcs[kRegions - 1], &dst_bytes, &src_bytes, 0,
324
+ tail_blocks);
325
+
326
+ // Final tail copy for under 16 bytes.
327
+ crcs[kRegions - 1] =
328
+ ShortCrcCopy(dst_bytes, src_bytes, tail_size - tail_blocks * kBlockSize,
329
+ crcs[kRegions - 1]);
330
+
331
+ if (kRegions == 1) {
332
+ // If there is only one region, finalize and return its CRC.
333
+ return crc32c_t{static_cast<uint32_t>(crcs[0]) ^ kCrcDataXor};
334
+ }
335
+
336
+ // Finalize the first CRCs: XOR the internal CRCs by the XOR mask to undo the
337
+ // XOR done before doing block copy + CRCs.
338
+ for (size_t i = 0; i + 1 < kRegions; i++) {
339
+ crcs[i] = crc32c_t{static_cast<uint32_t>(crcs[i]) ^ kCrcDataXor};
340
+ }
341
+
342
+ // Build a CRC of the first kRegions - 1 regions.
343
+ crc32c_t full_crc = crcs[0];
344
+ for (size_t i = 1; i + 1 < kRegions; i++) {
345
+ full_crc = ConcatCrc32c(full_crc, crcs[i], region_size);
346
+ }
347
+
348
+ // Finalize and concatenate the final CRC, then return.
349
+ crcs[kRegions - 1] =
350
+ crc32c_t{static_cast<uint32_t>(crcs[kRegions - 1]) ^ kCrcDataXor};
351
+ return ConcatCrc32c(full_crc, crcs[kRegions - 1], region_size + tail_size);
352
+ }
353
+
354
+ CrcMemcpy::ArchSpecificEngines CrcMemcpy::GetArchSpecificEngines() {
355
+ #ifdef UNDEFINED_BEHAVIOR_SANITIZER
356
+ // UBSAN does not play nicely with unaligned loads (which we use a lot).
357
+ // Get the underlying architecture.
358
+ CpuType cpu_type = GetCpuType();
359
+ switch (cpu_type) {
360
+ case CpuType::kAmdRome:
361
+ case CpuType::kAmdNaples:
362
+ case CpuType::kAmdMilan:
363
+ case CpuType::kAmdGenoa:
364
+ case CpuType::kAmdRyzenV3000:
365
+ case CpuType::kIntelCascadelakeXeon:
366
+ case CpuType::kIntelSkylakeXeon:
367
+ case CpuType::kIntelSkylake:
368
+ case CpuType::kIntelBroadwell:
369
+ case CpuType::kIntelHaswell:
370
+ case CpuType::kIntelIvybridge:
371
+ return {
372
+ /*.temporal=*/new FallbackCrcMemcpyEngine(),
373
+ /*.non_temporal=*/new CrcNonTemporalMemcpyAVXEngine(),
374
+ };
375
+ // INTEL_SANDYBRIDGE performs better with SSE than AVX.
376
+ case CpuType::kIntelSandybridge:
377
+ return {
378
+ /*.temporal=*/new FallbackCrcMemcpyEngine(),
379
+ /*.non_temporal=*/new CrcNonTemporalMemcpyEngine(),
380
+ };
381
+ default:
382
+ return {/*.temporal=*/new FallbackCrcMemcpyEngine(),
383
+ /*.non_temporal=*/new FallbackCrcMemcpyEngine()};
384
+ }
385
+ #else
386
+ // Get the underlying architecture.
387
+ CpuType cpu_type = GetCpuType();
388
+ switch (cpu_type) {
389
+ // On Zen 2, PEXTRQ uses 2 micro-ops, including one on the vector store port
390
+ // which data movement from the vector registers to the integer registers
391
+ // (where CRC32C happens) to crowd the same units as vector stores. As a
392
+ // result, using that path exclusively causes bottlenecking on this port.
393
+ // We can avoid this bottleneck by using the integer side of the CPU for
394
+ // most operations rather than the vector side. We keep a vector region to
395
+ // engage some of the prefetching logic in the cache hierarchy which seems
396
+ // to give vector instructions special treatment. These prefetch units see
397
+ // strided access to each region, and do the right thing.
398
+ case CpuType::kAmdRome:
399
+ case CpuType::kAmdNaples:
400
+ case CpuType::kAmdMilan:
401
+ case CpuType::kAmdGenoa:
402
+ case CpuType::kAmdRyzenV3000:
403
+ return {
404
+ /*.temporal=*/new AcceleratedCrcMemcpyEngine<1, 2>(),
405
+ /*.non_temporal=*/new CrcNonTemporalMemcpyAVXEngine(),
406
+ };
407
+ // PCLMULQDQ is slow and we don't have wide enough issue width to take
408
+ // advantage of it. For an unknown architecture, don't risk using CLMULs.
409
+ case CpuType::kIntelCascadelakeXeon:
410
+ case CpuType::kIntelSkylakeXeon:
411
+ case CpuType::kIntelSkylake:
412
+ case CpuType::kIntelBroadwell:
413
+ case CpuType::kIntelHaswell:
414
+ case CpuType::kIntelIvybridge:
415
+ return {
416
+ /*.temporal=*/new AcceleratedCrcMemcpyEngine<3, 0>(),
417
+ /*.non_temporal=*/new CrcNonTemporalMemcpyAVXEngine(),
418
+ };
419
+ // INTEL_SANDYBRIDGE performs better with SSE than AVX.
420
+ case CpuType::kIntelSandybridge:
421
+ return {
422
+ /*.temporal=*/new AcceleratedCrcMemcpyEngine<3, 0>(),
423
+ /*.non_temporal=*/new CrcNonTemporalMemcpyEngine(),
424
+ };
425
+ default:
426
+ return {/*.temporal=*/new FallbackCrcMemcpyEngine(),
427
+ /*.non_temporal=*/new FallbackCrcMemcpyEngine()};
428
+ }
429
+ #endif // UNDEFINED_BEHAVIOR_SANITIZER
430
+ }
431
+
432
+ // For testing, allow the user to specify which engine they want.
433
+ std::unique_ptr<CrcMemcpyEngine> CrcMemcpy::GetTestEngine(int vector,
434
+ int integer) {
435
+ if (vector == 3 && integer == 0) {
436
+ return std::make_unique<AcceleratedCrcMemcpyEngine<3, 0>>();
437
+ } else if (vector == 1 && integer == 2) {
438
+ return std::make_unique<AcceleratedCrcMemcpyEngine<1, 2>>();
439
+ } else if (vector == 1 && integer == 0) {
440
+ return std::make_unique<AcceleratedCrcMemcpyEngine<1, 0>>();
441
+ }
442
+ return nullptr;
443
+ }
444
+
445
+ } // namespace crc_internal
446
+ ABSL_NAMESPACE_END
447
+ } // namespace absl
448
+
449
+ #endif // ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE ||
450
+ // ABSL_INTERNAL_HAVE_ARM_ACCELERATED_CRC_MEMCPY_ENGINE
weight/_dep/abseil-cpp/absl/crc/internal/crc_non_temporal_memcpy.cc ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include <cstdint>
16
+
17
+ #include "absl/base/config.h"
18
+ #include "absl/crc/crc32c.h"
19
+ #include "absl/crc/internal/crc_memcpy.h"
20
+ #include "absl/crc/internal/non_temporal_memcpy.h"
21
+ #include "absl/strings/string_view.h"
22
+
23
+ namespace absl {
24
+ ABSL_NAMESPACE_BEGIN
25
+ namespace crc_internal {
26
+
27
+ crc32c_t CrcNonTemporalMemcpyEngine::Compute(void* __restrict dst,
28
+ const void* __restrict src,
29
+ std::size_t length,
30
+ crc32c_t initial_crc) const {
31
+ constexpr size_t kBlockSize = 8192;
32
+ crc32c_t crc = initial_crc;
33
+
34
+ const char* src_bytes = reinterpret_cast<const char*>(src);
35
+ char* dst_bytes = reinterpret_cast<char*>(dst);
36
+
37
+ // Copy + CRC loop - run 8k chunks until we are out of full chunks.
38
+ std::size_t offset = 0;
39
+ for (; offset + kBlockSize < length; offset += kBlockSize) {
40
+ crc = absl::ExtendCrc32c(crc,
41
+ absl::string_view(src_bytes + offset, kBlockSize));
42
+ non_temporal_store_memcpy(dst_bytes + offset, src_bytes + offset,
43
+ kBlockSize);
44
+ }
45
+
46
+ // Save some work if length is 0.
47
+ if (offset < length) {
48
+ std::size_t final_copy_size = length - offset;
49
+ crc = ExtendCrc32c(crc,
50
+ absl::string_view(src_bytes + offset, final_copy_size));
51
+
52
+ non_temporal_store_memcpy(dst_bytes + offset, src_bytes + offset,
53
+ final_copy_size);
54
+ }
55
+
56
+ return crc;
57
+ }
58
+
59
+ crc32c_t CrcNonTemporalMemcpyAVXEngine::Compute(void* __restrict dst,
60
+ const void* __restrict src,
61
+ std::size_t length,
62
+ crc32c_t initial_crc) const {
63
+ constexpr size_t kBlockSize = 8192;
64
+ crc32c_t crc = initial_crc;
65
+
66
+ const char* src_bytes = reinterpret_cast<const char*>(src);
67
+ char* dst_bytes = reinterpret_cast<char*>(dst);
68
+
69
+ // Copy + CRC loop - run 8k chunks until we are out of full chunks.
70
+ std::size_t offset = 0;
71
+ for (; offset + kBlockSize < length; offset += kBlockSize) {
72
+ crc = ExtendCrc32c(crc, absl::string_view(src_bytes + offset, kBlockSize));
73
+
74
+ non_temporal_store_memcpy_avx(dst_bytes + offset, src_bytes + offset,
75
+ kBlockSize);
76
+ }
77
+
78
+ // Save some work if length is 0.
79
+ if (offset < length) {
80
+ std::size_t final_copy_size = length - offset;
81
+ crc = ExtendCrc32c(crc,
82
+ absl::string_view(src_bytes + offset, final_copy_size));
83
+
84
+ non_temporal_store_memcpy_avx(dst_bytes + offset, src_bytes + offset,
85
+ final_copy_size);
86
+ }
87
+
88
+ return crc;
89
+ }
90
+
91
+ } // namespace crc_internal
92
+ ABSL_NAMESPACE_END
93
+ } // namespace absl
weight/_dep/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc ADDED
@@ -0,0 +1,733 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ // Hardware accelerated CRC32 computation on Intel and ARM architecture.
16
+
17
+ #include <cstddef>
18
+ #include <cstdint>
19
+ #include <memory>
20
+ #include <vector>
21
+
22
+ #include "absl/base/attributes.h"
23
+ #include "absl/base/config.h"
24
+ #include "absl/base/internal/endian.h"
25
+ #include "absl/base/prefetch.h"
26
+ #include "absl/crc/internal/cpu_detect.h"
27
+ #include "absl/crc/internal/crc32_x86_arm_combined_simd.h"
28
+ #include "absl/crc/internal/crc_internal.h"
29
+ #include "absl/memory/memory.h"
30
+ #include "absl/numeric/bits.h"
31
+
32
+ #if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) || \
33
+ defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD)
34
+ #define ABSL_INTERNAL_CAN_USE_SIMD_CRC32C
35
+ #endif
36
+
37
+ namespace absl {
38
+ ABSL_NAMESPACE_BEGIN
39
+ namespace crc_internal {
40
+
41
+ #if defined(ABSL_INTERNAL_CAN_USE_SIMD_CRC32C)
42
+
43
+ // Implementation details not exported outside of file
44
+ namespace {
45
+
46
+ // Some machines have CRC acceleration hardware.
47
+ // We can do a faster version of Extend() on such machines.
48
+ class CRC32AcceleratedX86ARMCombined : public CRC32 {
49
+ public:
50
+ CRC32AcceleratedX86ARMCombined() {}
51
+ ~CRC32AcceleratedX86ARMCombined() override {}
52
+ void ExtendByZeroes(uint32_t* crc, size_t length) const override;
53
+ uint32_t ComputeZeroConstant(size_t length) const;
54
+
55
+ private:
56
+ CRC32AcceleratedX86ARMCombined(const CRC32AcceleratedX86ARMCombined&) =
57
+ delete;
58
+ CRC32AcceleratedX86ARMCombined& operator=(
59
+ const CRC32AcceleratedX86ARMCombined&) = delete;
60
+ };
61
+
62
+ // Constants for switching between algorithms.
63
+ // Chosen by comparing speed at different powers of 2.
64
+ constexpr size_t kSmallCutoff = 256;
65
+ constexpr size_t kMediumCutoff = 2048;
66
+
67
+ #define ABSL_INTERNAL_STEP1(crc) \
68
+ do { \
69
+ crc = CRC32_u8(static_cast<uint32_t>(crc), *p++); \
70
+ } while (0)
71
+ #define ABSL_INTERNAL_STEP2(crc) \
72
+ do { \
73
+ crc = \
74
+ CRC32_u16(static_cast<uint32_t>(crc), absl::little_endian::Load16(p)); \
75
+ p += 2; \
76
+ } while (0)
77
+ #define ABSL_INTERNAL_STEP4(crc) \
78
+ do { \
79
+ crc = \
80
+ CRC32_u32(static_cast<uint32_t>(crc), absl::little_endian::Load32(p)); \
81
+ p += 4; \
82
+ } while (0)
83
+ #define ABSL_INTERNAL_STEP8(crc, data) \
84
+ do { \
85
+ crc = CRC32_u64(static_cast<uint32_t>(crc), \
86
+ absl::little_endian::Load64(data)); \
87
+ data += 8; \
88
+ } while (0)
89
+ #define ABSL_INTERNAL_STEP8BY2(crc0, crc1, p0, p1) \
90
+ do { \
91
+ ABSL_INTERNAL_STEP8(crc0, p0); \
92
+ ABSL_INTERNAL_STEP8(crc1, p1); \
93
+ } while (0)
94
+ #define ABSL_INTERNAL_STEP8BY3(crc0, crc1, crc2, p0, p1, p2) \
95
+ do { \
96
+ ABSL_INTERNAL_STEP8(crc0, p0); \
97
+ ABSL_INTERNAL_STEP8(crc1, p1); \
98
+ ABSL_INTERNAL_STEP8(crc2, p2); \
99
+ } while (0)
100
+
101
+ namespace {
102
+
103
+ uint32_t multiply(uint32_t a, uint32_t b) {
104
+ V128 shifts = V128_From2x64(0, 1);
105
+ V128 power = V128_From2x64(0, a);
106
+ V128 crc = V128_From2x64(0, b);
107
+ V128 res = V128_PMulLow(power, crc);
108
+
109
+ // Combine crc values
110
+ res = V128_ShiftLeft64(res, shifts);
111
+ return static_cast<uint32_t>(V128_Extract32<1>(res)) ^
112
+ CRC32_u32(0, static_cast<uint32_t>(V128_Low64(res)));
113
+ }
114
+
115
+ // Powers of crc32c polynomial, for faster ExtendByZeros.
116
+ // Verified against folly:
117
+ // folly/hash/detail/Crc32CombineDetail.cpp
118
+ constexpr uint32_t kCRC32CPowers[] = {
119
+ 0x82f63b78, 0x6ea2d55c, 0x18b8ea18, 0x510ac59a, 0xb82be955, 0xb8fdb1e7,
120
+ 0x88e56f72, 0x74c360a4, 0xe4172b16, 0x0d65762a, 0x35d73a62, 0x28461564,
121
+ 0xbf455269, 0xe2ea32dc, 0xfe7740e6, 0xf946610b, 0x3c204f8f, 0x538586e3,
122
+ 0x59726915, 0x734d5309, 0xbc1ac763, 0x7d0722cc, 0xd289cabe, 0xe94ca9bc,
123
+ 0x05b74f3f, 0xa51e1f42, 0x40000000, 0x20000000, 0x08000000, 0x00800000,
124
+ 0x00008000, 0x82f63b78, 0x6ea2d55c, 0x18b8ea18, 0x510ac59a, 0xb82be955,
125
+ 0xb8fdb1e7, 0x88e56f72, 0x74c360a4, 0xe4172b16, 0x0d65762a, 0x35d73a62,
126
+ 0x28461564, 0xbf455269, 0xe2ea32dc, 0xfe7740e6, 0xf946610b, 0x3c204f8f,
127
+ 0x538586e3, 0x59726915, 0x734d5309, 0xbc1ac763, 0x7d0722cc, 0xd289cabe,
128
+ 0xe94ca9bc, 0x05b74f3f, 0xa51e1f42, 0x40000000, 0x20000000, 0x08000000,
129
+ 0x00800000, 0x00008000,
130
+ };
131
+
132
+ } // namespace
133
+
134
+ // Compute a magic constant, so that multiplying by it is the same as
135
+ // extending crc by length zeros.
136
+ uint32_t CRC32AcceleratedX86ARMCombined::ComputeZeroConstant(
137
+ size_t length) const {
138
+ // Lowest 2 bits are handled separately in ExtendByZeroes
139
+ length >>= 2;
140
+
141
+ int index = absl::countr_zero(length);
142
+ uint32_t prev = kCRC32CPowers[index];
143
+ length &= length - 1;
144
+
145
+ while (length) {
146
+ // For each bit of length, extend by 2**n zeros.
147
+ index = absl::countr_zero(length);
148
+ prev = multiply(prev, kCRC32CPowers[index]);
149
+ length &= length - 1;
150
+ }
151
+ return prev;
152
+ }
153
+
154
+ void CRC32AcceleratedX86ARMCombined::ExtendByZeroes(uint32_t* crc,
155
+ size_t length) const {
156
+ uint32_t val = *crc;
157
+ // Don't bother with multiplication for small length.
158
+ switch (length & 3) {
159
+ case 0:
160
+ break;
161
+ case 1:
162
+ val = CRC32_u8(val, 0);
163
+ break;
164
+ case 2:
165
+ val = CRC32_u16(val, 0);
166
+ break;
167
+ case 3:
168
+ val = CRC32_u8(val, 0);
169
+ val = CRC32_u16(val, 0);
170
+ break;
171
+ }
172
+ if (length > 3) {
173
+ val = multiply(val, ComputeZeroConstant(length));
174
+ }
175
+ *crc = val;
176
+ }
177
+
178
+ // Taken from Intel paper "Fast CRC Computation for iSCSI Polynomial Using CRC32
179
+ // Instruction"
180
+ // https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/crc-iscsi-polynomial-crc32-instruction-paper.pdf
181
+ // We only need every 4th value, because we unroll loop by 4.
182
+ constexpr uint64_t kClmulConstants[] = {
183
+ 0x09e4addf8, 0x0ba4fc28e, 0x00d3b6092, 0x09e4addf8, 0x0ab7aff2a,
184
+ 0x102f9b8a2, 0x0b9e02b86, 0x00d3b6092, 0x1bf2e8b8a, 0x18266e456,
185
+ 0x0d270f1a2, 0x0ab7aff2a, 0x11eef4f8e, 0x083348832, 0x0dd7e3b0c,
186
+ 0x0b9e02b86, 0x0271d9844, 0x1b331e26a, 0x06b749fb2, 0x1bf2e8b8a,
187
+ 0x0e6fc4e6a, 0x0ce7f39f4, 0x0d7a4825c, 0x0d270f1a2, 0x026f6a60a,
188
+ 0x12ed0daac, 0x068bce87a, 0x11eef4f8e, 0x1329d9f7e, 0x0b3e32c28,
189
+ 0x0170076fa, 0x0dd7e3b0c, 0x1fae1cc66, 0x010746f3c, 0x086d8e4d2,
190
+ 0x0271d9844, 0x0b3af077a, 0x093a5f730, 0x1d88abd4a, 0x06b749fb2,
191
+ 0x0c9c8b782, 0x0cec3662e, 0x1ddffc5d4, 0x0e6fc4e6a, 0x168763fa6,
192
+ 0x0b0cd4768, 0x19b1afbc4, 0x0d7a4825c, 0x123888b7a, 0x00167d312,
193
+ 0x133d7a042, 0x026f6a60a, 0x000bcf5f6, 0x19d34af3a, 0x1af900c24,
194
+ 0x068bce87a, 0x06d390dec, 0x16cba8aca, 0x1f16a3418, 0x1329d9f7e,
195
+ 0x19fb2a8b0, 0x02178513a, 0x1a0f717c4, 0x0170076fa,
196
+ };
197
+
198
+ enum class CutoffStrategy {
199
+ // Use 3 CRC streams to fold into 1.
200
+ Fold3,
201
+ // Unroll CRC instructions for 64 bytes.
202
+ Unroll64CRC,
203
+ };
204
+
205
+ // Base class for CRC32AcceleratedX86ARMCombinedMultipleStreams containing the
206
+ // methods and data that don't need the template arguments.
207
+ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase
208
+ : public CRC32AcceleratedX86ARMCombined {
209
+ protected:
210
+ // Update partialCRC with crc of 64 byte block. Calling FinalizePclmulStream
211
+ // would produce a single crc checksum, but it is expensive. PCLMULQDQ has a
212
+ // high latency, so we run 4 128-bit partial checksums that can be reduced to
213
+ // a single value by FinalizePclmulStream later. Computing crc for arbitrary
214
+ // polynomialas with PCLMULQDQ is described in Intel paper "Fast CRC
215
+ // Computation for Generic Polynomials Using PCLMULQDQ Instruction"
216
+ // https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
217
+ // We are applying it to CRC32C polynomial.
218
+ ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesPclmul(
219
+ const uint8_t* p, V128* partialCRC) const {
220
+ V128 loopMultiplicands = V128_Load(reinterpret_cast<const V128*>(k1k2));
221
+
222
+ V128 partialCRC1 = partialCRC[0];
223
+ V128 partialCRC2 = partialCRC[1];
224
+ V128 partialCRC3 = partialCRC[2];
225
+ V128 partialCRC4 = partialCRC[3];
226
+
227
+ V128 tmp1 = V128_PMulHi(partialCRC1, loopMultiplicands);
228
+ V128 tmp2 = V128_PMulHi(partialCRC2, loopMultiplicands);
229
+ V128 tmp3 = V128_PMulHi(partialCRC3, loopMultiplicands);
230
+ V128 tmp4 = V128_PMulHi(partialCRC4, loopMultiplicands);
231
+ V128 data1 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 0));
232
+ V128 data2 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 1));
233
+ V128 data3 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 2));
234
+ V128 data4 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 3));
235
+ partialCRC1 = V128_PMulLow(partialCRC1, loopMultiplicands);
236
+ partialCRC2 = V128_PMulLow(partialCRC2, loopMultiplicands);
237
+ partialCRC3 = V128_PMulLow(partialCRC3, loopMultiplicands);
238
+ partialCRC4 = V128_PMulLow(partialCRC4, loopMultiplicands);
239
+ partialCRC1 = V128_Xor(tmp1, partialCRC1);
240
+ partialCRC2 = V128_Xor(tmp2, partialCRC2);
241
+ partialCRC3 = V128_Xor(tmp3, partialCRC3);
242
+ partialCRC4 = V128_Xor(tmp4, partialCRC4);
243
+ partialCRC1 = V128_Xor(partialCRC1, data1);
244
+ partialCRC2 = V128_Xor(partialCRC2, data2);
245
+ partialCRC3 = V128_Xor(partialCRC3, data3);
246
+ partialCRC4 = V128_Xor(partialCRC4, data4);
247
+ partialCRC[0] = partialCRC1;
248
+ partialCRC[1] = partialCRC2;
249
+ partialCRC[2] = partialCRC3;
250
+ partialCRC[3] = partialCRC4;
251
+ }
252
+
253
+ // Reduce partialCRC produced by Process64BytesPclmul into a single value,
254
+ // that represents crc checksum of all the processed bytes.
255
+ ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t
256
+ FinalizePclmulStream(V128* partialCRC) const {
257
+ V128 partialCRC1 = partialCRC[0];
258
+ V128 partialCRC2 = partialCRC[1];
259
+ V128 partialCRC3 = partialCRC[2];
260
+ V128 partialCRC4 = partialCRC[3];
261
+
262
+ // Combine 4 vectors of partial crc into a single vector.
263
+ V128 reductionMultiplicands =
264
+ V128_Load(reinterpret_cast<const V128*>(k5k6));
265
+
266
+ V128 low = V128_PMulLow(reductionMultiplicands, partialCRC1);
267
+ V128 high = V128_PMulHi(reductionMultiplicands, partialCRC1);
268
+
269
+ partialCRC1 = V128_Xor(low, high);
270
+ partialCRC1 = V128_Xor(partialCRC1, partialCRC2);
271
+
272
+ low = V128_PMulLow(reductionMultiplicands, partialCRC3);
273
+ high = V128_PMulHi(reductionMultiplicands, partialCRC3);
274
+
275
+ partialCRC3 = V128_Xor(low, high);
276
+ partialCRC3 = V128_Xor(partialCRC3, partialCRC4);
277
+
278
+ reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(k3k4));
279
+
280
+ low = V128_PMulLow(reductionMultiplicands, partialCRC1);
281
+ high = V128_PMulHi(reductionMultiplicands, partialCRC1);
282
+ V128 fullCRC = V128_Xor(low, high);
283
+ fullCRC = V128_Xor(fullCRC, partialCRC3);
284
+
285
+ // Reduce fullCRC into scalar value.
286
+ reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(k5k6));
287
+
288
+ V128 mask = V128_Load(reinterpret_cast<const V128*>(kMask));
289
+
290
+ V128 tmp = V128_PMul01(reductionMultiplicands, fullCRC);
291
+ fullCRC = V128_ShiftRight<8>(fullCRC);
292
+ fullCRC = V128_Xor(fullCRC, tmp);
293
+
294
+ reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(k7k0));
295
+
296
+ tmp = V128_ShiftRight<4>(fullCRC);
297
+ fullCRC = V128_And(fullCRC, mask);
298
+ fullCRC = V128_PMulLow(reductionMultiplicands, fullCRC);
299
+ fullCRC = V128_Xor(tmp, fullCRC);
300
+
301
+ reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(kPoly));
302
+
303
+ tmp = V128_And(fullCRC, mask);
304
+ tmp = V128_PMul01(reductionMultiplicands, tmp);
305
+ tmp = V128_And(tmp, mask);
306
+ tmp = V128_PMulLow(reductionMultiplicands, tmp);
307
+
308
+ fullCRC = V128_Xor(tmp, fullCRC);
309
+
310
+ return static_cast<uint64_t>(V128_Extract32<1>(fullCRC));
311
+ }
312
+
313
+ // Update crc with 64 bytes of data from p.
314
+ ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t Process64BytesCRC(const uint8_t* p,
315
+ uint64_t crc) const {
316
+ for (int i = 0; i < 8; i++) {
317
+ crc =
318
+ CRC32_u64(static_cast<uint32_t>(crc), absl::little_endian::Load64(p));
319
+ p += 8;
320
+ }
321
+ return crc;
322
+ }
323
+
324
+ // Generated by crc32c_x86_test --crc32c_generate_constants=true
325
+ // and verified against constants in linux kernel for S390:
326
+ // https://github.com/torvalds/linux/blob/master/arch/s390/crypto/crc32le-vx.S
327
+ alignas(16) static constexpr uint64_t k1k2[2] = {0x0740eef02, 0x09e4addf8};
328
+ alignas(16) static constexpr uint64_t k3k4[2] = {0x1384aa63a, 0x0ba4fc28e};
329
+ alignas(16) static constexpr uint64_t k5k6[2] = {0x0f20c0dfe, 0x14cd00bd6};
330
+ alignas(16) static constexpr uint64_t k7k0[2] = {0x0dd45aab8, 0x000000000};
331
+ alignas(16) static constexpr uint64_t kPoly[2] = {0x105ec76f0, 0x0dea713f1};
332
+ alignas(16) static constexpr uint32_t kMask[4] = {~0u, 0u, ~0u, 0u};
333
+
334
+ // Medium runs of bytes are broken into groups of kGroupsSmall blocks of same
335
+ // size. Each group is CRCed in parallel then combined at the end of the
336
+ // block.
337
+ static constexpr size_t kGroupsSmall = 3;
338
+ // For large runs we use up to kMaxStreams blocks computed with CRC
339
+ // instruction, and up to kMaxStreams blocks computed with PCLMULQDQ, which
340
+ // are combined in the end.
341
+ static constexpr size_t kMaxStreams = 3;
342
+ };
343
+
344
+ #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
345
+ alignas(16) constexpr uint64_t
346
+ CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k1k2[2];
347
+ alignas(16) constexpr uint64_t
348
+ CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k3k4[2];
349
+ alignas(16) constexpr uint64_t
350
+ CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k5k6[2];
351
+ alignas(16) constexpr uint64_t
352
+ CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k7k0[2];
353
+ alignas(16) constexpr uint64_t
354
+ CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kPoly[2];
355
+ alignas(16) constexpr uint32_t
356
+ CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kMask[4];
357
+ constexpr size_t
358
+ CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kGroupsSmall;
359
+ constexpr size_t CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kMaxStreams;
360
+ #endif // ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
361
+
362
+ template <size_t num_crc_streams, size_t num_pclmul_streams,
363
+ CutoffStrategy strategy>
364
+ class CRC32AcceleratedX86ARMCombinedMultipleStreams
365
+ : public CRC32AcceleratedX86ARMCombinedMultipleStreamsBase {
366
+ ABSL_ATTRIBUTE_HOT
367
+ void Extend(uint32_t* crc, const void* bytes, size_t length) const override {
368
+ static_assert(num_crc_streams >= 1 && num_crc_streams <= kMaxStreams,
369
+ "Invalid number of crc streams");
370
+ static_assert(num_pclmul_streams >= 0 && num_pclmul_streams <= kMaxStreams,
371
+ "Invalid number of pclmul streams");
372
+ const uint8_t* p = static_cast<const uint8_t*>(bytes);
373
+ const uint8_t* e = p + length;
374
+ uint32_t l = *crc;
375
+ uint64_t l64;
376
+
377
+ // We have dedicated instruction for 1,2,4 and 8 bytes.
378
+ if (length & 8) {
379
+ ABSL_INTERNAL_STEP8(l, p);
380
+ length &= ~size_t{8};
381
+ }
382
+ if (length & 4) {
383
+ ABSL_INTERNAL_STEP4(l);
384
+ length &= ~size_t{4};
385
+ }
386
+ if (length & 2) {
387
+ ABSL_INTERNAL_STEP2(l);
388
+ length &= ~size_t{2};
389
+ }
390
+ if (length & 1) {
391
+ ABSL_INTERNAL_STEP1(l);
392
+ length &= ~size_t{1};
393
+ }
394
+ if (length == 0) {
395
+ *crc = l;
396
+ return;
397
+ }
398
+ // length is now multiple of 16.
399
+
400
+ // For small blocks just run simple loop, because cost of combining multiple
401
+ // streams is significant.
402
+ if (strategy != CutoffStrategy::Unroll64CRC) {
403
+ if (length < kSmallCutoff) {
404
+ while (length >= 16) {
405
+ ABSL_INTERNAL_STEP8(l, p);
406
+ ABSL_INTERNAL_STEP8(l, p);
407
+ length -= 16;
408
+ }
409
+ *crc = l;
410
+ return;
411
+ }
412
+ }
413
+
414
+ // For medium blocks we run 3 crc streams and combine them as described in
415
+ // Intel paper above. Running 4th stream doesn't help, because crc
416
+ // instruction has latency 3 and throughput 1.
417
+ if (length < kMediumCutoff) {
418
+ l64 = l;
419
+ if (strategy == CutoffStrategy::Fold3) {
420
+ uint64_t l641 = 0;
421
+ uint64_t l642 = 0;
422
+ const size_t blockSize = 32;
423
+ size_t bs = static_cast<size_t>(e - p) / kGroupsSmall / blockSize;
424
+ const uint8_t* p1 = p + bs * blockSize;
425
+ const uint8_t* p2 = p1 + bs * blockSize;
426
+
427
+ for (size_t i = 0; i + 1 < bs; ++i) {
428
+ ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2);
429
+ ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2);
430
+ ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2);
431
+ ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2);
432
+ PrefetchToLocalCache(
433
+ reinterpret_cast<const char*>(p + kPrefetchHorizonMedium));
434
+ PrefetchToLocalCache(
435
+ reinterpret_cast<const char*>(p1 + kPrefetchHorizonMedium));
436
+ PrefetchToLocalCache(
437
+ reinterpret_cast<const char*>(p2 + kPrefetchHorizonMedium));
438
+ }
439
+ // Don't run crc on last 8 bytes.
440
+ ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2);
441
+ ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2);
442
+ ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2);
443
+ ABSL_INTERNAL_STEP8BY2(l64, l641, p, p1);
444
+
445
+ V128 magic = *(reinterpret_cast<const V128*>(kClmulConstants) + bs - 1);
446
+
447
+ V128 tmp = V128_From2x64(0, l64);
448
+
449
+ V128 res1 = V128_PMulLow(tmp, magic);
450
+
451
+ tmp = V128_From2x64(0, l641);
452
+
453
+ V128 res2 = V128_PMul10(tmp, magic);
454
+ V128 x = V128_Xor(res1, res2);
455
+ l64 = static_cast<uint64_t>(V128_Low64(x)) ^
456
+ absl::little_endian::Load64(p2);
457
+ l64 = CRC32_u64(static_cast<uint32_t>(l642), l64);
458
+
459
+ p = p2 + 8;
460
+ } else if (strategy == CutoffStrategy::Unroll64CRC) {
461
+ while ((e - p) >= 64) {
462
+ l64 = Process64BytesCRC(p, l64);
463
+ p += 64;
464
+ }
465
+ }
466
+ } else {
467
+ // There is a lot of data, we can ignore combine costs and run all
468
+ // requested streams (num_crc_streams + num_pclmul_streams),
469
+ // using prefetch. CRC and PCLMULQDQ use different cpu execution units,
470
+ // so on some cpus it makes sense to execute both of them for different
471
+ // streams.
472
+
473
+ // Point x at first 8-byte aligned byte in string.
474
+ const uint8_t* x = RoundUp<8>(p);
475
+ // Process bytes until p is 8-byte aligned, if that isn't past the end.
476
+ while (p != x) {
477
+ ABSL_INTERNAL_STEP1(l);
478
+ }
479
+
480
+ size_t bs = static_cast<size_t>(e - p) /
481
+ (num_crc_streams + num_pclmul_streams) / 64;
482
+ const uint8_t* crc_streams[kMaxStreams];
483
+ const uint8_t* pclmul_streams[kMaxStreams];
484
+ // We are guaranteed to have at least one crc stream.
485
+ crc_streams[0] = p;
486
+ for (size_t i = 1; i < num_crc_streams; i++) {
487
+ crc_streams[i] = crc_streams[i - 1] + bs * 64;
488
+ }
489
+ pclmul_streams[0] = crc_streams[num_crc_streams - 1] + bs * 64;
490
+ for (size_t i = 1; i < num_pclmul_streams; i++) {
491
+ pclmul_streams[i] = pclmul_streams[i - 1] + bs * 64;
492
+ }
493
+
494
+ // Per stream crc sums.
495
+ uint64_t l64_crc[kMaxStreams] = {l};
496
+ uint64_t l64_pclmul[kMaxStreams] = {0};
497
+
498
+ // Peel first iteration, because PCLMULQDQ stream, needs setup.
499
+ for (size_t i = 0; i < num_crc_streams; i++) {
500
+ l64_crc[i] = Process64BytesCRC(crc_streams[i], l64_crc[i]);
501
+ crc_streams[i] += 16 * 4;
502
+ }
503
+
504
+ V128 partialCRC[kMaxStreams][4];
505
+ for (size_t i = 0; i < num_pclmul_streams; i++) {
506
+ partialCRC[i][0] = V128_LoadU(
507
+ reinterpret_cast<const V128*>(pclmul_streams[i] + 16 * 0));
508
+ partialCRC[i][1] = V128_LoadU(
509
+ reinterpret_cast<const V128*>(pclmul_streams[i] + 16 * 1));
510
+ partialCRC[i][2] = V128_LoadU(
511
+ reinterpret_cast<const V128*>(pclmul_streams[i] + 16 * 2));
512
+ partialCRC[i][3] = V128_LoadU(
513
+ reinterpret_cast<const V128*>(pclmul_streams[i] + 16 * 3));
514
+ pclmul_streams[i] += 16 * 4;
515
+ }
516
+
517
+ for (size_t i = 1; i < bs; i++) {
518
+ // Prefetch data for next iterations.
519
+ for (size_t j = 0; j < num_crc_streams; j++) {
520
+ PrefetchToLocalCache(
521
+ reinterpret_cast<const char*>(crc_streams[j] + kPrefetchHorizon));
522
+ }
523
+ for (size_t j = 0; j < num_pclmul_streams; j++) {
524
+ PrefetchToLocalCache(reinterpret_cast<const char*>(pclmul_streams[j] +
525
+ kPrefetchHorizon));
526
+ }
527
+
528
+ // We process each stream in 64 byte blocks. This can be written as
529
+ // for (int i = 0; i < num_pclmul_streams; i++) {
530
+ // Process64BytesPclmul(pclmul_streams[i], partialCRC[i]);
531
+ // pclmul_streams[i] += 16 * 4;
532
+ // }
533
+ // for (int i = 0; i < num_crc_streams; i++) {
534
+ // l64_crc[i] = Process64BytesCRC(crc_streams[i], l64_crc[i]);
535
+ // crc_streams[i] += 16*4;
536
+ // }
537
+ // But unrolling and interleaving PCLMULQDQ and CRC blocks manually
538
+ // gives ~2% performance boost.
539
+ l64_crc[0] = Process64BytesCRC(crc_streams[0], l64_crc[0]);
540
+ crc_streams[0] += 16 * 4;
541
+ if (num_pclmul_streams > 0) {
542
+ Process64BytesPclmul(pclmul_streams[0], partialCRC[0]);
543
+ pclmul_streams[0] += 16 * 4;
544
+ }
545
+ if (num_crc_streams > 1) {
546
+ l64_crc[1] = Process64BytesCRC(crc_streams[1], l64_crc[1]);
547
+ crc_streams[1] += 16 * 4;
548
+ }
549
+ if (num_pclmul_streams > 1) {
550
+ Process64BytesPclmul(pclmul_streams[1], partialCRC[1]);
551
+ pclmul_streams[1] += 16 * 4;
552
+ }
553
+ if (num_crc_streams > 2) {
554
+ l64_crc[2] = Process64BytesCRC(crc_streams[2], l64_crc[2]);
555
+ crc_streams[2] += 16 * 4;
556
+ }
557
+ if (num_pclmul_streams > 2) {
558
+ Process64BytesPclmul(pclmul_streams[2], partialCRC[2]);
559
+ pclmul_streams[2] += 16 * 4;
560
+ }
561
+ }
562
+
563
+ // PCLMULQDQ based streams require special final step;
564
+ // CRC based don't.
565
+ for (size_t i = 0; i < num_pclmul_streams; i++) {
566
+ l64_pclmul[i] = FinalizePclmulStream(partialCRC[i]);
567
+ }
568
+
569
+ // Combine all streams into single result.
570
+ uint32_t magic = ComputeZeroConstant(bs * 64);
571
+ l64 = l64_crc[0];
572
+ for (size_t i = 1; i < num_crc_streams; i++) {
573
+ l64 = multiply(static_cast<uint32_t>(l64), magic);
574
+ l64 ^= l64_crc[i];
575
+ }
576
+ for (size_t i = 0; i < num_pclmul_streams; i++) {
577
+ l64 = multiply(static_cast<uint32_t>(l64), magic);
578
+ l64 ^= l64_pclmul[i];
579
+ }
580
+
581
+ // Update p.
582
+ if (num_pclmul_streams > 0) {
583
+ p = pclmul_streams[num_pclmul_streams - 1];
584
+ } else {
585
+ p = crc_streams[num_crc_streams - 1];
586
+ }
587
+ }
588
+ l = static_cast<uint32_t>(l64);
589
+
590
+ while ((e - p) >= 16) {
591
+ ABSL_INTERNAL_STEP8(l, p);
592
+ ABSL_INTERNAL_STEP8(l, p);
593
+ }
594
+ // Process the last few bytes
595
+ while (p != e) {
596
+ ABSL_INTERNAL_STEP1(l);
597
+ }
598
+
599
+ #undef ABSL_INTERNAL_STEP8BY3
600
+ #undef ABSL_INTERNAL_STEP8BY2
601
+ #undef ABSL_INTERNAL_STEP8
602
+ #undef ABSL_INTERNAL_STEP4
603
+ #undef ABSL_INTERNAL_STEP2
604
+ #undef ABSL_INTERNAL_STEP1
605
+
606
+ *crc = l;
607
+ }
608
+ };
609
+
610
+ } // namespace
611
+
612
+ // Intel processors with SSE4.2 have an instruction for one particular
613
+ // 32-bit CRC polynomial: crc32c
614
+ CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() {
615
+ CpuType type = GetCpuType();
616
+ switch (type) {
617
+ case CpuType::kIntelHaswell:
618
+ case CpuType::kAmdRome:
619
+ case CpuType::kAmdNaples:
620
+ case CpuType::kAmdMilan:
621
+ return new CRC32AcceleratedX86ARMCombinedMultipleStreams<
622
+ 3, 1, CutoffStrategy::Fold3>();
623
+ // PCLMULQDQ is fast, use combined PCLMULQDQ + CRC implementation.
624
+ case CpuType::kIntelCascadelakeXeon:
625
+ case CpuType::kIntelSkylakeXeon:
626
+ case CpuType::kIntelBroadwell:
627
+ case CpuType::kIntelSkylake:
628
+ return new CRC32AcceleratedX86ARMCombinedMultipleStreams<
629
+ 3, 2, CutoffStrategy::Fold3>();
630
+ // PCLMULQDQ is slow, don't use it.
631
+ case CpuType::kIntelIvybridge:
632
+ case CpuType::kIntelSandybridge:
633
+ case CpuType::kIntelWestmere:
634
+ return new CRC32AcceleratedX86ARMCombinedMultipleStreams<
635
+ 3, 0, CutoffStrategy::Fold3>();
636
+ case CpuType::kArmNeoverseN1:
637
+ case CpuType::kArmNeoverseN2:
638
+ case CpuType::kArmNeoverseV1:
639
+ return new CRC32AcceleratedX86ARMCombinedMultipleStreams<
640
+ 1, 1, CutoffStrategy::Unroll64CRC>();
641
+ case CpuType::kAmpereSiryn:
642
+ return new CRC32AcceleratedX86ARMCombinedMultipleStreams<
643
+ 3, 2, CutoffStrategy::Fold3>();
644
+ case CpuType::kArmNeoverseV2:
645
+ return new CRC32AcceleratedX86ARMCombinedMultipleStreams<
646
+ 1, 2, CutoffStrategy::Unroll64CRC>();
647
+ #if defined(__aarch64__)
648
+ default:
649
+ // Not all ARM processors support the needed instructions, so check here
650
+ // before trying to use an accelerated implementation.
651
+ if (SupportsArmCRC32PMULL()) {
652
+ return new CRC32AcceleratedX86ARMCombinedMultipleStreams<
653
+ 1, 1, CutoffStrategy::Unroll64CRC>();
654
+ } else {
655
+ return nullptr;
656
+ }
657
+ #else
658
+ default:
659
+ // Something else, play it safe and assume slow PCLMULQDQ.
660
+ return new CRC32AcceleratedX86ARMCombinedMultipleStreams<
661
+ 3, 0, CutoffStrategy::Fold3>();
662
+ #endif
663
+ }
664
+ }
665
+
666
+ std::vector<std::unique_ptr<CRCImpl>> NewCRC32AcceleratedX86ARMCombinedAll() {
667
+ auto ret = std::vector<std::unique_ptr<CRCImpl>>();
668
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
669
+ 1, 0, CutoffStrategy::Fold3>>());
670
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
671
+ 1, 1, CutoffStrategy::Fold3>>());
672
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
673
+ 1, 2, CutoffStrategy::Fold3>>());
674
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
675
+ 1, 3, CutoffStrategy::Fold3>>());
676
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
677
+ 2, 0, CutoffStrategy::Fold3>>());
678
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
679
+ 2, 1, CutoffStrategy::Fold3>>());
680
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
681
+ 2, 2, CutoffStrategy::Fold3>>());
682
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
683
+ 2, 3, CutoffStrategy::Fold3>>());
684
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
685
+ 3, 0, CutoffStrategy::Fold3>>());
686
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
687
+ 3, 1, CutoffStrategy::Fold3>>());
688
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
689
+ 3, 2, CutoffStrategy::Fold3>>());
690
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
691
+ 3, 3, CutoffStrategy::Fold3>>());
692
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
693
+ 1, 0, CutoffStrategy::Unroll64CRC>>());
694
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
695
+ 1, 1, CutoffStrategy::Unroll64CRC>>());
696
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
697
+ 1, 2, CutoffStrategy::Unroll64CRC>>());
698
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
699
+ 1, 3, CutoffStrategy::Unroll64CRC>>());
700
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
701
+ 2, 0, CutoffStrategy::Unroll64CRC>>());
702
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
703
+ 2, 1, CutoffStrategy::Unroll64CRC>>());
704
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
705
+ 2, 2, CutoffStrategy::Unroll64CRC>>());
706
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
707
+ 2, 3, CutoffStrategy::Unroll64CRC>>());
708
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
709
+ 3, 0, CutoffStrategy::Unroll64CRC>>());
710
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
711
+ 3, 1, CutoffStrategy::Unroll64CRC>>());
712
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
713
+ 3, 2, CutoffStrategy::Unroll64CRC>>());
714
+ ret.push_back(absl::make_unique<CRC32AcceleratedX86ARMCombinedMultipleStreams<
715
+ 3, 3, CutoffStrategy::Unroll64CRC>>());
716
+
717
+ return ret;
718
+ }
719
+
720
+ #else // !ABSL_INTERNAL_CAN_USE_SIMD_CRC32C
721
+
722
+ std::vector<std::unique_ptr<CRCImpl>> NewCRC32AcceleratedX86ARMCombinedAll() {
723
+ return std::vector<std::unique_ptr<CRCImpl>>();
724
+ }
725
+
726
+ // no hardware acceleration available
727
+ CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() { return nullptr; }
728
+
729
+ #endif
730
+
731
+ } // namespace crc_internal
732
+ ABSL_NAMESPACE_END
733
+ } // namespace absl
weight/_dep/abseil-cpp/absl/crc/internal/non_temporal_arm_intrinsics.h ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_CRC_INTERNAL_NON_TEMPORAL_ARM_INTRINSICS_H_
16
+ #define ABSL_CRC_INTERNAL_NON_TEMPORAL_ARM_INTRINSICS_H_
17
+
18
+ #include "absl/base/config.h"
19
+
20
+ #ifdef __aarch64__
21
+ #include <arm_neon.h>
22
+
23
+ typedef int64x2_t __m128i; /* 128-bit vector containing integers */
24
+ #define vreinterpretq_m128i_s32(x) vreinterpretq_s64_s32(x)
25
+ #define vreinterpretq_s64_m128i(x) (x)
26
+
27
+ // Guarantees that every preceding store is globally visible before any
28
+ // subsequent store.
29
+ // https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx
30
+ static inline __attribute__((always_inline)) void _mm_sfence(void) {
31
+ __sync_synchronize();
32
+ }
33
+
34
+ // Load 128-bits of integer data from unaligned memory into dst. This intrinsic
35
+ // may perform better than _mm_loadu_si128 when the data crosses a cache line
36
+ // boundary.
37
+ //
38
+ // dst[127:0] := MEM[mem_addr+127:mem_addr]
39
+ //
40
+ // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_lddqu_si128
41
+ #define _mm_lddqu_si128 _mm_loadu_si128
42
+
43
+ // Loads 128-bit value. :
44
+ // https://msdn.microsoft.com/zh-cn/library/f4k12ae8(v=vs.90).aspx
45
+ static inline __attribute__((always_inline)) __m128i _mm_loadu_si128(
46
+ const __m128i *p) {
47
+ return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *)p));
48
+ }
49
+
50
+ // Stores the data in a to the address p without polluting the caches. If the
51
+ // cache line containing address p is already in the cache, the cache will be
52
+ // updated.
53
+ // https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx
54
+ static inline __attribute__((always_inline)) void _mm_stream_si128(__m128i *p,
55
+ __m128i a) {
56
+ #if ABSL_HAVE_BUILTIN(__builtin_nontemporal_store)
57
+ __builtin_nontemporal_store(a, p);
58
+ #else
59
+ vst1q_s64((int64_t *)p, vreinterpretq_s64_m128i(a));
60
+ #endif
61
+ }
62
+
63
+ // Sets the 16 signed 8-bit integer values.
64
+ // https://msdn.microsoft.com/en-us/library/x0cx8zd3(v=vs.90).aspx
65
+ static inline __attribute__((always_inline)) __m128i _mm_set_epi8(
66
+ signed char b15, signed char b14, signed char b13, signed char b12,
67
+ signed char b11, signed char b10, signed char b9, signed char b8,
68
+ signed char b7, signed char b6, signed char b5, signed char b4,
69
+ signed char b3, signed char b2, signed char b1, signed char b0) {
70
+ int8_t __attribute__((aligned(16)))
71
+ data[16] = {(int8_t)b0, (int8_t)b1, (int8_t)b2, (int8_t)b3,
72
+ (int8_t)b4, (int8_t)b5, (int8_t)b6, (int8_t)b7,
73
+ (int8_t)b8, (int8_t)b9, (int8_t)b10, (int8_t)b11,
74
+ (int8_t)b12, (int8_t)b13, (int8_t)b14, (int8_t)b15};
75
+ return (__m128i)vld1q_s8(data);
76
+ }
77
+ #endif // __aarch64__
78
+
79
+ #endif // ABSL_CRC_INTERNAL_NON_TEMPORAL_ARM_INTRINSICS_H_
weight/_dep/abseil-cpp/absl/crc/internal/non_temporal_memcpy.h ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_CRC_INTERNAL_NON_TEMPORAL_MEMCPY_H_
16
+ #define ABSL_CRC_INTERNAL_NON_TEMPORAL_MEMCPY_H_
17
+
18
+ #ifdef _MSC_VER
19
+ #include <intrin.h>
20
+ #endif
21
+
22
+ #ifdef __SSE__
23
+ #include <xmmintrin.h>
24
+ #endif
25
+
26
+ #ifdef __SSE2__
27
+ #include <emmintrin.h>
28
+ #endif
29
+
30
+ #ifdef __SSE3__
31
+ #include <pmmintrin.h>
32
+ #endif
33
+
34
+ #ifdef __AVX__
35
+ #include <immintrin.h>
36
+ #endif
37
+
38
+ #ifdef __aarch64__
39
+ #include "absl/crc/internal/non_temporal_arm_intrinsics.h"
40
+ #endif
41
+
42
+ #include <algorithm>
43
+ #include <cassert>
44
+ #include <cstdint>
45
+ #include <cstring>
46
+
47
+ #include "absl/base/config.h"
48
+ #include "absl/base/optimization.h"
49
+
50
+ namespace absl {
51
+ ABSL_NAMESPACE_BEGIN
52
+ namespace crc_internal {
53
+
54
+ // This non-temporal memcpy does regular load and non-temporal store memory
55
+ // copy. It is compatible to both 16-byte aligned and unaligned addresses. If
56
+ // data at the destination is not immediately accessed, using non-temporal
57
+ // memcpy can save 1 DRAM load of the destination cacheline.
58
+ constexpr size_t kCacheLineSize = ABSL_CACHELINE_SIZE;
59
+
60
+ // If the objects overlap, the behavior is undefined.
61
+ inline void *non_temporal_store_memcpy(void *__restrict dst,
62
+ const void *__restrict src, size_t len) {
63
+ #if defined(__SSE3__) || defined(__aarch64__) || \
64
+ (defined(_MSC_VER) && defined(__AVX__))
65
+ // This implementation requires SSE3.
66
+ // MSVC cannot target SSE3 directly, but when MSVC targets AVX,
67
+ // SSE3 support is implied.
68
+ uint8_t *d = reinterpret_cast<uint8_t *>(dst);
69
+ const uint8_t *s = reinterpret_cast<const uint8_t *>(src);
70
+
71
+ // memcpy() the misaligned header. At the end of this if block, <d> is
72
+ // aligned to a 64-byte cacheline boundary or <len> == 0.
73
+ if (reinterpret_cast<uintptr_t>(d) & (kCacheLineSize - 1)) {
74
+ uintptr_t bytes_before_alignment_boundary =
75
+ kCacheLineSize -
76
+ (reinterpret_cast<uintptr_t>(d) & (kCacheLineSize - 1));
77
+ size_t header_len = (std::min)(bytes_before_alignment_boundary, len);
78
+ assert(bytes_before_alignment_boundary < kCacheLineSize);
79
+ memcpy(d, s, header_len);
80
+ d += header_len;
81
+ s += header_len;
82
+ len -= header_len;
83
+ }
84
+
85
+ if (len >= kCacheLineSize) {
86
+ _mm_sfence();
87
+ __m128i *dst_cacheline = reinterpret_cast<__m128i *>(d);
88
+ const __m128i *src_cacheline = reinterpret_cast<const __m128i *>(s);
89
+ constexpr int kOpsPerCacheLine = kCacheLineSize / sizeof(__m128i);
90
+ size_t loops = len / kCacheLineSize;
91
+
92
+ while (len >= kCacheLineSize) {
93
+ __m128i temp1, temp2, temp3, temp4;
94
+ temp1 = _mm_lddqu_si128(src_cacheline + 0);
95
+ temp2 = _mm_lddqu_si128(src_cacheline + 1);
96
+ temp3 = _mm_lddqu_si128(src_cacheline + 2);
97
+ temp4 = _mm_lddqu_si128(src_cacheline + 3);
98
+ _mm_stream_si128(dst_cacheline + 0, temp1);
99
+ _mm_stream_si128(dst_cacheline + 1, temp2);
100
+ _mm_stream_si128(dst_cacheline + 2, temp3);
101
+ _mm_stream_si128(dst_cacheline + 3, temp4);
102
+ src_cacheline += kOpsPerCacheLine;
103
+ dst_cacheline += kOpsPerCacheLine;
104
+ len -= kCacheLineSize;
105
+ }
106
+ d += loops * kCacheLineSize;
107
+ s += loops * kCacheLineSize;
108
+ _mm_sfence();
109
+ }
110
+
111
+ // memcpy the tail.
112
+ if (len) {
113
+ memcpy(d, s, len);
114
+ }
115
+ return dst;
116
+ #else
117
+ // Fallback to regular memcpy.
118
+ return memcpy(dst, src, len);
119
+ #endif // __SSE3__ || __aarch64__ || (_MSC_VER && __AVX__)
120
+ }
121
+
122
+ inline void *non_temporal_store_memcpy_avx(void *__restrict dst,
123
+ const void *__restrict src,
124
+ size_t len) {
125
+ #ifdef __AVX__
126
+ uint8_t *d = reinterpret_cast<uint8_t *>(dst);
127
+ const uint8_t *s = reinterpret_cast<const uint8_t *>(src);
128
+
129
+ // memcpy() the misaligned header. At the end of this if block, <d> is
130
+ // aligned to a 64-byte cacheline boundary or <len> == 0.
131
+ if (reinterpret_cast<uintptr_t>(d) & (kCacheLineSize - 1)) {
132
+ uintptr_t bytes_before_alignment_boundary =
133
+ kCacheLineSize -
134
+ (reinterpret_cast<uintptr_t>(d) & (kCacheLineSize - 1));
135
+ size_t header_len = (std::min)(bytes_before_alignment_boundary, len);
136
+ assert(bytes_before_alignment_boundary < kCacheLineSize);
137
+ memcpy(d, s, header_len);
138
+ d += header_len;
139
+ s += header_len;
140
+ len -= header_len;
141
+ }
142
+
143
+ if (len >= kCacheLineSize) {
144
+ _mm_sfence();
145
+ __m256i *dst_cacheline = reinterpret_cast<__m256i *>(d);
146
+ const __m256i *src_cacheline = reinterpret_cast<const __m256i *>(s);
147
+ constexpr int kOpsPerCacheLine = kCacheLineSize / sizeof(__m256i);
148
+ size_t loops = len / kCacheLineSize;
149
+
150
+ while (len >= kCacheLineSize) {
151
+ __m256i temp1, temp2;
152
+ temp1 = _mm256_lddqu_si256(src_cacheline + 0);
153
+ temp2 = _mm256_lddqu_si256(src_cacheline + 1);
154
+ _mm256_stream_si256(dst_cacheline + 0, temp1);
155
+ _mm256_stream_si256(dst_cacheline + 1, temp2);
156
+ src_cacheline += kOpsPerCacheLine;
157
+ dst_cacheline += kOpsPerCacheLine;
158
+ len -= kCacheLineSize;
159
+ }
160
+ d += loops * kCacheLineSize;
161
+ s += loops * kCacheLineSize;
162
+ _mm_sfence();
163
+ }
164
+
165
+ // memcpy the tail.
166
+ if (len) {
167
+ memcpy(d, s, len);
168
+ }
169
+ return dst;
170
+ #else
171
+ // Fallback to regular memcpy when AVX is not available.
172
+ return memcpy(dst, src, len);
173
+ #endif // __AVX__
174
+ }
175
+
176
+ } // namespace crc_internal
177
+ ABSL_NAMESPACE_END
178
+ } // namespace absl
179
+
180
+ #endif // ABSL_CRC_INTERNAL_NON_TEMPORAL_MEMCPY_H_
weight/_dep/abseil-cpp/absl/crc/internal/non_temporal_memcpy_test.cc ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2022 The Abseil Authors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/crc/internal/non_temporal_memcpy.h"
16
+
17
+ #include <algorithm>
18
+ #include <cstdint>
19
+ #include <iostream>
20
+ #include <vector>
21
+
22
+ #include "gtest/gtest.h"
23
+
24
+ namespace {
25
+
26
+ struct TestParam {
27
+ size_t copy_size;
28
+ uint32_t src_offset;
29
+ uint32_t dst_offset;
30
+ };
31
+
32
+ class NonTemporalMemcpyTest : public testing::TestWithParam<TestParam> {
33
+ protected:
34
+ void SetUp() override {
35
+ // Make buf_size multiple of 16 bytes.
36
+ size_t buf_size = ((std::max(GetParam().src_offset, GetParam().dst_offset) +
37
+ GetParam().copy_size) +
38
+ 15) /
39
+ 16 * 16;
40
+ a_.resize(buf_size);
41
+ b_.resize(buf_size);
42
+ for (size_t i = 0; i < buf_size; i++) {
43
+ a_[i] = static_cast<uint8_t>(i % 256);
44
+ b_[i] = ~a_[i];
45
+ }
46
+ }
47
+
48
+ std::vector<uint8_t> a_, b_;
49
+ };
50
+
51
+ TEST_P(NonTemporalMemcpyTest, SSEEquality) {
52
+ uint8_t *src = a_.data() + GetParam().src_offset;
53
+ uint8_t *dst = b_.data() + GetParam().dst_offset;
54
+ absl::crc_internal::non_temporal_store_memcpy(dst, src, GetParam().copy_size);
55
+ for (size_t i = 0; i < GetParam().copy_size; i++) {
56
+ EXPECT_EQ(src[i], dst[i]);
57
+ }
58
+ }
59
+
60
+ TEST_P(NonTemporalMemcpyTest, AVXEquality) {
61
+ uint8_t* src = a_.data() + GetParam().src_offset;
62
+ uint8_t* dst = b_.data() + GetParam().dst_offset;
63
+
64
+ absl::crc_internal::non_temporal_store_memcpy_avx(dst, src,
65
+ GetParam().copy_size);
66
+ for (size_t i = 0; i < GetParam().copy_size; i++) {
67
+ EXPECT_EQ(src[i], dst[i]);
68
+ }
69
+ }
70
+
71
+ // 63B is smaller than one cacheline operation thus the non-temporal routine
72
+ // will not be called.
73
+ // 4352B is sufficient for testing 4092B data copy with room for offsets.
74
+ constexpr TestParam params[] = {
75
+ {63, 0, 0}, {58, 5, 5}, {61, 2, 0}, {61, 0, 2},
76
+ {58, 5, 2}, {4096, 0, 0}, {4096, 0, 1}, {4096, 0, 2},
77
+ {4096, 0, 3}, {4096, 0, 4}, {4096, 0, 5}, {4096, 0, 6},
78
+ {4096, 0, 7}, {4096, 0, 8}, {4096, 0, 9}, {4096, 0, 10},
79
+ {4096, 0, 11}, {4096, 0, 12}, {4096, 0, 13}, {4096, 0, 14},
80
+ {4096, 0, 15}, {4096, 7, 7}, {4096, 3, 0}, {4096, 1, 0},
81
+ {4096, 9, 3}, {4096, 9, 11}, {8192, 0, 0}, {8192, 5, 2},
82
+ {1024768, 7, 11}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0},
83
+ {1, 1, 1}};
84
+
85
+ INSTANTIATE_TEST_SUITE_P(ParameterizedNonTemporalMemcpyTest,
86
+ NonTemporalMemcpyTest, testing::ValuesIn(params));
87
+
88
+ } // namespace
weight/_dep/abseil-cpp/absl/debugging/BUILD.bazel ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Copyright 2017 The Abseil Authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # https://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ load(
18
+ "//absl:copts/configure_copts.bzl",
19
+ "ABSL_DEFAULT_COPTS",
20
+ "ABSL_DEFAULT_LINKOPTS",
21
+ "ABSL_TEST_COPTS",
22
+ )
23
+
24
+ package(
25
+ default_visibility = ["//visibility:public"],
26
+ features = [
27
+ "header_modules",
28
+ "layering_check",
29
+ "parse_headers",
30
+ ],
31
+ )
32
+
33
+ licenses(["notice"])
34
+
35
+ cc_library(
36
+ name = "stacktrace",
37
+ srcs = [
38
+ "internal/stacktrace_aarch64-inl.inc",
39
+ "internal/stacktrace_arm-inl.inc",
40
+ "internal/stacktrace_config.h",
41
+ "internal/stacktrace_emscripten-inl.inc",
42
+ "internal/stacktrace_generic-inl.inc",
43
+ "internal/stacktrace_powerpc-inl.inc",
44
+ "internal/stacktrace_riscv-inl.inc",
45
+ "internal/stacktrace_unimplemented-inl.inc",
46
+ "internal/stacktrace_win32-inl.inc",
47
+ "internal/stacktrace_x86-inl.inc",
48
+ "stacktrace.cc",
49
+ ],
50
+ hdrs = ["stacktrace.h"],
51
+ copts = ABSL_DEFAULT_COPTS,
52
+ linkopts = ABSL_DEFAULT_LINKOPTS,
53
+ deps = [
54
+ ":debugging_internal",
55
+ "//absl/base:config",
56
+ "//absl/base:core_headers",
57
+ "//absl/base:dynamic_annotations",
58
+ "//absl/base:raw_logging_internal",
59
+ ],
60
+ )
61
+
62
+ cc_test(
63
+ name = "stacktrace_test",
64
+ srcs = ["stacktrace_test.cc"],
65
+ copts = ABSL_TEST_COPTS,
66
+ linkopts = ABSL_DEFAULT_LINKOPTS,
67
+ deps = [
68
+ ":stacktrace",
69
+ "//absl/base:core_headers",
70
+ "@com_google_googletest//:gtest",
71
+ "@com_google_googletest//:gtest_main",
72
+ ],
73
+ )
74
+
75
+ cc_library(
76
+ name = "symbolize",
77
+ srcs = [
78
+ "symbolize.cc",
79
+ "symbolize_darwin.inc",
80
+ "symbolize_elf.inc",
81
+ "symbolize_emscripten.inc",
82
+ "symbolize_unimplemented.inc",
83
+ "symbolize_win32.inc",
84
+ ],
85
+ hdrs = [
86
+ "internal/symbolize.h",
87
+ "symbolize.h",
88
+ ],
89
+ copts = ABSL_DEFAULT_COPTS,
90
+ linkopts = ABSL_DEFAULT_LINKOPTS + select({
91
+ "//absl:msvc_compiler": ["-DEFAULTLIB:dbghelp.lib"],
92
+ "//absl:clang-cl_compiler": ["-DEFAULTLIB:dbghelp.lib"],
93
+ "//absl:mingw_compiler": [
94
+ "-DEFAULTLIB:dbghelp.lib",
95
+ "-ldbghelp",
96
+ ],
97
+ "//conditions:default": [],
98
+ }),
99
+ deps = [
100
+ ":debugging_internal",
101
+ ":demangle_internal",
102
+ "//absl/base",
103
+ "//absl/base:config",
104
+ "//absl/base:core_headers",
105
+ "//absl/base:dynamic_annotations",
106
+ "//absl/base:malloc_internal",
107
+ "//absl/base:raw_logging_internal",
108
+ "//absl/strings",
109
+ ],
110
+ )
111
+
112
+ cc_test(
113
+ name = "symbolize_test",
114
+ srcs = ["symbolize_test.cc"],
115
+ copts = ABSL_TEST_COPTS + select({
116
+ "//absl:msvc_compiler": ["/Z7"],
117
+ "//absl:clang-cl_compiler": ["/Z7"],
118
+ "//conditions:default": [],
119
+ }),
120
+ linkopts = ABSL_DEFAULT_LINKOPTS + select({
121
+ "//absl:msvc_compiler": ["/DEBUG"],
122
+ "//absl:clang-cl_compiler": ["/DEBUG"],
123
+ "//conditions:default": [],
124
+ }),
125
+ deps = [
126
+ ":stack_consumption",
127
+ ":symbolize",
128
+ "//absl/base",
129
+ "//absl/base:config",
130
+ "//absl/base:core_headers",
131
+ "//absl/log",
132
+ "//absl/log:check",
133
+ "//absl/memory",
134
+ "//absl/strings",
135
+ "@com_google_googletest//:gtest",
136
+ ],
137
+ )
138
+
139
+ cc_library(
140
+ name = "examine_stack",
141
+ srcs = [
142
+ "internal/examine_stack.cc",
143
+ ],
144
+ hdrs = [
145
+ "internal/examine_stack.h",
146
+ ],
147
+ copts = ABSL_DEFAULT_COPTS,
148
+ linkopts = ABSL_DEFAULT_LINKOPTS,
149
+ visibility = ["//absl/log/internal:__pkg__"],
150
+ deps = [
151
+ ":stacktrace",
152
+ ":symbolize",
153
+ "//absl/base:config",
154
+ "//absl/base:core_headers",
155
+ "//absl/base:raw_logging_internal",
156
+ ],
157
+ )
158
+
159
+ cc_library(
160
+ name = "failure_signal_handler",
161
+ srcs = ["failure_signal_handler.cc"],
162
+ hdrs = ["failure_signal_handler.h"],
163
+ copts = ABSL_DEFAULT_COPTS,
164
+ linkopts = ABSL_DEFAULT_LINKOPTS,
165
+ deps = [
166
+ ":examine_stack",
167
+ ":stacktrace",
168
+ "//absl/base",
169
+ "//absl/base:config",
170
+ "//absl/base:core_headers",
171
+ "//absl/base:raw_logging_internal",
172
+ ],
173
+ )
174
+
175
+ cc_test(
176
+ name = "failure_signal_handler_test",
177
+ srcs = ["failure_signal_handler_test.cc"],
178
+ copts = ABSL_TEST_COPTS,
179
+ linkopts = select({
180
+ "//absl:msvc_compiler": [],
181
+ "//absl:clang-cl_compiler": [],
182
+ "//absl:wasm": [],
183
+ "//conditions:default": ["-pthread"],
184
+ }) + ABSL_DEFAULT_LINKOPTS,
185
+ deps = [
186
+ ":failure_signal_handler",
187
+ ":stacktrace",
188
+ ":symbolize",
189
+ "//absl/base:raw_logging_internal",
190
+ "//absl/log:check",
191
+ "//absl/strings",
192
+ "@com_google_googletest//:gtest",
193
+ ],
194
+ )
195
+
196
+ cc_library(
197
+ name = "debugging_internal",
198
+ srcs = [
199
+ "internal/address_is_readable.cc",
200
+ "internal/elf_mem_image.cc",
201
+ "internal/vdso_support.cc",
202
+ ],
203
+ hdrs = [
204
+ "internal/address_is_readable.h",
205
+ "internal/elf_mem_image.h",
206
+ "internal/vdso_support.h",
207
+ ],
208
+ copts = ABSL_DEFAULT_COPTS,
209
+ linkopts = ABSL_DEFAULT_LINKOPTS,
210
+ visibility = ["//visibility:private"],
211
+ deps = [
212
+ "//absl/base:config",
213
+ "//absl/base:core_headers",
214
+ "//absl/base:dynamic_annotations",
215
+ "//absl/base:errno_saver",
216
+ "//absl/base:raw_logging_internal",
217
+ ],
218
+ )
219
+
220
+ cc_library(
221
+ name = "demangle_internal",
222
+ srcs = ["internal/demangle.cc"],
223
+ hdrs = ["internal/demangle.h"],
224
+ copts = ABSL_DEFAULT_COPTS,
225
+ linkopts = ABSL_DEFAULT_LINKOPTS,
226
+ visibility = [
227
+ "//absl/container:__pkg__",
228
+ "//absl/debugging:__pkg__",
229
+ ],
230
+ deps = [
231
+ "//absl/base",
232
+ "//absl/base:config",
233
+ "//absl/base:core_headers",
234
+ ],
235
+ )
236
+
237
+ cc_test(
238
+ name = "demangle_test",
239
+ srcs = ["internal/demangle_test.cc"],
240
+ copts = ABSL_TEST_COPTS,
241
+ linkopts = ABSL_DEFAULT_LINKOPTS,
242
+ deps = [
243
+ ":demangle_internal",
244
+ ":stack_consumption",
245
+ "//absl/base:config",
246
+ "//absl/base:core_headers",
247
+ "//absl/log",
248
+ "//absl/memory",
249
+ "@com_google_googletest//:gtest",
250
+ "@com_google_googletest//:gtest_main",
251
+ ],
252
+ )
253
+
254
+ cc_library(
255
+ name = "leak_check",
256
+ srcs = ["leak_check.cc"],
257
+ hdrs = ["leak_check.h"],
258
+ copts = ABSL_DEFAULT_COPTS,
259
+ linkopts = ABSL_DEFAULT_LINKOPTS,
260
+ deps = [
261
+ "//absl/base:config",
262
+ "//absl/base:core_headers",
263
+ ],
264
+ )
265
+
266
+ cc_test(
267
+ name = "leak_check_test",
268
+ srcs = ["leak_check_test.cc"],
269
+ copts = ABSL_TEST_COPTS,
270
+ linkopts = ABSL_DEFAULT_LINKOPTS,
271
+ tags = ["notsan"],
272
+ deps = [
273
+ ":leak_check",
274
+ "//absl/base:config",
275
+ "//absl/log",
276
+ "@com_google_googletest//:gtest",
277
+ "@com_google_googletest//:gtest_main",
278
+ ],
279
+ )
280
+
281
+ # Binary that leaks memory and expects to fail on exit. This isn't a
282
+ # test that expected to pass on its own; it exists to be called by a
283
+ # script that checks exit status and output.
284
+ # TODO(absl-team): Write a test to run this with a script that
285
+ # verifies that it correctly fails.
286
+ cc_binary(
287
+ name = "leak_check_fail_test_binary",
288
+ srcs = ["leak_check_fail_test.cc"],
289
+ copts = ABSL_TEST_COPTS,
290
+ linkopts = ABSL_DEFAULT_LINKOPTS,
291
+ deps = [
292
+ ":leak_check",
293
+ "//absl/log",
294
+ "@com_google_googletest//:gtest",
295
+ "@com_google_googletest//:gtest_main",
296
+ ],
297
+ )
298
+
299
+ cc_library(
300
+ name = "stack_consumption",
301
+ testonly = 1,
302
+ srcs = ["internal/stack_consumption.cc"],
303
+ hdrs = ["internal/stack_consumption.h"],
304
+ copts = ABSL_DEFAULT_COPTS,
305
+ linkopts = ABSL_DEFAULT_LINKOPTS,
306
+ visibility = ["//visibility:private"],
307
+ deps = [
308
+ "//absl/base:config",
309
+ "//absl/base:core_headers",
310
+ "//absl/base:raw_logging_internal",
311
+ ],
312
+ )
313
+
314
+ cc_test(
315
+ name = "stack_consumption_test",
316
+ srcs = ["internal/stack_consumption_test.cc"],
317
+ copts = ABSL_TEST_COPTS,
318
+ linkopts = ABSL_DEFAULT_LINKOPTS,
319
+ tags = ["notsan"],
320
+ deps = [
321
+ ":stack_consumption",
322
+ "//absl/base:core_headers",
323
+ "//absl/log",
324
+ "@com_google_googletest//:gtest",
325
+ "@com_google_googletest//:gtest_main",
326
+ ],
327
+ )
328
+
329
+ cc_binary(
330
+ name = "stacktrace_benchmark",
331
+ testonly = 1,
332
+ srcs = ["stacktrace_benchmark.cc"],
333
+ copts = ABSL_TEST_COPTS,
334
+ linkopts = ABSL_DEFAULT_LINKOPTS,
335
+ tags = ["benchmark"],
336
+ deps = [
337
+ ":stacktrace",
338
+ "//absl/base:config",
339
+ "//absl/base:core_headers",
340
+ "@com_github_google_benchmark//:benchmark_main",
341
+ ],
342
+ )
weight/_dep/abseil-cpp/absl/debugging/failure_signal_handler.cc ADDED
@@ -0,0 +1,405 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Copyright 2018 The Abseil Authors.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // https://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ //
16
+
17
+ #include "absl/debugging/failure_signal_handler.h"
18
+
19
+ #include "absl/base/config.h"
20
+
21
+ #ifdef _WIN32
22
+ #include <windows.h>
23
+ #else
24
+ #include <sched.h>
25
+ #include <unistd.h>
26
+ #endif
27
+
28
+ #ifdef __APPLE__
29
+ #include <TargetConditionals.h>
30
+ #endif
31
+
32
+ #ifdef ABSL_HAVE_MMAP
33
+ #include <sys/mman.h>
34
+ #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
35
+ #define MAP_ANONYMOUS MAP_ANON
36
+ #endif
37
+ #endif
38
+
39
+ #ifdef __linux__
40
+ #include <sys/prctl.h>
41
+ #endif
42
+
43
+ #include <algorithm>
44
+ #include <atomic>
45
+ #include <cerrno>
46
+ #include <csignal>
47
+ #include <cstdio>
48
+ #include <cstring>
49
+ #include <ctime>
50
+
51
+ #include "absl/base/attributes.h"
52
+ #include "absl/base/internal/raw_logging.h"
53
+ #include "absl/base/internal/sysinfo.h"
54
+ #include "absl/debugging/internal/examine_stack.h"
55
+ #include "absl/debugging/stacktrace.h"
56
+
57
+ #if !defined(_WIN32) && !defined(__wasi__)
58
+ #define ABSL_HAVE_SIGACTION
59
+ // Apple WatchOS and TVOS don't allow sigaltstack
60
+ // Apple macOS has sigaltstack, but using it makes backtrace() unusable.
61
+ #if !(defined(TARGET_OS_OSX) && TARGET_OS_OSX) && \
62
+ !(defined(TARGET_OS_WATCH) && TARGET_OS_WATCH) && \
63
+ !(defined(TARGET_OS_TV) && TARGET_OS_TV) && !defined(__QNX__)
64
+ #define ABSL_HAVE_SIGALTSTACK
65
+ #endif
66
+ #endif
67
+
68
+ namespace absl {
69
+ ABSL_NAMESPACE_BEGIN
70
+
71
+ ABSL_CONST_INIT static FailureSignalHandlerOptions fsh_options;
72
+
73
+ // Resets the signal handler for signo to the default action for that
74
+ // signal, then raises the signal.
75
+ static void RaiseToDefaultHandler(int signo) {
76
+ signal(signo, SIG_DFL);
77
+ raise(signo);
78
+ }
79
+
80
+ struct FailureSignalData {
81
+ const int signo;
82
+ const char* const as_string;
83
+ #ifdef ABSL_HAVE_SIGACTION
84
+ struct sigaction previous_action;
85
+ // StructSigaction is used to silence -Wmissing-field-initializers.
86
+ using StructSigaction = struct sigaction;
87
+ #define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction()
88
+ #else
89
+ void (*previous_handler)(int);
90
+ #define FSD_PREVIOUS_INIT SIG_DFL
91
+ #endif
92
+ };
93
+
94
+ ABSL_CONST_INIT static FailureSignalData failure_signal_data[] = {
95
+ {SIGSEGV, "SIGSEGV", FSD_PREVIOUS_INIT},
96
+ {SIGILL, "SIGILL", FSD_PREVIOUS_INIT},
97
+ {SIGFPE, "SIGFPE", FSD_PREVIOUS_INIT},
98
+ {SIGABRT, "SIGABRT", FSD_PREVIOUS_INIT},
99
+ {SIGTERM, "SIGTERM", FSD_PREVIOUS_INIT},
100
+ #ifndef _WIN32
101
+ {SIGBUS, "SIGBUS", FSD_PREVIOUS_INIT},
102
+ {SIGTRAP, "SIGTRAP", FSD_PREVIOUS_INIT},
103
+ #endif
104
+ };
105
+
106
+ #undef FSD_PREVIOUS_INIT
107
+
108
+ static void RaiseToPreviousHandler(int signo) {
109
+ // Search for the previous handler.
110
+ for (const auto& it : failure_signal_data) {
111
+ if (it.signo == signo) {
112
+ #ifdef ABSL_HAVE_SIGACTION
113
+ sigaction(signo, &it.previous_action, nullptr);
114
+ #else
115
+ signal(signo, it.previous_handler);
116
+ #endif
117
+ raise(signo);
118
+ return;
119
+ }
120
+ }
121
+
122
+ // Not found, use the default handler.
123
+ RaiseToDefaultHandler(signo);
124
+ }
125
+
126
+ namespace debugging_internal {
127
+
128
+ const char* FailureSignalToString(int signo) {
129
+ for (const auto& it : failure_signal_data) {
130
+ if (it.signo == signo) {
131
+ return it.as_string;
132
+ }
133
+ }
134
+ return "";
135
+ }
136
+
137
+ } // namespace debugging_internal
138
+
139
+ #ifdef ABSL_HAVE_SIGALTSTACK
140
+
141
+ static bool SetupAlternateStackOnce() {
142
+ #if defined(__wasm__) || defined(__asjms__)
143
+ const size_t page_mask = getpagesize() - 1;
144
+ #else
145
+ const size_t page_mask = static_cast<size_t>(sysconf(_SC_PAGESIZE)) - 1;
146
+ #endif
147
+ size_t stack_size =
148
+ (std::max(static_cast<size_t>(SIGSTKSZ), size_t{65536}) + page_mask) &
149
+ ~page_mask;
150
+ #if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
151
+ defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
152
+ // Account for sanitizer instrumentation requiring additional stack space.
153
+ stack_size *= 5;
154
+ #endif
155
+
156
+ stack_t sigstk;
157
+ memset(&sigstk, 0, sizeof(sigstk));
158
+ sigstk.ss_size = stack_size;
159
+
160
+ #ifdef ABSL_HAVE_MMAP
161
+ #ifndef MAP_STACK
162
+ #define MAP_STACK 0
163
+ #endif
164
+ sigstk.ss_sp = mmap(nullptr, sigstk.ss_size, PROT_READ | PROT_WRITE,
165
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
166
+ if (sigstk.ss_sp == MAP_FAILED) {
167
+ ABSL_RAW_LOG(FATAL, "mmap() for alternate signal stack failed");
168
+ }
169
+ #else
170
+ sigstk.ss_sp = malloc(sigstk.ss_size);
171
+ if (sigstk.ss_sp == nullptr) {
172
+ ABSL_RAW_LOG(FATAL, "malloc() for alternate signal stack failed");
173
+ }
174
+ #endif
175
+
176
+ if (sigaltstack(&sigstk, nullptr) != 0) {
177
+ ABSL_RAW_LOG(FATAL, "sigaltstack() failed with errno=%d", errno);
178
+ }
179
+
180
+ #ifdef __linux__
181
+ #if defined(PR_SET_VMA) && defined(PR_SET_VMA_ANON_NAME)
182
+ // Make a best-effort attempt to name the allocated region in
183
+ // /proc/$PID/smaps.
184
+ //
185
+ // The call to prctl() may fail if the kernel was not configured with the
186
+ // CONFIG_ANON_VMA_NAME kernel option. This is OK since the call is
187
+ // primarily a debugging aid.
188
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, sigstk.ss_sp, sigstk.ss_size,
189
+ "absl-signalstack");
190
+ #endif
191
+ #endif // __linux__
192
+
193
+ return true;
194
+ }
195
+
196
+ #endif
197
+
198
+ #ifdef ABSL_HAVE_SIGACTION
199
+
200
+ // Sets up an alternate stack for signal handlers once.
201
+ // Returns the appropriate flag for sig_action.sa_flags
202
+ // if the system supports using an alternate stack.
203
+ static int MaybeSetupAlternateStack() {
204
+ #ifdef ABSL_HAVE_SIGALTSTACK
205
+ ABSL_ATTRIBUTE_UNUSED static const bool kOnce = SetupAlternateStackOnce();
206
+ return SA_ONSTACK;
207
+ #else
208
+ return 0;
209
+ #endif
210
+ }
211
+
212
+ static void InstallOneFailureHandler(FailureSignalData* data,
213
+ void (*handler)(int, siginfo_t*, void*)) {
214
+ struct sigaction act;
215
+ memset(&act, 0, sizeof(act));
216
+ sigemptyset(&act.sa_mask);
217
+ act.sa_flags |= SA_SIGINFO;
218
+ // SA_NODEFER is required to handle SIGABRT from
219
+ // ImmediateAbortSignalHandler().
220
+ act.sa_flags |= SA_NODEFER;
221
+ if (fsh_options.use_alternate_stack) {
222
+ act.sa_flags |= MaybeSetupAlternateStack();
223
+ }
224
+ act.sa_sigaction = handler;
225
+ ABSL_RAW_CHECK(sigaction(data->signo, &act, &data->previous_action) == 0,
226
+ "sigaction() failed");
227
+ }
228
+
229
+ #else
230
+
231
+ static void InstallOneFailureHandler(FailureSignalData* data,
232
+ void (*handler)(int)) {
233
+ data->previous_handler = signal(data->signo, handler);
234
+ ABSL_RAW_CHECK(data->previous_handler != SIG_ERR, "signal() failed");
235
+ }
236
+
237
+ #endif
238
+
239
+ static void WriteSignalMessage(int signo, int cpu,
240
+ void (*writerfn)(const char*)) {
241
+ char buf[96];
242
+ char on_cpu[32] = {0};
243
+ if (cpu != -1) {
244
+ snprintf(on_cpu, sizeof(on_cpu), " on cpu %d", cpu);
245
+ }
246
+ const char* const signal_string =
247
+ debugging_internal::FailureSignalToString(signo);
248
+ if (signal_string != nullptr && signal_string[0] != '\0') {
249
+ snprintf(buf, sizeof(buf), "*** %s received at time=%ld%s ***\n",
250
+ signal_string,
251
+ static_cast<long>(time(nullptr)), // NOLINT(runtime/int)
252
+ on_cpu);
253
+ } else {
254
+ snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld%s ***\n",
255
+ signo, static_cast<long>(time(nullptr)), // NOLINT(runtime/int)
256
+ on_cpu);
257
+ }
258
+ writerfn(buf);
259
+ }
260
+
261
+ // `void*` might not be big enough to store `void(*)(const char*)`.
262
+ struct WriterFnStruct {
263
+ void (*writerfn)(const char*);
264
+ };
265
+
266
+ // Many of the absl::debugging_internal::Dump* functions in
267
+ // examine_stack.h take a writer function pointer that has a void* arg
268
+ // for historical reasons. failure_signal_handler_writer only takes a
269
+ // data pointer. This function converts between these types.
270
+ static void WriterFnWrapper(const char* data, void* arg) {
271
+ static_cast<WriterFnStruct*>(arg)->writerfn(data);
272
+ }
273
+
274
+ // Convenient wrapper around DumpPCAndFrameSizesAndStackTrace() for signal
275
+ // handlers. "noinline" so that GetStackFrames() skips the top-most stack
276
+ // frame for this function.
277
+ ABSL_ATTRIBUTE_NOINLINE static void WriteStackTrace(
278
+ void* ucontext, bool symbolize_stacktrace,
279
+ void (*writerfn)(const char*, void*), void* writerfn_arg) {
280
+ constexpr int kNumStackFrames = 32;
281
+ void* stack[kNumStackFrames];
282
+ int frame_sizes[kNumStackFrames];
283
+ int min_dropped_frames;
284
+ int depth = absl::GetStackFramesWithContext(
285
+ stack, frame_sizes, kNumStackFrames,
286
+ 1, // Do not include this function in stack trace.
287
+ ucontext, &min_dropped_frames);
288
+ absl::debugging_internal::DumpPCAndFrameSizesAndStackTrace(
289
+ absl::debugging_internal::GetProgramCounter(ucontext), stack, frame_sizes,
290
+ depth, min_dropped_frames, symbolize_stacktrace, writerfn, writerfn_arg);
291
+ }
292
+
293
+ // Called by AbslFailureSignalHandler() to write the failure info. It is
294
+ // called once with writerfn set to WriteToStderr() and then possibly
295
+ // with writerfn set to the user provided function.
296
+ static void WriteFailureInfo(int signo, void* ucontext, int cpu,
297
+ void (*writerfn)(const char*)) {
298
+ WriterFnStruct writerfn_struct{writerfn};
299
+ WriteSignalMessage(signo, cpu, writerfn);
300
+ WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper,
301
+ &writerfn_struct);
302
+ }
303
+
304
+ // absl::SleepFor() can't be used here since AbslInternalSleepFor()
305
+ // may be overridden to do something that isn't async-signal-safe on
306
+ // some platforms.
307
+ static void PortableSleepForSeconds(int seconds) {
308
+ #ifdef _WIN32
309
+ Sleep(static_cast<DWORD>(seconds * 1000));
310
+ #else
311
+ struct timespec sleep_time;
312
+ sleep_time.tv_sec = seconds;
313
+ sleep_time.tv_nsec = 0;
314
+ while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {
315
+ }
316
+ #endif
317
+ }
318
+
319
+ #ifdef ABSL_HAVE_ALARM
320
+ // AbslFailureSignalHandler() installs this as a signal handler for
321
+ // SIGALRM, then sets an alarm to be delivered to the program after a
322
+ // set amount of time. If AbslFailureSignalHandler() hangs for more than
323
+ // the alarm timeout, ImmediateAbortSignalHandler() will abort the
324
+ // program.
325
+ static void ImmediateAbortSignalHandler(int) { RaiseToDefaultHandler(SIGABRT); }
326
+ #endif
327
+
328
+ // absl::base_internal::GetTID() returns pid_t on most platforms, but
329
+ // returns absl::base_internal::pid_t on Windows.
330
+ using GetTidType = decltype(absl::base_internal::GetTID());
331
+ ABSL_CONST_INIT static std::atomic<GetTidType> failed_tid(0);
332
+
333
+ #ifndef ABSL_HAVE_SIGACTION
334
+ static void AbslFailureSignalHandler(int signo) {
335
+ void* ucontext = nullptr;
336
+ #else
337
+ static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) {
338
+ #endif
339
+
340
+ const GetTidType this_tid = absl::base_internal::GetTID();
341
+ GetTidType previous_failed_tid = 0;
342
+ if (!failed_tid.compare_exchange_strong(previous_failed_tid, this_tid,
343
+ std::memory_order_acq_rel,
344
+ std::memory_order_relaxed)) {
345
+ ABSL_RAW_LOG(
346
+ ERROR,
347
+ "Signal %d raised at PC=%p while already in AbslFailureSignalHandler()",
348
+ signo, absl::debugging_internal::GetProgramCounter(ucontext));
349
+ if (this_tid != previous_failed_tid) {
350
+ // Another thread is already in AbslFailureSignalHandler(), so wait
351
+ // a bit for it to finish. If the other thread doesn't kill us,
352
+ // we do so after sleeping.
353
+ PortableSleepForSeconds(3);
354
+ RaiseToDefaultHandler(signo);
355
+ // The recursively raised signal may be blocked until we return.
356
+ return;
357
+ }
358
+ }
359
+
360
+ // Increase the chance that the CPU we report was the same CPU on which the
361
+ // signal was received by doing this as early as possible, i.e. after
362
+ // verifying that this is not a recursive signal handler invocation.
363
+ int my_cpu = -1;
364
+ #ifdef ABSL_HAVE_SCHED_GETCPU
365
+ my_cpu = sched_getcpu();
366
+ #endif
367
+
368
+ #ifdef ABSL_HAVE_ALARM
369
+ // Set an alarm to abort the program in case this code hangs or deadlocks.
370
+ if (fsh_options.alarm_on_failure_secs > 0) {
371
+ alarm(0); // Cancel any existing alarms.
372
+ signal(SIGALRM, ImmediateAbortSignalHandler);
373
+ alarm(static_cast<unsigned int>(fsh_options.alarm_on_failure_secs));
374
+ }
375
+ #endif
376
+
377
+ // First write to stderr.
378
+ WriteFailureInfo(
379
+ signo, ucontext, my_cpu, +[](const char* data) {
380
+ absl::raw_log_internal::AsyncSignalSafeWriteError(data, strlen(data));
381
+ });
382
+
383
+ // Riskier code (because it is less likely to be async-signal-safe)
384
+ // goes after this point.
385
+ if (fsh_options.writerfn != nullptr) {
386
+ WriteFailureInfo(signo, ucontext, my_cpu, fsh_options.writerfn);
387
+ fsh_options.writerfn(nullptr);
388
+ }
389
+
390
+ if (fsh_options.call_previous_handler) {
391
+ RaiseToPreviousHandler(signo);
392
+ } else {
393
+ RaiseToDefaultHandler(signo);
394
+ }
395
+ }
396
+
397
+ void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options) {
398
+ fsh_options = options;
399
+ for (auto& it : failure_signal_data) {
400
+ InstallOneFailureHandler(&it, AbslFailureSignalHandler);
401
+ }
402
+ }
403
+
404
+ ABSL_NAMESPACE_END
405
+ } // namespace absl
weight/_dep/abseil-cpp/absl/debugging/failure_signal_handler.h ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ // -----------------------------------------------------------------------------
16
+ // File: failure_signal_handler.h
17
+ // -----------------------------------------------------------------------------
18
+ //
19
+ // This file configures the Abseil *failure signal handler* to capture and dump
20
+ // useful debugging information (such as a stacktrace) upon program failure.
21
+ //
22
+ // To use the failure signal handler, call `absl::InstallFailureSignalHandler()`
23
+ // very early in your program, usually in the first few lines of main():
24
+ //
25
+ // int main(int argc, char** argv) {
26
+ // // Initialize the symbolizer to get a human-readable stack trace
27
+ // absl::InitializeSymbolizer(argv[0]);
28
+ //
29
+ // absl::FailureSignalHandlerOptions options;
30
+ // absl::InstallFailureSignalHandler(options);
31
+ // DoSomethingInteresting();
32
+ // return 0;
33
+ // }
34
+ //
35
+ // Any program that raises a fatal signal (such as `SIGSEGV`, `SIGILL`,
36
+ // `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP`) will call the
37
+ // installed failure signal handler and provide debugging information to stderr.
38
+ //
39
+ // Note that you should *not* install the Abseil failure signal handler more
40
+ // than once. You may, of course, have another (non-Abseil) failure signal
41
+ // handler installed (which would be triggered if Abseil's failure signal
42
+ // handler sets `call_previous_handler` to `true`).
43
+
44
+ #ifndef ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
45
+ #define ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
46
+
47
+ #include "absl/base/config.h"
48
+
49
+ namespace absl {
50
+ ABSL_NAMESPACE_BEGIN
51
+
52
+ // FailureSignalHandlerOptions
53
+ //
54
+ // Struct for holding `absl::InstallFailureSignalHandler()` configuration
55
+ // options.
56
+ struct FailureSignalHandlerOptions {
57
+ // If true, try to symbolize the stacktrace emitted on failure, provided that
58
+ // you have initialized a symbolizer for that purpose. (See symbolize.h for
59
+ // more information.)
60
+ bool symbolize_stacktrace = true;
61
+
62
+ // If true, try to run signal handlers on an alternate stack (if supported on
63
+ // the given platform). An alternate stack is useful for program crashes due
64
+ // to a stack overflow; by running on a alternate stack, the signal handler
65
+ // may run even when normal stack space has been exhausted. The downside of
66
+ // using an alternate stack is that extra memory for the alternate stack needs
67
+ // to be pre-allocated.
68
+ bool use_alternate_stack = true;
69
+
70
+ // If positive, indicates the number of seconds after which the failure signal
71
+ // handler is invoked to abort the program. Setting such an alarm is useful in
72
+ // cases where the failure signal handler itself may become hung or
73
+ // deadlocked.
74
+ int alarm_on_failure_secs = 3;
75
+
76
+ // If true, call the previously registered signal handler for the signal that
77
+ // was received (if one was registered) after the existing signal handler
78
+ // runs. This mechanism can be used to chain signal handlers together.
79
+ //
80
+ // If false, the signal is raised to the default handler for that signal
81
+ // (which normally terminates the program).
82
+ //
83
+ // IMPORTANT: If true, the chained fatal signal handlers must not try to
84
+ // recover from the fatal signal. Instead, they should terminate the program
85
+ // via some mechanism, like raising the default handler for the signal, or by
86
+ // calling `_exit()`. Note that the failure signal handler may put parts of
87
+ // the Abseil library into a state from which they cannot recover.
88
+ bool call_previous_handler = false;
89
+
90
+ // If non-null, indicates a pointer to a callback function that will be called
91
+ // upon failure, with a string argument containing failure data. This function
92
+ // may be used as a hook to write failure data to a secondary location, such
93
+ // as a log file. This function will also be called with null data, as a hint
94
+ // to flush any buffered data before the program may be terminated. Consider
95
+ // flushing any buffered data in all calls to this function.
96
+ //
97
+ // Since this function runs within a signal handler, it should be
98
+ // async-signal-safe if possible.
99
+ // See http://man7.org/linux/man-pages/man7/signal-safety.7.html
100
+ void (*writerfn)(const char*) = nullptr;
101
+ };
102
+
103
+ // InstallFailureSignalHandler()
104
+ //
105
+ // Installs a signal handler for the common failure signals `SIGSEGV`, `SIGILL`,
106
+ // `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP` (provided they exist
107
+ // on the given platform). The failure signal handler dumps program failure data
108
+ // useful for debugging in an unspecified format to stderr. This data may
109
+ // include the program counter, a stacktrace, and register information on some
110
+ // systems; do not rely on an exact format for the output, as it is subject to
111
+ // change.
112
+ void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options);
113
+
114
+ namespace debugging_internal {
115
+ const char* FailureSignalToString(int signo);
116
+ } // namespace debugging_internal
117
+
118
+ ABSL_NAMESPACE_END
119
+ } // namespace absl
120
+
121
+ #endif // ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
weight/_dep/abseil-cpp/absl/debugging/failure_signal_handler_test.cc ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Copyright 2018 The Abseil Authors.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // https://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ //
16
+
17
+ #include "absl/debugging/failure_signal_handler.h"
18
+
19
+ #include <csignal>
20
+ #include <cstdio>
21
+ #include <cstdlib>
22
+ #include <cstring>
23
+ #include <fstream>
24
+
25
+ #include "gmock/gmock.h"
26
+ #include "gtest/gtest.h"
27
+ #include "absl/base/internal/raw_logging.h"
28
+ #include "absl/debugging/stacktrace.h"
29
+ #include "absl/debugging/symbolize.h"
30
+ #include "absl/log/check.h"
31
+ #include "absl/strings/match.h"
32
+ #include "absl/strings/str_cat.h"
33
+
34
+ namespace {
35
+
36
+ using testing::StartsWith;
37
+
38
+ #if GTEST_HAS_DEATH_TEST
39
+
40
+ // For the parameterized death tests. GetParam() returns the signal number.
41
+ using FailureSignalHandlerDeathTest = ::testing::TestWithParam<int>;
42
+
43
+ // This function runs in a fork()ed process on most systems.
44
+ void InstallHandlerAndRaise(int signo) {
45
+ absl::InstallFailureSignalHandler(absl::FailureSignalHandlerOptions());
46
+ raise(signo);
47
+ }
48
+
49
+ TEST_P(FailureSignalHandlerDeathTest, AbslFailureSignal) {
50
+ const int signo = GetParam();
51
+ std::string exit_regex = absl::StrCat(
52
+ "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
53
+ " received at time=");
54
+ #ifndef _WIN32
55
+ EXPECT_EXIT(InstallHandlerAndRaise(signo), testing::KilledBySignal(signo),
56
+ exit_regex);
57
+ #else
58
+ // Windows doesn't have testing::KilledBySignal().
59
+ EXPECT_DEATH_IF_SUPPORTED(InstallHandlerAndRaise(signo), exit_regex);
60
+ #endif
61
+ }
62
+
63
+ ABSL_CONST_INIT FILE* error_file = nullptr;
64
+
65
+ void WriteToErrorFile(const char* msg) {
66
+ if (msg != nullptr) {
67
+ ABSL_RAW_CHECK(fwrite(msg, strlen(msg), 1, error_file) == 1,
68
+ "fwrite() failed");
69
+ }
70
+ ABSL_RAW_CHECK(fflush(error_file) == 0, "fflush() failed");
71
+ }
72
+
73
+ std::string GetTmpDir() {
74
+ // TEST_TMPDIR is set by Bazel. Try the others when not running under Bazel.
75
+ static const char* const kTmpEnvVars[] = {"TEST_TMPDIR", "TMPDIR", "TEMP",
76
+ "TEMPDIR", "TMP"};
77
+ for (const char* const var : kTmpEnvVars) {
78
+ const char* tmp_dir = std::getenv(var);
79
+ if (tmp_dir != nullptr) {
80
+ return tmp_dir;
81
+ }
82
+ }
83
+
84
+ // Try something reasonable.
85
+ return "/tmp";
86
+ }
87
+
88
+ // This function runs in a fork()ed process on most systems.
89
+ void InstallHandlerWithWriteToFileAndRaise(const char* file, int signo) {
90
+ error_file = fopen(file, "w");
91
+ CHECK_NE(error_file, nullptr) << "Failed create error_file";
92
+ absl::FailureSignalHandlerOptions options;
93
+ options.writerfn = WriteToErrorFile;
94
+ absl::InstallFailureSignalHandler(options);
95
+ raise(signo);
96
+ }
97
+
98
+ TEST_P(FailureSignalHandlerDeathTest, AbslFatalSignalsWithWriterFn) {
99
+ const int signo = GetParam();
100
+ std::string tmp_dir = GetTmpDir();
101
+ std::string file = absl::StrCat(tmp_dir, "/signo_", signo);
102
+
103
+ std::string exit_regex = absl::StrCat(
104
+ "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
105
+ " received at time=");
106
+ #ifndef _WIN32
107
+ EXPECT_EXIT(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
108
+ testing::KilledBySignal(signo), exit_regex);
109
+ #else
110
+ // Windows doesn't have testing::KilledBySignal().
111
+ EXPECT_DEATH_IF_SUPPORTED(
112
+ InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo), exit_regex);
113
+ #endif
114
+
115
+ // Open the file in this process and check its contents.
116
+ std::fstream error_output(file);
117
+ ASSERT_TRUE(error_output.is_open()) << file;
118
+ std::string error_line;
119
+ std::getline(error_output, error_line);
120
+ EXPECT_THAT(
121
+ error_line,
122
+ StartsWith(absl::StrCat(
123
+ "*** ", absl::debugging_internal::FailureSignalToString(signo),
124
+ " received at ")));
125
+
126
+ // On platforms where it is possible to get the current CPU, the
127
+ // CPU number is also logged. Check that it is present in output.
128
+ #if defined(__linux__)
129
+ EXPECT_THAT(error_line, testing::HasSubstr(" on cpu "));
130
+ #endif
131
+
132
+ if (absl::debugging_internal::StackTraceWorksForTest()) {
133
+ std::getline(error_output, error_line);
134
+ EXPECT_THAT(error_line, StartsWith("PC: "));
135
+ }
136
+ }
137
+
138
+ constexpr int kFailureSignals[] = {
139
+ SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM,
140
+ #ifndef _WIN32
141
+ SIGBUS, SIGTRAP,
142
+ #endif
143
+ };
144
+
145
+ std::string SignalParamToString(const ::testing::TestParamInfo<int>& info) {
146
+ std::string result =
147
+ absl::debugging_internal::FailureSignalToString(info.param);
148
+ if (result.empty()) {
149
+ result = absl::StrCat(info.param);
150
+ }
151
+ return result;
152
+ }
153
+
154
+ INSTANTIATE_TEST_SUITE_P(AbslDeathTest, FailureSignalHandlerDeathTest,
155
+ ::testing::ValuesIn(kFailureSignals),
156
+ SignalParamToString);
157
+
158
+ #endif // GTEST_HAS_DEATH_TEST
159
+
160
+ } // namespace
161
+
162
+ int main(int argc, char** argv) {
163
+ absl::InitializeSymbolizer(argv[0]);
164
+ testing::InitGoogleTest(&argc, argv);
165
+ return RUN_ALL_TESTS();
166
+ }
weight/_dep/abseil-cpp/absl/debugging/internal/demangle.cc ADDED
@@ -0,0 +1,2012 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ // For reference check out:
16
+ // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
17
+ //
18
+ // Note that we only have partial C++11 support yet.
19
+
20
+ #include "absl/debugging/internal/demangle.h"
21
+
22
+ #include <cstdint>
23
+ #include <cstdio>
24
+ #include <cstdlib>
25
+ #include <limits>
26
+ #include <string>
27
+
28
+ #include "absl/base/config.h"
29
+
30
+ #if ABSL_INTERNAL_HAS_CXA_DEMANGLE
31
+ #include <cxxabi.h>
32
+ #endif
33
+
34
+ namespace absl {
35
+ ABSL_NAMESPACE_BEGIN
36
+ namespace debugging_internal {
37
+
38
+ typedef struct {
39
+ const char *abbrev;
40
+ const char *real_name;
41
+ // Number of arguments in <expression> context, or 0 if disallowed.
42
+ int arity;
43
+ } AbbrevPair;
44
+
45
+ // List of operators from Itanium C++ ABI.
46
+ static const AbbrevPair kOperatorList[] = {
47
+ // New has special syntax (not currently supported).
48
+ {"nw", "new", 0},
49
+ {"na", "new[]", 0},
50
+
51
+ // Works except that the 'gs' prefix is not supported.
52
+ {"dl", "delete", 1},
53
+ {"da", "delete[]", 1},
54
+
55
+ {"ps", "+", 1}, // "positive"
56
+ {"ng", "-", 1}, // "negative"
57
+ {"ad", "&", 1}, // "address-of"
58
+ {"de", "*", 1}, // "dereference"
59
+ {"co", "~", 1},
60
+
61
+ {"pl", "+", 2},
62
+ {"mi", "-", 2},
63
+ {"ml", "*", 2},
64
+ {"dv", "/", 2},
65
+ {"rm", "%", 2},
66
+ {"an", "&", 2},
67
+ {"or", "|", 2},
68
+ {"eo", "^", 2},
69
+ {"aS", "=", 2},
70
+ {"pL", "+=", 2},
71
+ {"mI", "-=", 2},
72
+ {"mL", "*=", 2},
73
+ {"dV", "/=", 2},
74
+ {"rM", "%=", 2},
75
+ {"aN", "&=", 2},
76
+ {"oR", "|=", 2},
77
+ {"eO", "^=", 2},
78
+ {"ls", "<<", 2},
79
+ {"rs", ">>", 2},
80
+ {"lS", "<<=", 2},
81
+ {"rS", ">>=", 2},
82
+ {"eq", "==", 2},
83
+ {"ne", "!=", 2},
84
+ {"lt", "<", 2},
85
+ {"gt", ">", 2},
86
+ {"le", "<=", 2},
87
+ {"ge", ">=", 2},
88
+ {"nt", "!", 1},
89
+ {"aa", "&&", 2},
90
+ {"oo", "||", 2},
91
+ {"pp", "++", 1},
92
+ {"mm", "--", 1},
93
+ {"cm", ",", 2},
94
+ {"pm", "->*", 2},
95
+ {"pt", "->", 0}, // Special syntax
96
+ {"cl", "()", 0}, // Special syntax
97
+ {"ix", "[]", 2},
98
+ {"qu", "?", 3},
99
+ {"st", "sizeof", 0}, // Special syntax
100
+ {"sz", "sizeof", 1}, // Not a real operator name, but used in expressions.
101
+ {nullptr, nullptr, 0},
102
+ };
103
+
104
+ // List of builtin types from Itanium C++ ABI.
105
+ //
106
+ // Invariant: only one- or two-character type abbreviations here.
107
+ static const AbbrevPair kBuiltinTypeList[] = {
108
+ {"v", "void", 0},
109
+ {"w", "wchar_t", 0},
110
+ {"b", "bool", 0},
111
+ {"c", "char", 0},
112
+ {"a", "signed char", 0},
113
+ {"h", "unsigned char", 0},
114
+ {"s", "short", 0},
115
+ {"t", "unsigned short", 0},
116
+ {"i", "int", 0},
117
+ {"j", "unsigned int", 0},
118
+ {"l", "long", 0},
119
+ {"m", "unsigned long", 0},
120
+ {"x", "long long", 0},
121
+ {"y", "unsigned long long", 0},
122
+ {"n", "__int128", 0},
123
+ {"o", "unsigned __int128", 0},
124
+ {"f", "float", 0},
125
+ {"d", "double", 0},
126
+ {"e", "long double", 0},
127
+ {"g", "__float128", 0},
128
+ {"z", "ellipsis", 0},
129
+
130
+ {"De", "decimal128", 0}, // IEEE 754r decimal floating point (128 bits)
131
+ {"Dd", "decimal64", 0}, // IEEE 754r decimal floating point (64 bits)
132
+ {"Dc", "decltype(auto)", 0},
133
+ {"Da", "auto", 0},
134
+ {"Dn", "std::nullptr_t", 0}, // i.e., decltype(nullptr)
135
+ {"Df", "decimal32", 0}, // IEEE 754r decimal floating point (32 bits)
136
+ {"Di", "char32_t", 0},
137
+ {"Du", "char8_t", 0},
138
+ {"Ds", "char16_t", 0},
139
+ {"Dh", "float16", 0}, // IEEE 754r half-precision float (16 bits)
140
+ {nullptr, nullptr, 0},
141
+ };
142
+
143
+ // List of substitutions Itanium C++ ABI.
144
+ static const AbbrevPair kSubstitutionList[] = {
145
+ {"St", "", 0},
146
+ {"Sa", "allocator", 0},
147
+ {"Sb", "basic_string", 0},
148
+ // std::basic_string<char, std::char_traits<char>,std::allocator<char> >
149
+ {"Ss", "string", 0},
150
+ // std::basic_istream<char, std::char_traits<char> >
151
+ {"Si", "istream", 0},
152
+ // std::basic_ostream<char, std::char_traits<char> >
153
+ {"So", "ostream", 0},
154
+ // std::basic_iostream<char, std::char_traits<char> >
155
+ {"Sd", "iostream", 0},
156
+ {nullptr, nullptr, 0},
157
+ };
158
+
159
+ // State needed for demangling. This struct is copied in almost every stack
160
+ // frame, so every byte counts.
161
+ typedef struct {
162
+ int mangled_idx; // Cursor of mangled name.
163
+ int out_cur_idx; // Cursor of output string.
164
+ int prev_name_idx; // For constructors/destructors.
165
+ unsigned int prev_name_length : 16; // For constructors/destructors.
166
+ signed int nest_level : 15; // For nested names.
167
+ unsigned int append : 1; // Append flag.
168
+ // Note: for some reason MSVC can't pack "bool append : 1" into the same int
169
+ // with the above two fields, so we use an int instead. Amusingly it can pack
170
+ // "signed bool" as expected, but relying on that to continue to be a legal
171
+ // type seems ill-advised (as it's illegal in at least clang).
172
+ } ParseState;
173
+
174
+ static_assert(sizeof(ParseState) == 4 * sizeof(int),
175
+ "unexpected size of ParseState");
176
+
177
+ // One-off state for demangling that's not subject to backtracking -- either
178
+ // constant data, data that's intentionally immune to backtracking (steps), or
179
+ // data that would never be changed by backtracking anyway (recursion_depth).
180
+ //
181
+ // Only one copy of this exists for each call to Demangle, so the size of this
182
+ // struct is nearly inconsequential.
183
+ typedef struct {
184
+ const char *mangled_begin; // Beginning of input string.
185
+ char *out; // Beginning of output string.
186
+ int out_end_idx; // One past last allowed output character.
187
+ int recursion_depth; // For stack exhaustion prevention.
188
+ int steps; // Cap how much work we'll do, regardless of depth.
189
+ ParseState parse_state; // Backtrackable state copied for most frames.
190
+ } State;
191
+
192
+ namespace {
193
+ // Prevent deep recursion / stack exhaustion.
194
+ // Also prevent unbounded handling of complex inputs.
195
+ class ComplexityGuard {
196
+ public:
197
+ explicit ComplexityGuard(State *state) : state_(state) {
198
+ ++state->recursion_depth;
199
+ ++state->steps;
200
+ }
201
+ ~ComplexityGuard() { --state_->recursion_depth; }
202
+
203
+ // 256 levels of recursion seems like a reasonable upper limit on depth.
204
+ // 128 is not enough to demagle synthetic tests from demangle_unittest.txt:
205
+ // "_ZaaZZZZ..." and "_ZaaZcvZcvZ..."
206
+ static constexpr int kRecursionDepthLimit = 256;
207
+
208
+ // We're trying to pick a charitable upper-limit on how many parse steps are
209
+ // necessary to handle something that a human could actually make use of.
210
+ // This is mostly in place as a bound on how much work we'll do if we are
211
+ // asked to demangle an mangled name from an untrusted source, so it should be
212
+ // much larger than the largest expected symbol, but much smaller than the
213
+ // amount of work we can do in, e.g., a second.
214
+ //
215
+ // Some real-world symbols from an arbitrary binary started failing between
216
+ // 2^12 and 2^13, so we multiply the latter by an extra factor of 16 to set
217
+ // the limit.
218
+ //
219
+ // Spending one second on 2^17 parse steps would require each step to take
220
+ // 7.6us, or ~30000 clock cycles, so it's safe to say this can be done in
221
+ // under a second.
222
+ static constexpr int kParseStepsLimit = 1 << 17;
223
+
224
+ bool IsTooComplex() const {
225
+ return state_->recursion_depth > kRecursionDepthLimit ||
226
+ state_->steps > kParseStepsLimit;
227
+ }
228
+
229
+ private:
230
+ State *state_;
231
+ };
232
+ } // namespace
233
+
234
+ // We don't use strlen() in libc since it's not guaranteed to be async
235
+ // signal safe.
236
+ static size_t StrLen(const char *str) {
237
+ size_t len = 0;
238
+ while (*str != '\0') {
239
+ ++str;
240
+ ++len;
241
+ }
242
+ return len;
243
+ }
244
+
245
+ // Returns true if "str" has at least "n" characters remaining.
246
+ static bool AtLeastNumCharsRemaining(const char *str, size_t n) {
247
+ for (size_t i = 0; i < n; ++i) {
248
+ if (str[i] == '\0') {
249
+ return false;
250
+ }
251
+ }
252
+ return true;
253
+ }
254
+
255
+ // Returns true if "str" has "prefix" as a prefix.
256
+ static bool StrPrefix(const char *str, const char *prefix) {
257
+ size_t i = 0;
258
+ while (str[i] != '\0' && prefix[i] != '\0' && str[i] == prefix[i]) {
259
+ ++i;
260
+ }
261
+ return prefix[i] == '\0'; // Consumed everything in "prefix".
262
+ }
263
+
264
+ static void InitState(State* state,
265
+ const char* mangled,
266
+ char* out,
267
+ size_t out_size) {
268
+ state->mangled_begin = mangled;
269
+ state->out = out;
270
+ state->out_end_idx = static_cast<int>(out_size);
271
+ state->recursion_depth = 0;
272
+ state->steps = 0;
273
+
274
+ state->parse_state.mangled_idx = 0;
275
+ state->parse_state.out_cur_idx = 0;
276
+ state->parse_state.prev_name_idx = 0;
277
+ state->parse_state.prev_name_length = 0;
278
+ state->parse_state.nest_level = -1;
279
+ state->parse_state.append = true;
280
+ }
281
+
282
+ static inline const char *RemainingInput(State *state) {
283
+ return &state->mangled_begin[state->parse_state.mangled_idx];
284
+ }
285
+
286
+ // Returns true and advances "mangled_idx" if we find "one_char_token"
287
+ // at "mangled_idx" position. It is assumed that "one_char_token" does
288
+ // not contain '\0'.
289
+ static bool ParseOneCharToken(State *state, const char one_char_token) {
290
+ ComplexityGuard guard(state);
291
+ if (guard.IsTooComplex()) return false;
292
+ if (RemainingInput(state)[0] == one_char_token) {
293
+ ++state->parse_state.mangled_idx;
294
+ return true;
295
+ }
296
+ return false;
297
+ }
298
+
299
+ // Returns true and advances "mangled_cur" if we find "two_char_token"
300
+ // at "mangled_cur" position. It is assumed that "two_char_token" does
301
+ // not contain '\0'.
302
+ static bool ParseTwoCharToken(State *state, const char *two_char_token) {
303
+ ComplexityGuard guard(state);
304
+ if (guard.IsTooComplex()) return false;
305
+ if (RemainingInput(state)[0] == two_char_token[0] &&
306
+ RemainingInput(state)[1] == two_char_token[1]) {
307
+ state->parse_state.mangled_idx += 2;
308
+ return true;
309
+ }
310
+ return false;
311
+ }
312
+
313
+ // Returns true and advances "mangled_cur" if we find any character in
314
+ // "char_class" at "mangled_cur" position.
315
+ static bool ParseCharClass(State *state, const char *char_class) {
316
+ ComplexityGuard guard(state);
317
+ if (guard.IsTooComplex()) return false;
318
+ if (RemainingInput(state)[0] == '\0') {
319
+ return false;
320
+ }
321
+ const char *p = char_class;
322
+ for (; *p != '\0'; ++p) {
323
+ if (RemainingInput(state)[0] == *p) {
324
+ ++state->parse_state.mangled_idx;
325
+ return true;
326
+ }
327
+ }
328
+ return false;
329
+ }
330
+
331
+ static bool ParseDigit(State *state, int *digit) {
332
+ char c = RemainingInput(state)[0];
333
+ if (ParseCharClass(state, "0123456789")) {
334
+ if (digit != nullptr) {
335
+ *digit = c - '0';
336
+ }
337
+ return true;
338
+ }
339
+ return false;
340
+ }
341
+
342
+ // This function is used for handling an optional non-terminal.
343
+ static bool Optional(bool /*status*/) { return true; }
344
+
345
+ // This function is used for handling <non-terminal>+ syntax.
346
+ typedef bool (*ParseFunc)(State *);
347
+ static bool OneOrMore(ParseFunc parse_func, State *state) {
348
+ if (parse_func(state)) {
349
+ while (parse_func(state)) {
350
+ }
351
+ return true;
352
+ }
353
+ return false;
354
+ }
355
+
356
+ // This function is used for handling <non-terminal>* syntax. The function
357
+ // always returns true and must be followed by a termination token or a
358
+ // terminating sequence not handled by parse_func (e.g.
359
+ // ParseOneCharToken(state, 'E')).
360
+ static bool ZeroOrMore(ParseFunc parse_func, State *state) {
361
+ while (parse_func(state)) {
362
+ }
363
+ return true;
364
+ }
365
+
366
+ // Append "str" at "out_cur_idx". If there is an overflow, out_cur_idx is
367
+ // set to out_end_idx+1. The output string is ensured to
368
+ // always terminate with '\0' as long as there is no overflow.
369
+ static void Append(State *state, const char *const str, const size_t length) {
370
+ for (size_t i = 0; i < length; ++i) {
371
+ if (state->parse_state.out_cur_idx + 1 <
372
+ state->out_end_idx) { // +1 for '\0'
373
+ state->out[state->parse_state.out_cur_idx++] = str[i];
374
+ } else {
375
+ // signal overflow
376
+ state->parse_state.out_cur_idx = state->out_end_idx + 1;
377
+ break;
378
+ }
379
+ }
380
+ if (state->parse_state.out_cur_idx < state->out_end_idx) {
381
+ state->out[state->parse_state.out_cur_idx] =
382
+ '\0'; // Terminate it with '\0'
383
+ }
384
+ }
385
+
386
+ // We don't use equivalents in libc to avoid locale issues.
387
+ static bool IsLower(char c) { return c >= 'a' && c <= 'z'; }
388
+
389
+ static bool IsAlpha(char c) {
390
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
391
+ }
392
+
393
+ static bool IsDigit(char c) { return c >= '0' && c <= '9'; }
394
+
395
+ // Returns true if "str" is a function clone suffix. These suffixes are used
396
+ // by GCC 4.5.x and later versions (and our locally-modified version of GCC
397
+ // 4.4.x) to indicate functions which have been cloned during optimization.
398
+ // We treat any sequence (.<alpha>+.<digit>+)+ as a function clone suffix.
399
+ // Additionally, '_' is allowed along with the alphanumeric sequence.
400
+ static bool IsFunctionCloneSuffix(const char *str) {
401
+ size_t i = 0;
402
+ while (str[i] != '\0') {
403
+ bool parsed = false;
404
+ // Consume a single [.<alpha> | _]*[.<digit>]* sequence.
405
+ if (str[i] == '.' && (IsAlpha(str[i + 1]) || str[i + 1] == '_')) {
406
+ parsed = true;
407
+ i += 2;
408
+ while (IsAlpha(str[i]) || str[i] == '_') {
409
+ ++i;
410
+ }
411
+ }
412
+ if (str[i] == '.' && IsDigit(str[i + 1])) {
413
+ parsed = true;
414
+ i += 2;
415
+ while (IsDigit(str[i])) {
416
+ ++i;
417
+ }
418
+ }
419
+ if (!parsed)
420
+ return false;
421
+ }
422
+ return true; // Consumed everything in "str".
423
+ }
424
+
425
+ static bool EndsWith(State *state, const char chr) {
426
+ return state->parse_state.out_cur_idx > 0 &&
427
+ state->parse_state.out_cur_idx < state->out_end_idx &&
428
+ chr == state->out[state->parse_state.out_cur_idx - 1];
429
+ }
430
+
431
+ // Append "str" with some tweaks, iff "append" state is true.
432
+ static void MaybeAppendWithLength(State *state, const char *const str,
433
+ const size_t length) {
434
+ if (state->parse_state.append && length > 0) {
435
+ // Append a space if the output buffer ends with '<' and "str"
436
+ // starts with '<' to avoid <<<.
437
+ if (str[0] == '<' && EndsWith(state, '<')) {
438
+ Append(state, " ", 1);
439
+ }
440
+ // Remember the last identifier name for ctors/dtors,
441
+ // but only if we haven't yet overflown the buffer.
442
+ if (state->parse_state.out_cur_idx < state->out_end_idx &&
443
+ (IsAlpha(str[0]) || str[0] == '_')) {
444
+ state->parse_state.prev_name_idx = state->parse_state.out_cur_idx;
445
+ state->parse_state.prev_name_length = static_cast<unsigned int>(length);
446
+ }
447
+ Append(state, str, length);
448
+ }
449
+ }
450
+
451
+ // Appends a positive decimal number to the output if appending is enabled.
452
+ static bool MaybeAppendDecimal(State *state, int val) {
453
+ // Max {32-64}-bit unsigned int is 20 digits.
454
+ constexpr size_t kMaxLength = 20;
455
+ char buf[kMaxLength];
456
+
457
+ // We can't use itoa or sprintf as neither is specified to be
458
+ // async-signal-safe.
459
+ if (state->parse_state.append) {
460
+ // We can't have a one-before-the-beginning pointer, so instead start with
461
+ // one-past-the-end and manipulate one character before the pointer.
462
+ char *p = &buf[kMaxLength];
463
+ do { // val=0 is the only input that should write a leading zero digit.
464
+ *--p = static_cast<char>((val % 10) + '0');
465
+ val /= 10;
466
+ } while (p > buf && val != 0);
467
+
468
+ // 'p' landed on the last character we set. How convenient.
469
+ Append(state, p, kMaxLength - static_cast<size_t>(p - buf));
470
+ }
471
+
472
+ return true;
473
+ }
474
+
475
+ // A convenient wrapper around MaybeAppendWithLength().
476
+ // Returns true so that it can be placed in "if" conditions.
477
+ static bool MaybeAppend(State *state, const char *const str) {
478
+ if (state->parse_state.append) {
479
+ size_t length = StrLen(str);
480
+ MaybeAppendWithLength(state, str, length);
481
+ }
482
+ return true;
483
+ }
484
+
485
+ // This function is used for handling nested names.
486
+ static bool EnterNestedName(State *state) {
487
+ state->parse_state.nest_level = 0;
488
+ return true;
489
+ }
490
+
491
+ // This function is used for handling nested names.
492
+ static bool LeaveNestedName(State *state, int16_t prev_value) {
493
+ state->parse_state.nest_level = prev_value;
494
+ return true;
495
+ }
496
+
497
+ // Disable the append mode not to print function parameters, etc.
498
+ static bool DisableAppend(State *state) {
499
+ state->parse_state.append = false;
500
+ return true;
501
+ }
502
+
503
+ // Restore the append mode to the previous state.
504
+ static bool RestoreAppend(State *state, bool prev_value) {
505
+ state->parse_state.append = prev_value;
506
+ return true;
507
+ }
508
+
509
+ // Increase the nest level for nested names.
510
+ static void MaybeIncreaseNestLevel(State *state) {
511
+ if (state->parse_state.nest_level > -1) {
512
+ ++state->parse_state.nest_level;
513
+ }
514
+ }
515
+
516
+ // Appends :: for nested names if necessary.
517
+ static void MaybeAppendSeparator(State *state) {
518
+ if (state->parse_state.nest_level >= 1) {
519
+ MaybeAppend(state, "::");
520
+ }
521
+ }
522
+
523
+ // Cancel the last separator if necessary.
524
+ static void MaybeCancelLastSeparator(State *state) {
525
+ if (state->parse_state.nest_level >= 1 && state->parse_state.append &&
526
+ state->parse_state.out_cur_idx >= 2) {
527
+ state->parse_state.out_cur_idx -= 2;
528
+ state->out[state->parse_state.out_cur_idx] = '\0';
529
+ }
530
+ }
531
+
532
+ // Returns true if the identifier of the given length pointed to by
533
+ // "mangled_cur" is anonymous namespace.
534
+ static bool IdentifierIsAnonymousNamespace(State *state, size_t length) {
535
+ // Returns true if "anon_prefix" is a proper prefix of "mangled_cur".
536
+ static const char anon_prefix[] = "_GLOBAL__N_";
537
+ return (length > (sizeof(anon_prefix) - 1) &&
538
+ StrPrefix(RemainingInput(state), anon_prefix));
539
+ }
540
+
541
+ // Forward declarations of our parsing functions.
542
+ static bool ParseMangledName(State *state);
543
+ static bool ParseEncoding(State *state);
544
+ static bool ParseName(State *state);
545
+ static bool ParseUnscopedName(State *state);
546
+ static bool ParseNestedName(State *state);
547
+ static bool ParsePrefix(State *state);
548
+ static bool ParseUnqualifiedName(State *state);
549
+ static bool ParseSourceName(State *state);
550
+ static bool ParseLocalSourceName(State *state);
551
+ static bool ParseUnnamedTypeName(State *state);
552
+ static bool ParseNumber(State *state, int *number_out);
553
+ static bool ParseFloatNumber(State *state);
554
+ static bool ParseSeqId(State *state);
555
+ static bool ParseIdentifier(State *state, size_t length);
556
+ static bool ParseOperatorName(State *state, int *arity);
557
+ static bool ParseSpecialName(State *state);
558
+ static bool ParseCallOffset(State *state);
559
+ static bool ParseNVOffset(State *state);
560
+ static bool ParseVOffset(State *state);
561
+ static bool ParseAbiTags(State *state);
562
+ static bool ParseCtorDtorName(State *state);
563
+ static bool ParseDecltype(State *state);
564
+ static bool ParseType(State *state);
565
+ static bool ParseCVQualifiers(State *state);
566
+ static bool ParseBuiltinType(State *state);
567
+ static bool ParseFunctionType(State *state);
568
+ static bool ParseBareFunctionType(State *state);
569
+ static bool ParseClassEnumType(State *state);
570
+ static bool ParseArrayType(State *state);
571
+ static bool ParsePointerToMemberType(State *state);
572
+ static bool ParseTemplateParam(State *state);
573
+ static bool ParseTemplateTemplateParam(State *state);
574
+ static bool ParseTemplateArgs(State *state);
575
+ static bool ParseTemplateArg(State *state);
576
+ static bool ParseBaseUnresolvedName(State *state);
577
+ static bool ParseUnresolvedName(State *state);
578
+ static bool ParseExpression(State *state);
579
+ static bool ParseExprPrimary(State *state);
580
+ static bool ParseExprCastValue(State *state);
581
+ static bool ParseLocalName(State *state);
582
+ static bool ParseLocalNameSuffix(State *state);
583
+ static bool ParseDiscriminator(State *state);
584
+ static bool ParseSubstitution(State *state, bool accept_std);
585
+
586
+ // Implementation note: the following code is a straightforward
587
+ // translation of the Itanium C++ ABI defined in BNF with a couple of
588
+ // exceptions.
589
+ //
590
+ // - Support GNU extensions not defined in the Itanium C++ ABI
591
+ // - <prefix> and <template-prefix> are combined to avoid infinite loop
592
+ // - Reorder patterns to shorten the code
593
+ // - Reorder patterns to give greedier functions precedence
594
+ // We'll mark "Less greedy than" for these cases in the code
595
+ //
596
+ // Each parsing function changes the parse state and returns true on
597
+ // success, or returns false and doesn't change the parse state (note:
598
+ // the parse-steps counter increases regardless of success or failure).
599
+ // To ensure that the parse state isn't changed in the latter case, we
600
+ // save the original state before we call multiple parsing functions
601
+ // consecutively with &&, and restore it if unsuccessful. See
602
+ // ParseEncoding() as an example of this convention. We follow the
603
+ // convention throughout the code.
604
+ //
605
+ // Originally we tried to do demangling without following the full ABI
606
+ // syntax but it turned out we needed to follow the full syntax to
607
+ // parse complicated cases like nested template arguments. Note that
608
+ // implementing a full-fledged demangler isn't trivial (libiberty's
609
+ // cp-demangle.c has +4300 lines).
610
+ //
611
+ // Note that (foo) in <(foo) ...> is a modifier to be ignored.
612
+ //
613
+ // Reference:
614
+ // - Itanium C++ ABI
615
+ // <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling>
616
+
617
+ // <mangled-name> ::= _Z <encoding>
618
+ static bool ParseMangledName(State *state) {
619
+ ComplexityGuard guard(state);
620
+ if (guard.IsTooComplex()) return false;
621
+ return ParseTwoCharToken(state, "_Z") && ParseEncoding(state);
622
+ }
623
+
624
+ // <encoding> ::= <(function) name> <bare-function-type>
625
+ // ::= <(data) name>
626
+ // ::= <special-name>
627
+ static bool ParseEncoding(State *state) {
628
+ ComplexityGuard guard(state);
629
+ if (guard.IsTooComplex()) return false;
630
+ // Implementing the first two productions together as <name>
631
+ // [<bare-function-type>] avoids exponential blowup of backtracking.
632
+ //
633
+ // Since Optional(...) can't fail, there's no need to copy the state for
634
+ // backtracking.
635
+ if (ParseName(state) && Optional(ParseBareFunctionType(state))) {
636
+ return true;
637
+ }
638
+
639
+ if (ParseSpecialName(state)) {
640
+ return true;
641
+ }
642
+ return false;
643
+ }
644
+
645
+ // <name> ::= <nested-name>
646
+ // ::= <unscoped-template-name> <template-args>
647
+ // ::= <unscoped-name>
648
+ // ::= <local-name>
649
+ static bool ParseName(State *state) {
650
+ ComplexityGuard guard(state);
651
+ if (guard.IsTooComplex()) return false;
652
+ if (ParseNestedName(state) || ParseLocalName(state)) {
653
+ return true;
654
+ }
655
+
656
+ // We reorganize the productions to avoid re-parsing unscoped names.
657
+ // - Inline <unscoped-template-name> productions:
658
+ // <name> ::= <substitution> <template-args>
659
+ // ::= <unscoped-name> <template-args>
660
+ // ::= <unscoped-name>
661
+ // - Merge the two productions that start with unscoped-name:
662
+ // <name> ::= <unscoped-name> [<template-args>]
663
+
664
+ ParseState copy = state->parse_state;
665
+ // "std<...>" isn't a valid name.
666
+ if (ParseSubstitution(state, /*accept_std=*/false) &&
667
+ ParseTemplateArgs(state)) {
668
+ return true;
669
+ }
670
+ state->parse_state = copy;
671
+
672
+ // Note there's no need to restore state after this since only the first
673
+ // subparser can fail.
674
+ return ParseUnscopedName(state) && Optional(ParseTemplateArgs(state));
675
+ }
676
+
677
+ // <unscoped-name> ::= <unqualified-name>
678
+ // ::= St <unqualified-name>
679
+ static bool ParseUnscopedName(State *state) {
680
+ ComplexityGuard guard(state);
681
+ if (guard.IsTooComplex()) return false;
682
+ if (ParseUnqualifiedName(state)) {
683
+ return true;
684
+ }
685
+
686
+ ParseState copy = state->parse_state;
687
+ if (ParseTwoCharToken(state, "St") && MaybeAppend(state, "std::") &&
688
+ ParseUnqualifiedName(state)) {
689
+ return true;
690
+ }
691
+ state->parse_state = copy;
692
+ return false;
693
+ }
694
+
695
+ // <ref-qualifer> ::= R // lvalue method reference qualifier
696
+ // ::= O // rvalue method reference qualifier
697
+ static inline bool ParseRefQualifier(State *state) {
698
+ return ParseCharClass(state, "OR");
699
+ }
700
+
701
+ // <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix>
702
+ // <unqualified-name> E
703
+ // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix>
704
+ // <template-args> E
705
+ static bool ParseNestedName(State *state) {
706
+ ComplexityGuard guard(state);
707
+ if (guard.IsTooComplex()) return false;
708
+ ParseState copy = state->parse_state;
709
+ if (ParseOneCharToken(state, 'N') && EnterNestedName(state) &&
710
+ Optional(ParseCVQualifiers(state)) &&
711
+ Optional(ParseRefQualifier(state)) && ParsePrefix(state) &&
712
+ LeaveNestedName(state, copy.nest_level) &&
713
+ ParseOneCharToken(state, 'E')) {
714
+ return true;
715
+ }
716
+ state->parse_state = copy;
717
+ return false;
718
+ }
719
+
720
+ // This part is tricky. If we literally translate them to code, we'll
721
+ // end up infinite loop. Hence we merge them to avoid the case.
722
+ //
723
+ // <prefix> ::= <prefix> <unqualified-name>
724
+ // ::= <template-prefix> <template-args>
725
+ // ::= <template-param>
726
+ // ::= <substitution>
727
+ // ::= # empty
728
+ // <template-prefix> ::= <prefix> <(template) unqualified-name>
729
+ // ::= <template-param>
730
+ // ::= <substitution>
731
+ static bool ParsePrefix(State *state) {
732
+ ComplexityGuard guard(state);
733
+ if (guard.IsTooComplex()) return false;
734
+ bool has_something = false;
735
+ while (true) {
736
+ MaybeAppendSeparator(state);
737
+ if (ParseTemplateParam(state) ||
738
+ ParseSubstitution(state, /*accept_std=*/true) ||
739
+ ParseUnscopedName(state) ||
740
+ (ParseOneCharToken(state, 'M') && ParseUnnamedTypeName(state))) {
741
+ has_something = true;
742
+ MaybeIncreaseNestLevel(state);
743
+ continue;
744
+ }
745
+ MaybeCancelLastSeparator(state);
746
+ if (has_something && ParseTemplateArgs(state)) {
747
+ return ParsePrefix(state);
748
+ } else {
749
+ break;
750
+ }
751
+ }
752
+ return true;
753
+ }
754
+
755
+ // <unqualified-name> ::= <operator-name> [<abi-tags>]
756
+ // ::= <ctor-dtor-name> [<abi-tags>]
757
+ // ::= <source-name> [<abi-tags>]
758
+ // ::= <local-source-name> [<abi-tags>]
759
+ // ::= <unnamed-type-name> [<abi-tags>]
760
+ //
761
+ // <local-source-name> is a GCC extension; see below.
762
+ static bool ParseUnqualifiedName(State *state) {
763
+ ComplexityGuard guard(state);
764
+ if (guard.IsTooComplex()) return false;
765
+ if (ParseOperatorName(state, nullptr) || ParseCtorDtorName(state) ||
766
+ ParseSourceName(state) || ParseLocalSourceName(state) ||
767
+ ParseUnnamedTypeName(state)) {
768
+ return ParseAbiTags(state);
769
+ }
770
+ return false;
771
+ }
772
+
773
+ // <abi-tags> ::= <abi-tag> [<abi-tags>]
774
+ // <abi-tag> ::= B <source-name>
775
+ static bool ParseAbiTags(State *state) {
776
+ ComplexityGuard guard(state);
777
+ if (guard.IsTooComplex()) return false;
778
+
779
+ while (ParseOneCharToken(state, 'B')) {
780
+ ParseState copy = state->parse_state;
781
+ MaybeAppend(state, "[abi:");
782
+
783
+ if (!ParseSourceName(state)) {
784
+ state->parse_state = copy;
785
+ return false;
786
+ }
787
+ MaybeAppend(state, "]");
788
+ }
789
+
790
+ return true;
791
+ }
792
+
793
+ // <source-name> ::= <positive length number> <identifier>
794
+ static bool ParseSourceName(State *state) {
795
+ ComplexityGuard guard(state);
796
+ if (guard.IsTooComplex()) return false;
797
+ ParseState copy = state->parse_state;
798
+ int length = -1;
799
+ if (ParseNumber(state, &length) &&
800
+ ParseIdentifier(state, static_cast<size_t>(length))) {
801
+ return true;
802
+ }
803
+ state->parse_state = copy;
804
+ return false;
805
+ }
806
+
807
+ // <local-source-name> ::= L <source-name> [<discriminator>]
808
+ //
809
+ // References:
810
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
811
+ // https://gcc.gnu.org/viewcvs?view=rev&revision=124467
812
+ static bool ParseLocalSourceName(State *state) {
813
+ ComplexityGuard guard(state);
814
+ if (guard.IsTooComplex()) return false;
815
+ ParseState copy = state->parse_state;
816
+ if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&
817
+ Optional(ParseDiscriminator(state))) {
818
+ return true;
819
+ }
820
+ state->parse_state = copy;
821
+ return false;
822
+ }
823
+
824
+ // <unnamed-type-name> ::= Ut [<(nonnegative) number>] _
825
+ // ::= <closure-type-name>
826
+ // <closure-type-name> ::= Ul <lambda-sig> E [<(nonnegative) number>] _
827
+ // <lambda-sig> ::= <(parameter) type>+
828
+ static bool ParseUnnamedTypeName(State *state) {
829
+ ComplexityGuard guard(state);
830
+ if (guard.IsTooComplex()) return false;
831
+ ParseState copy = state->parse_state;
832
+ // Type's 1-based index n is encoded as { "", n == 1; itoa(n-2), otherwise }.
833
+ // Optionally parse the encoded value into 'which' and add 2 to get the index.
834
+ int which = -1;
835
+
836
+ // Unnamed type local to function or class.
837
+ if (ParseTwoCharToken(state, "Ut") && Optional(ParseNumber(state, &which)) &&
838
+ which <= std::numeric_limits<int>::max() - 2 && // Don't overflow.
839
+ ParseOneCharToken(state, '_')) {
840
+ MaybeAppend(state, "{unnamed type#");
841
+ MaybeAppendDecimal(state, 2 + which);
842
+ MaybeAppend(state, "}");
843
+ return true;
844
+ }
845
+ state->parse_state = copy;
846
+
847
+ // Closure type.
848
+ which = -1;
849
+ if (ParseTwoCharToken(state, "Ul") && DisableAppend(state) &&
850
+ OneOrMore(ParseType, state) && RestoreAppend(state, copy.append) &&
851
+ ParseOneCharToken(state, 'E') && Optional(ParseNumber(state, &which)) &&
852
+ which <= std::numeric_limits<int>::max() - 2 && // Don't overflow.
853
+ ParseOneCharToken(state, '_')) {
854
+ MaybeAppend(state, "{lambda()#");
855
+ MaybeAppendDecimal(state, 2 + which);
856
+ MaybeAppend(state, "}");
857
+ return true;
858
+ }
859
+ state->parse_state = copy;
860
+
861
+ return false;
862
+ }
863
+
864
+ // <number> ::= [n] <non-negative decimal integer>
865
+ // If "number_out" is non-null, then *number_out is set to the value of the
866
+ // parsed number on success.
867
+ static bool ParseNumber(State *state, int *number_out) {
868
+ ComplexityGuard guard(state);
869
+ if (guard.IsTooComplex()) return false;
870
+ bool negative = false;
871
+ if (ParseOneCharToken(state, 'n')) {
872
+ negative = true;
873
+ }
874
+ const char *p = RemainingInput(state);
875
+ uint64_t number = 0;
876
+ for (; *p != '\0'; ++p) {
877
+ if (IsDigit(*p)) {
878
+ number = number * 10 + static_cast<uint64_t>(*p - '0');
879
+ } else {
880
+ break;
881
+ }
882
+ }
883
+ // Apply the sign with uint64_t arithmetic so overflows aren't UB. Gives
884
+ // "incorrect" results for out-of-range inputs, but negative values only
885
+ // appear for literals, which aren't printed.
886
+ if (negative) {
887
+ number = ~number + 1;
888
+ }
889
+ if (p != RemainingInput(state)) { // Conversion succeeded.
890
+ state->parse_state.mangled_idx += p - RemainingInput(state);
891
+ if (number_out != nullptr) {
892
+ // Note: possibly truncate "number".
893
+ *number_out = static_cast<int>(number);
894
+ }
895
+ return true;
896
+ }
897
+ return false;
898
+ }
899
+
900
+ // Floating-point literals are encoded using a fixed-length lowercase
901
+ // hexadecimal string.
902
+ static bool ParseFloatNumber(State *state) {
903
+ ComplexityGuard guard(state);
904
+ if (guard.IsTooComplex()) return false;
905
+ const char *p = RemainingInput(state);
906
+ for (; *p != '\0'; ++p) {
907
+ if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {
908
+ break;
909
+ }
910
+ }
911
+ if (p != RemainingInput(state)) { // Conversion succeeded.
912
+ state->parse_state.mangled_idx += p - RemainingInput(state);
913
+ return true;
914
+ }
915
+ return false;
916
+ }
917
+
918
+ // The <seq-id> is a sequence number in base 36,
919
+ // using digits and upper case letters
920
+ static bool ParseSeqId(State *state) {
921
+ ComplexityGuard guard(state);
922
+ if (guard.IsTooComplex()) return false;
923
+ const char *p = RemainingInput(state);
924
+ for (; *p != '\0'; ++p) {
925
+ if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {
926
+ break;
927
+ }
928
+ }
929
+ if (p != RemainingInput(state)) { // Conversion succeeded.
930
+ state->parse_state.mangled_idx += p - RemainingInput(state);
931
+ return true;
932
+ }
933
+ return false;
934
+ }
935
+
936
+ // <identifier> ::= <unqualified source code identifier> (of given length)
937
+ static bool ParseIdentifier(State *state, size_t length) {
938
+ ComplexityGuard guard(state);
939
+ if (guard.IsTooComplex()) return false;
940
+ if (!AtLeastNumCharsRemaining(RemainingInput(state), length)) {
941
+ return false;
942
+ }
943
+ if (IdentifierIsAnonymousNamespace(state, length)) {
944
+ MaybeAppend(state, "(anonymous namespace)");
945
+ } else {
946
+ MaybeAppendWithLength(state, RemainingInput(state), length);
947
+ }
948
+ state->parse_state.mangled_idx += length;
949
+ return true;
950
+ }
951
+
952
+ // <operator-name> ::= nw, and other two letters cases
953
+ // ::= cv <type> # (cast)
954
+ // ::= v <digit> <source-name> # vendor extended operator
955
+ static bool ParseOperatorName(State *state, int *arity) {
956
+ ComplexityGuard guard(state);
957
+ if (guard.IsTooComplex()) return false;
958
+ if (!AtLeastNumCharsRemaining(RemainingInput(state), 2)) {
959
+ return false;
960
+ }
961
+ // First check with "cv" (cast) case.
962
+ ParseState copy = state->parse_state;
963
+ if (ParseTwoCharToken(state, "cv") && MaybeAppend(state, "operator ") &&
964
+ EnterNestedName(state) && ParseType(state) &&
965
+ LeaveNestedName(state, copy.nest_level)) {
966
+ if (arity != nullptr) {
967
+ *arity = 1;
968
+ }
969
+ return true;
970
+ }
971
+ state->parse_state = copy;
972
+
973
+ // Then vendor extended operators.
974
+ if (ParseOneCharToken(state, 'v') && ParseDigit(state, arity) &&
975
+ ParseSourceName(state)) {
976
+ return true;
977
+ }
978
+ state->parse_state = copy;
979
+
980
+ // Other operator names should start with a lower alphabet followed
981
+ // by a lower/upper alphabet.
982
+ if (!(IsLower(RemainingInput(state)[0]) &&
983
+ IsAlpha(RemainingInput(state)[1]))) {
984
+ return false;
985
+ }
986
+ // We may want to perform a binary search if we really need speed.
987
+ const AbbrevPair *p;
988
+ for (p = kOperatorList; p->abbrev != nullptr; ++p) {
989
+ if (RemainingInput(state)[0] == p->abbrev[0] &&
990
+ RemainingInput(state)[1] == p->abbrev[1]) {
991
+ if (arity != nullptr) {
992
+ *arity = p->arity;
993
+ }
994
+ MaybeAppend(state, "operator");
995
+ if (IsLower(*p->real_name)) { // new, delete, etc.
996
+ MaybeAppend(state, " ");
997
+ }
998
+ MaybeAppend(state, p->real_name);
999
+ state->parse_state.mangled_idx += 2;
1000
+ return true;
1001
+ }
1002
+ }
1003
+ return false;
1004
+ }
1005
+
1006
+ // <special-name> ::= TV <type>
1007
+ // ::= TT <type>
1008
+ // ::= TI <type>
1009
+ // ::= TS <type>
1010
+ // ::= TH <type> # thread-local
1011
+ // ::= Tc <call-offset> <call-offset> <(base) encoding>
1012
+ // ::= GV <(object) name>
1013
+ // ::= T <call-offset> <(base) encoding>
1014
+ // G++ extensions:
1015
+ // ::= TC <type> <(offset) number> _ <(base) type>
1016
+ // ::= TF <type>
1017
+ // ::= TJ <type>
1018
+ // ::= GR <name>
1019
+ // ::= GA <encoding>
1020
+ // ::= Th <call-offset> <(base) encoding>
1021
+ // ::= Tv <call-offset> <(base) encoding>
1022
+ //
1023
+ // Note: we don't care much about them since they don't appear in
1024
+ // stack traces. The are special data.
1025
+ static bool ParseSpecialName(State *state) {
1026
+ ComplexityGuard guard(state);
1027
+ if (guard.IsTooComplex()) return false;
1028
+ ParseState copy = state->parse_state;
1029
+ if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTISH") &&
1030
+ ParseType(state)) {
1031
+ return true;
1032
+ }
1033
+ state->parse_state = copy;
1034
+
1035
+ if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) &&
1036
+ ParseCallOffset(state) && ParseEncoding(state)) {
1037
+ return true;
1038
+ }
1039
+ state->parse_state = copy;
1040
+
1041
+ if (ParseTwoCharToken(state, "GV") && ParseName(state)) {
1042
+ return true;
1043
+ }
1044
+ state->parse_state = copy;
1045
+
1046
+ if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) &&
1047
+ ParseEncoding(state)) {
1048
+ return true;
1049
+ }
1050
+ state->parse_state = copy;
1051
+
1052
+ // G++ extensions
1053
+ if (ParseTwoCharToken(state, "TC") && ParseType(state) &&
1054
+ ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') &&
1055
+ DisableAppend(state) && ParseType(state)) {
1056
+ RestoreAppend(state, copy.append);
1057
+ return true;
1058
+ }
1059
+ state->parse_state = copy;
1060
+
1061
+ if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") &&
1062
+ ParseType(state)) {
1063
+ return true;
1064
+ }
1065
+ state->parse_state = copy;
1066
+
1067
+ if (ParseTwoCharToken(state, "GR") && ParseName(state)) {
1068
+ return true;
1069
+ }
1070
+ state->parse_state = copy;
1071
+
1072
+ if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) {
1073
+ return true;
1074
+ }
1075
+ state->parse_state = copy;
1076
+
1077
+ if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") &&
1078
+ ParseCallOffset(state) && ParseEncoding(state)) {
1079
+ return true;
1080
+ }
1081
+ state->parse_state = copy;
1082
+ return false;
1083
+ }
1084
+
1085
+ // <call-offset> ::= h <nv-offset> _
1086
+ // ::= v <v-offset> _
1087
+ static bool ParseCallOffset(State *state) {
1088
+ ComplexityGuard guard(state);
1089
+ if (guard.IsTooComplex()) return false;
1090
+ ParseState copy = state->parse_state;
1091
+ if (ParseOneCharToken(state, 'h') && ParseNVOffset(state) &&
1092
+ ParseOneCharToken(state, '_')) {
1093
+ return true;
1094
+ }
1095
+ state->parse_state = copy;
1096
+
1097
+ if (ParseOneCharToken(state, 'v') && ParseVOffset(state) &&
1098
+ ParseOneCharToken(state, '_')) {
1099
+ return true;
1100
+ }
1101
+ state->parse_state = copy;
1102
+
1103
+ return false;
1104
+ }
1105
+
1106
+ // <nv-offset> ::= <(offset) number>
1107
+ static bool ParseNVOffset(State *state) {
1108
+ ComplexityGuard guard(state);
1109
+ if (guard.IsTooComplex()) return false;
1110
+ return ParseNumber(state, nullptr);
1111
+ }
1112
+
1113
+ // <v-offset> ::= <(offset) number> _ <(virtual offset) number>
1114
+ static bool ParseVOffset(State *state) {
1115
+ ComplexityGuard guard(state);
1116
+ if (guard.IsTooComplex()) return false;
1117
+ ParseState copy = state->parse_state;
1118
+ if (ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') &&
1119
+ ParseNumber(state, nullptr)) {
1120
+ return true;
1121
+ }
1122
+ state->parse_state = copy;
1123
+ return false;
1124
+ }
1125
+
1126
+ // <ctor-dtor-name> ::= C1 | C2 | C3 | CI1 <base-class-type> | CI2
1127
+ // <base-class-type>
1128
+ // ::= D0 | D1 | D2
1129
+ // # GCC extensions: "unified" constructor/destructor. See
1130
+ // #
1131
+ // https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847
1132
+ // ::= C4 | D4
1133
+ static bool ParseCtorDtorName(State *state) {
1134
+ ComplexityGuard guard(state);
1135
+ if (guard.IsTooComplex()) return false;
1136
+ ParseState copy = state->parse_state;
1137
+ if (ParseOneCharToken(state, 'C')) {
1138
+ if (ParseCharClass(state, "1234")) {
1139
+ const char *const prev_name =
1140
+ state->out + state->parse_state.prev_name_idx;
1141
+ MaybeAppendWithLength(state, prev_name,
1142
+ state->parse_state.prev_name_length);
1143
+ return true;
1144
+ } else if (ParseOneCharToken(state, 'I') && ParseCharClass(state, "12") &&
1145
+ ParseClassEnumType(state)) {
1146
+ return true;
1147
+ }
1148
+ }
1149
+ state->parse_state = copy;
1150
+
1151
+ if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "0124")) {
1152
+ const char *const prev_name = state->out + state->parse_state.prev_name_idx;
1153
+ MaybeAppend(state, "~");
1154
+ MaybeAppendWithLength(state, prev_name,
1155
+ state->parse_state.prev_name_length);
1156
+ return true;
1157
+ }
1158
+ state->parse_state = copy;
1159
+ return false;
1160
+ }
1161
+
1162
+ // <decltype> ::= Dt <expression> E # decltype of an id-expression or class
1163
+ // # member access (C++0x)
1164
+ // ::= DT <expression> E # decltype of an expression (C++0x)
1165
+ static bool ParseDecltype(State *state) {
1166
+ ComplexityGuard guard(state);
1167
+ if (guard.IsTooComplex()) return false;
1168
+
1169
+ ParseState copy = state->parse_state;
1170
+ if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") &&
1171
+ ParseExpression(state) && ParseOneCharToken(state, 'E')) {
1172
+ return true;
1173
+ }
1174
+ state->parse_state = copy;
1175
+
1176
+ return false;
1177
+ }
1178
+
1179
+ // <type> ::= <CV-qualifiers> <type>
1180
+ // ::= P <type> # pointer-to
1181
+ // ::= R <type> # reference-to
1182
+ // ::= O <type> # rvalue reference-to (C++0x)
1183
+ // ::= C <type> # complex pair (C 2000)
1184
+ // ::= G <type> # imaginary (C 2000)
1185
+ // ::= U <source-name> <type> # vendor extended type qualifier
1186
+ // ::= <builtin-type>
1187
+ // ::= <function-type>
1188
+ // ::= <class-enum-type> # note: just an alias for <name>
1189
+ // ::= <array-type>
1190
+ // ::= <pointer-to-member-type>
1191
+ // ::= <template-template-param> <template-args>
1192
+ // ::= <template-param>
1193
+ // ::= <decltype>
1194
+ // ::= <substitution>
1195
+ // ::= Dp <type> # pack expansion of (C++0x)
1196
+ // ::= Dv <num-elems> _ # GNU vector extension
1197
+ //
1198
+ static bool ParseType(State *state) {
1199
+ ComplexityGuard guard(state);
1200
+ if (guard.IsTooComplex()) return false;
1201
+ ParseState copy = state->parse_state;
1202
+
1203
+ // We should check CV-qualifers, and PRGC things first.
1204
+ //
1205
+ // CV-qualifiers overlap with some operator names, but an operator name is not
1206
+ // valid as a type. To avoid an ambiguity that can lead to exponential time
1207
+ // complexity, refuse to backtrack the CV-qualifiers.
1208
+ //
1209
+ // _Z4aoeuIrMvvE
1210
+ // => _Z 4aoeuI rM v v E
1211
+ // aoeu<operator%=, void, void>
1212
+ // => _Z 4aoeuI r Mv v E
1213
+ // aoeu<void void::* restrict>
1214
+ //
1215
+ // By consuming the CV-qualifiers first, the former parse is disabled.
1216
+ if (ParseCVQualifiers(state)) {
1217
+ const bool result = ParseType(state);
1218
+ if (!result) state->parse_state = copy;
1219
+ return result;
1220
+ }
1221
+ state->parse_state = copy;
1222
+
1223
+ // Similarly, these tag characters can overlap with other <name>s resulting in
1224
+ // two different parse prefixes that land on <template-args> in the same
1225
+ // place, such as "C3r1xI...". So, disable the "ctor-name = C3" parse by
1226
+ // refusing to backtrack the tag characters.
1227
+ if (ParseCharClass(state, "OPRCG")) {
1228
+ const bool result = ParseType(state);
1229
+ if (!result) state->parse_state = copy;
1230
+ return result;
1231
+ }
1232
+ state->parse_state = copy;
1233
+
1234
+ if (ParseTwoCharToken(state, "Dp") && ParseType(state)) {
1235
+ return true;
1236
+ }
1237
+ state->parse_state = copy;
1238
+
1239
+ if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
1240
+ ParseType(state)) {
1241
+ return true;
1242
+ }
1243
+ state->parse_state = copy;
1244
+
1245
+ if (ParseBuiltinType(state) || ParseFunctionType(state) ||
1246
+ ParseClassEnumType(state) || ParseArrayType(state) ||
1247
+ ParsePointerToMemberType(state) || ParseDecltype(state) ||
1248
+ // "std" on its own isn't a type.
1249
+ ParseSubstitution(state, /*accept_std=*/false)) {
1250
+ return true;
1251
+ }
1252
+
1253
+ if (ParseTemplateTemplateParam(state) && ParseTemplateArgs(state)) {
1254
+ return true;
1255
+ }
1256
+ state->parse_state = copy;
1257
+
1258
+ // Less greedy than <template-template-param> <template-args>.
1259
+ if (ParseTemplateParam(state)) {
1260
+ return true;
1261
+ }
1262
+
1263
+ if (ParseTwoCharToken(state, "Dv") && ParseNumber(state, nullptr) &&
1264
+ ParseOneCharToken(state, '_')) {
1265
+ return true;
1266
+ }
1267
+ state->parse_state = copy;
1268
+
1269
+ return false;
1270
+ }
1271
+
1272
+ // <CV-qualifiers> ::= [r] [V] [K]
1273
+ // We don't allow empty <CV-qualifiers> to avoid infinite loop in
1274
+ // ParseType().
1275
+ static bool ParseCVQualifiers(State *state) {
1276
+ ComplexityGuard guard(state);
1277
+ if (guard.IsTooComplex()) return false;
1278
+ int num_cv_qualifiers = 0;
1279
+ num_cv_qualifiers += ParseOneCharToken(state, 'r');
1280
+ num_cv_qualifiers += ParseOneCharToken(state, 'V');
1281
+ num_cv_qualifiers += ParseOneCharToken(state, 'K');
1282
+ return num_cv_qualifiers > 0;
1283
+ }
1284
+
1285
+ // <builtin-type> ::= v, etc. # single-character builtin types
1286
+ // ::= u <source-name>
1287
+ // ::= Dd, etc. # two-character builtin types
1288
+ //
1289
+ // Not supported:
1290
+ // ::= DF <number> _ # _FloatN (N bits)
1291
+ //
1292
+ static bool ParseBuiltinType(State *state) {
1293
+ ComplexityGuard guard(state);
1294
+ if (guard.IsTooComplex()) return false;
1295
+ const AbbrevPair *p;
1296
+ for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) {
1297
+ // Guaranteed only 1- or 2-character strings in kBuiltinTypeList.
1298
+ if (p->abbrev[1] == '\0') {
1299
+ if (ParseOneCharToken(state, p->abbrev[0])) {
1300
+ MaybeAppend(state, p->real_name);
1301
+ return true;
1302
+ }
1303
+ } else if (p->abbrev[2] == '\0' && ParseTwoCharToken(state, p->abbrev)) {
1304
+ MaybeAppend(state, p->real_name);
1305
+ return true;
1306
+ }
1307
+ }
1308
+
1309
+ ParseState copy = state->parse_state;
1310
+ if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) {
1311
+ return true;
1312
+ }
1313
+ state->parse_state = copy;
1314
+ return false;
1315
+ }
1316
+
1317
+ // <exception-spec> ::= Do # non-throwing
1318
+ // exception-specification (e.g.,
1319
+ // noexcept, throw())
1320
+ // ::= DO <expression> E # computed (instantiation-dependent)
1321
+ // noexcept
1322
+ // ::= Dw <type>+ E # dynamic exception specification
1323
+ // with instantiation-dependent types
1324
+ static bool ParseExceptionSpec(State *state) {
1325
+ ComplexityGuard guard(state);
1326
+ if (guard.IsTooComplex()) return false;
1327
+
1328
+ if (ParseTwoCharToken(state, "Do")) return true;
1329
+
1330
+ ParseState copy = state->parse_state;
1331
+ if (ParseTwoCharToken(state, "DO") && ParseExpression(state) &&
1332
+ ParseOneCharToken(state, 'E')) {
1333
+ return true;
1334
+ }
1335
+ state->parse_state = copy;
1336
+ if (ParseTwoCharToken(state, "Dw") && OneOrMore(ParseType, state) &&
1337
+ ParseOneCharToken(state, 'E')) {
1338
+ return true;
1339
+ }
1340
+ state->parse_state = copy;
1341
+
1342
+ return false;
1343
+ }
1344
+
1345
+ // <function-type> ::= [exception-spec] F [Y] <bare-function-type> [O] E
1346
+ static bool ParseFunctionType(State *state) {
1347
+ ComplexityGuard guard(state);
1348
+ if (guard.IsTooComplex()) return false;
1349
+ ParseState copy = state->parse_state;
1350
+ if (Optional(ParseExceptionSpec(state)) && ParseOneCharToken(state, 'F') &&
1351
+ Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) &&
1352
+ Optional(ParseOneCharToken(state, 'O')) &&
1353
+ ParseOneCharToken(state, 'E')) {
1354
+ return true;
1355
+ }
1356
+ state->parse_state = copy;
1357
+ return false;
1358
+ }
1359
+
1360
+ // <bare-function-type> ::= <(signature) type>+
1361
+ static bool ParseBareFunctionType(State *state) {
1362
+ ComplexityGuard guard(state);
1363
+ if (guard.IsTooComplex()) return false;
1364
+ ParseState copy = state->parse_state;
1365
+ DisableAppend(state);
1366
+ if (OneOrMore(ParseType, state)) {
1367
+ RestoreAppend(state, copy.append);
1368
+ MaybeAppend(state, "()");
1369
+ return true;
1370
+ }
1371
+ state->parse_state = copy;
1372
+ return false;
1373
+ }
1374
+
1375
+ // <class-enum-type> ::= <name>
1376
+ static bool ParseClassEnumType(State *state) {
1377
+ ComplexityGuard guard(state);
1378
+ if (guard.IsTooComplex()) return false;
1379
+ return ParseName(state);
1380
+ }
1381
+
1382
+ // <array-type> ::= A <(positive dimension) number> _ <(element) type>
1383
+ // ::= A [<(dimension) expression>] _ <(element) type>
1384
+ static bool ParseArrayType(State *state) {
1385
+ ComplexityGuard guard(state);
1386
+ if (guard.IsTooComplex()) return false;
1387
+ ParseState copy = state->parse_state;
1388
+ if (ParseOneCharToken(state, 'A') && ParseNumber(state, nullptr) &&
1389
+ ParseOneCharToken(state, '_') && ParseType(state)) {
1390
+ return true;
1391
+ }
1392
+ state->parse_state = copy;
1393
+
1394
+ if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) &&
1395
+ ParseOneCharToken(state, '_') && ParseType(state)) {
1396
+ return true;
1397
+ }
1398
+ state->parse_state = copy;
1399
+ return false;
1400
+ }
1401
+
1402
+ // <pointer-to-member-type> ::= M <(class) type> <(member) type>
1403
+ static bool ParsePointerToMemberType(State *state) {
1404
+ ComplexityGuard guard(state);
1405
+ if (guard.IsTooComplex()) return false;
1406
+ ParseState copy = state->parse_state;
1407
+ if (ParseOneCharToken(state, 'M') && ParseType(state) && ParseType(state)) {
1408
+ return true;
1409
+ }
1410
+ state->parse_state = copy;
1411
+ return false;
1412
+ }
1413
+
1414
+ // <template-param> ::= T_
1415
+ // ::= T <parameter-2 non-negative number> _
1416
+ static bool ParseTemplateParam(State *state) {
1417
+ ComplexityGuard guard(state);
1418
+ if (guard.IsTooComplex()) return false;
1419
+ if (ParseTwoCharToken(state, "T_")) {
1420
+ MaybeAppend(state, "?"); // We don't support template substitutions.
1421
+ return true;
1422
+ }
1423
+
1424
+ ParseState copy = state->parse_state;
1425
+ if (ParseOneCharToken(state, 'T') && ParseNumber(state, nullptr) &&
1426
+ ParseOneCharToken(state, '_')) {
1427
+ MaybeAppend(state, "?"); // We don't support template substitutions.
1428
+ return true;
1429
+ }
1430
+ state->parse_state = copy;
1431
+ return false;
1432
+ }
1433
+
1434
+ // <template-template-param> ::= <template-param>
1435
+ // ::= <substitution>
1436
+ static bool ParseTemplateTemplateParam(State *state) {
1437
+ ComplexityGuard guard(state);
1438
+ if (guard.IsTooComplex()) return false;
1439
+ return (ParseTemplateParam(state) ||
1440
+ // "std" on its own isn't a template.
1441
+ ParseSubstitution(state, /*accept_std=*/false));
1442
+ }
1443
+
1444
+ // <template-args> ::= I <template-arg>+ E
1445
+ static bool ParseTemplateArgs(State *state) {
1446
+ ComplexityGuard guard(state);
1447
+ if (guard.IsTooComplex()) return false;
1448
+ ParseState copy = state->parse_state;
1449
+ DisableAppend(state);
1450
+ if (ParseOneCharToken(state, 'I') && OneOrMore(ParseTemplateArg, state) &&
1451
+ ParseOneCharToken(state, 'E')) {
1452
+ RestoreAppend(state, copy.append);
1453
+ MaybeAppend(state, "<>");
1454
+ return true;
1455
+ }
1456
+ state->parse_state = copy;
1457
+ return false;
1458
+ }
1459
+
1460
+ // <template-arg> ::= <type>
1461
+ // ::= <expr-primary>
1462
+ // ::= J <template-arg>* E # argument pack
1463
+ // ::= X <expression> E
1464
+ static bool ParseTemplateArg(State *state) {
1465
+ ComplexityGuard guard(state);
1466
+ if (guard.IsTooComplex()) return false;
1467
+ ParseState copy = state->parse_state;
1468
+ if (ParseOneCharToken(state, 'J') && ZeroOrMore(ParseTemplateArg, state) &&
1469
+ ParseOneCharToken(state, 'E')) {
1470
+ return true;
1471
+ }
1472
+ state->parse_state = copy;
1473
+
1474
+ // There can be significant overlap between the following leading to
1475
+ // exponential backtracking:
1476
+ //
1477
+ // <expr-primary> ::= L <type> <expr-cast-value> E
1478
+ // e.g. L 2xxIvE 1 E
1479
+ // <type> ==> <local-source-name> <template-args>
1480
+ // e.g. L 2xx IvE
1481
+ //
1482
+ // This means parsing an entire <type> twice, and <type> can contain
1483
+ // <template-arg>, so this can generate exponential backtracking. There is
1484
+ // only overlap when the remaining input starts with "L <source-name>", so
1485
+ // parse all cases that can start this way jointly to share the common prefix.
1486
+ //
1487
+ // We have:
1488
+ //
1489
+ // <template-arg> ::= <type>
1490
+ // ::= <expr-primary>
1491
+ //
1492
+ // First, drop all the productions of <type> that must start with something
1493
+ // other than 'L'. All that's left is <class-enum-type>; inline it.
1494
+ //
1495
+ // <type> ::= <nested-name> # starts with 'N'
1496
+ // ::= <unscoped-name>
1497
+ // ::= <unscoped-template-name> <template-args>
1498
+ // ::= <local-name> # starts with 'Z'
1499
+ //
1500
+ // Drop and inline again:
1501
+ //
1502
+ // <type> ::= <unscoped-name>
1503
+ // ::= <unscoped-name> <template-args>
1504
+ // ::= <substitution> <template-args> # starts with 'S'
1505
+ //
1506
+ // Merge the first two, inline <unscoped-name>, drop last:
1507
+ //
1508
+ // <type> ::= <unqualified-name> [<template-args>]
1509
+ // ::= St <unqualified-name> [<template-args>] # starts with 'S'
1510
+ //
1511
+ // Drop and inline:
1512
+ //
1513
+ // <type> ::= <operator-name> [<template-args>] # starts with lowercase
1514
+ // ::= <ctor-dtor-name> [<template-args>] # starts with 'C' or 'D'
1515
+ // ::= <source-name> [<template-args>] # starts with digit
1516
+ // ::= <local-source-name> [<template-args>]
1517
+ // ::= <unnamed-type-name> [<template-args>] # starts with 'U'
1518
+ //
1519
+ // One more time:
1520
+ //
1521
+ // <type> ::= L <source-name> [<template-args>]
1522
+ //
1523
+ // Likewise with <expr-primary>:
1524
+ //
1525
+ // <expr-primary> ::= L <type> <expr-cast-value> E
1526
+ // ::= LZ <encoding> E # cannot overlap; drop
1527
+ // ::= L <mangled_name> E # cannot overlap; drop
1528
+ //
1529
+ // By similar reasoning as shown above, the only <type>s starting with
1530
+ // <source-name> are "<source-name> [<template-args>]". Inline this.
1531
+ //
1532
+ // <expr-primary> ::= L <source-name> [<template-args>] <expr-cast-value> E
1533
+ //
1534
+ // Now inline both of these into <template-arg>:
1535
+ //
1536
+ // <template-arg> ::= L <source-name> [<template-args>]
1537
+ // ::= L <source-name> [<template-args>] <expr-cast-value> E
1538
+ //
1539
+ // Merge them and we're done:
1540
+ // <template-arg>
1541
+ // ::= L <source-name> [<template-args>] [<expr-cast-value> E]
1542
+ if (ParseLocalSourceName(state) && Optional(ParseTemplateArgs(state))) {
1543
+ copy = state->parse_state;
1544
+ if (ParseExprCastValue(state) && ParseOneCharToken(state, 'E')) {
1545
+ return true;
1546
+ }
1547
+ state->parse_state = copy;
1548
+ return true;
1549
+ }
1550
+
1551
+ // Now that the overlapping cases can't reach this code, we can safely call
1552
+ // both of these.
1553
+ if (ParseType(state) || ParseExprPrimary(state)) {
1554
+ return true;
1555
+ }
1556
+ state->parse_state = copy;
1557
+
1558
+ if (ParseOneCharToken(state, 'X') && ParseExpression(state) &&
1559
+ ParseOneCharToken(state, 'E')) {
1560
+ return true;
1561
+ }
1562
+ state->parse_state = copy;
1563
+ return false;
1564
+ }
1565
+
1566
+ // <unresolved-type> ::= <template-param> [<template-args>]
1567
+ // ::= <decltype>
1568
+ // ::= <substitution>
1569
+ static inline bool ParseUnresolvedType(State *state) {
1570
+ // No ComplexityGuard because we don't copy the state in this stack frame.
1571
+ return (ParseTemplateParam(state) && Optional(ParseTemplateArgs(state))) ||
1572
+ ParseDecltype(state) || ParseSubstitution(state, /*accept_std=*/false);
1573
+ }
1574
+
1575
+ // <simple-id> ::= <source-name> [<template-args>]
1576
+ static inline bool ParseSimpleId(State *state) {
1577
+ // No ComplexityGuard because we don't copy the state in this stack frame.
1578
+
1579
+ // Note: <simple-id> cannot be followed by a parameter pack; see comment in
1580
+ // ParseUnresolvedType.
1581
+ return ParseSourceName(state) && Optional(ParseTemplateArgs(state));
1582
+ }
1583
+
1584
+ // <base-unresolved-name> ::= <source-name> [<template-args>]
1585
+ // ::= on <operator-name> [<template-args>]
1586
+ // ::= dn <destructor-name>
1587
+ static bool ParseBaseUnresolvedName(State *state) {
1588
+ ComplexityGuard guard(state);
1589
+ if (guard.IsTooComplex()) return false;
1590
+
1591
+ if (ParseSimpleId(state)) {
1592
+ return true;
1593
+ }
1594
+
1595
+ ParseState copy = state->parse_state;
1596
+ if (ParseTwoCharToken(state, "on") && ParseOperatorName(state, nullptr) &&
1597
+ Optional(ParseTemplateArgs(state))) {
1598
+ return true;
1599
+ }
1600
+ state->parse_state = copy;
1601
+
1602
+ if (ParseTwoCharToken(state, "dn") &&
1603
+ (ParseUnresolvedType(state) || ParseSimpleId(state))) {
1604
+ return true;
1605
+ }
1606
+ state->parse_state = copy;
1607
+
1608
+ return false;
1609
+ }
1610
+
1611
+ // <unresolved-name> ::= [gs] <base-unresolved-name>
1612
+ // ::= sr <unresolved-type> <base-unresolved-name>
1613
+ // ::= srN <unresolved-type> <unresolved-qualifier-level>+ E
1614
+ // <base-unresolved-name>
1615
+ // ::= [gs] sr <unresolved-qualifier-level>+ E
1616
+ // <base-unresolved-name>
1617
+ static bool ParseUnresolvedName(State *state) {
1618
+ ComplexityGuard guard(state);
1619
+ if (guard.IsTooComplex()) return false;
1620
+
1621
+ ParseState copy = state->parse_state;
1622
+ if (Optional(ParseTwoCharToken(state, "gs")) &&
1623
+ ParseBaseUnresolvedName(state)) {
1624
+ return true;
1625
+ }
1626
+ state->parse_state = copy;
1627
+
1628
+ if (ParseTwoCharToken(state, "sr") && ParseUnresolvedType(state) &&
1629
+ ParseBaseUnresolvedName(state)) {
1630
+ return true;
1631
+ }
1632
+ state->parse_state = copy;
1633
+
1634
+ if (ParseTwoCharToken(state, "sr") && ParseOneCharToken(state, 'N') &&
1635
+ ParseUnresolvedType(state) &&
1636
+ OneOrMore(/* <unresolved-qualifier-level> ::= */ ParseSimpleId, state) &&
1637
+ ParseOneCharToken(state, 'E') && ParseBaseUnresolvedName(state)) {
1638
+ return true;
1639
+ }
1640
+ state->parse_state = copy;
1641
+
1642
+ if (Optional(ParseTwoCharToken(state, "gs")) &&
1643
+ ParseTwoCharToken(state, "sr") &&
1644
+ OneOrMore(/* <unresolved-qualifier-level> ::= */ ParseSimpleId, state) &&
1645
+ ParseOneCharToken(state, 'E') && ParseBaseUnresolvedName(state)) {
1646
+ return true;
1647
+ }
1648
+ state->parse_state = copy;
1649
+
1650
+ return false;
1651
+ }
1652
+
1653
+ // <expression> ::= <1-ary operator-name> <expression>
1654
+ // ::= <2-ary operator-name> <expression> <expression>
1655
+ // ::= <3-ary operator-name> <expression> <expression> <expression>
1656
+ // ::= cl <expression>+ E
1657
+ // ::= cp <simple-id> <expression>* E # Clang-specific.
1658
+ // ::= cv <type> <expression> # type (expression)
1659
+ // ::= cv <type> _ <expression>* E # type (expr-list)
1660
+ // ::= st <type>
1661
+ // ::= <template-param>
1662
+ // ::= <function-param>
1663
+ // ::= <expr-primary>
1664
+ // ::= dt <expression> <unresolved-name> # expr.name
1665
+ // ::= pt <expression> <unresolved-name> # expr->name
1666
+ // ::= sp <expression> # argument pack expansion
1667
+ // ::= sr <type> <unqualified-name> <template-args>
1668
+ // ::= sr <type> <unqualified-name>
1669
+ // <function-param> ::= fp <(top-level) CV-qualifiers> _
1670
+ // ::= fp <(top-level) CV-qualifiers> <number> _
1671
+ // ::= fL <number> p <(top-level) CV-qualifiers> _
1672
+ // ::= fL <number> p <(top-level) CV-qualifiers> <number> _
1673
+ static bool ParseExpression(State *state) {
1674
+ ComplexityGuard guard(state);
1675
+ if (guard.IsTooComplex()) return false;
1676
+ if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
1677
+ return true;
1678
+ }
1679
+
1680
+ ParseState copy = state->parse_state;
1681
+
1682
+ // Object/function call expression.
1683
+ if (ParseTwoCharToken(state, "cl") && OneOrMore(ParseExpression, state) &&
1684
+ ParseOneCharToken(state, 'E')) {
1685
+ return true;
1686
+ }
1687
+ state->parse_state = copy;
1688
+
1689
+ // Clang-specific "cp <simple-id> <expression>* E"
1690
+ // https://clang.llvm.org/doxygen/ItaniumMangle_8cpp_source.html#l04338
1691
+ if (ParseTwoCharToken(state, "cp") && ParseSimpleId(state) &&
1692
+ ZeroOrMore(ParseExpression, state) && ParseOneCharToken(state, 'E')) {
1693
+ return true;
1694
+ }
1695
+ state->parse_state = copy;
1696
+
1697
+ // Function-param expression (level 0).
1698
+ if (ParseTwoCharToken(state, "fp") && Optional(ParseCVQualifiers(state)) &&
1699
+ Optional(ParseNumber(state, nullptr)) && ParseOneCharToken(state, '_')) {
1700
+ return true;
1701
+ }
1702
+ state->parse_state = copy;
1703
+
1704
+ // Function-param expression (level 1+).
1705
+ if (ParseTwoCharToken(state, "fL") && Optional(ParseNumber(state, nullptr)) &&
1706
+ ParseOneCharToken(state, 'p') && Optional(ParseCVQualifiers(state)) &&
1707
+ Optional(ParseNumber(state, nullptr)) && ParseOneCharToken(state, '_')) {
1708
+ return true;
1709
+ }
1710
+ state->parse_state = copy;
1711
+
1712
+ // Parse the conversion expressions jointly to avoid re-parsing the <type> in
1713
+ // their common prefix. Parsed as:
1714
+ // <expression> ::= cv <type> <conversion-args>
1715
+ // <conversion-args> ::= _ <expression>* E
1716
+ // ::= <expression>
1717
+ //
1718
+ // Also don't try ParseOperatorName after seeing "cv", since ParseOperatorName
1719
+ // also needs to accept "cv <type>" in other contexts.
1720
+ if (ParseTwoCharToken(state, "cv")) {
1721
+ if (ParseType(state)) {
1722
+ ParseState copy2 = state->parse_state;
1723
+ if (ParseOneCharToken(state, '_') && ZeroOrMore(ParseExpression, state) &&
1724
+ ParseOneCharToken(state, 'E')) {
1725
+ return true;
1726
+ }
1727
+ state->parse_state = copy2;
1728
+ if (ParseExpression(state)) {
1729
+ return true;
1730
+ }
1731
+ }
1732
+ } else {
1733
+ // Parse unary, binary, and ternary operator expressions jointly, taking
1734
+ // care not to re-parse subexpressions repeatedly. Parse like:
1735
+ // <expression> ::= <operator-name> <expression>
1736
+ // [<one-to-two-expressions>]
1737
+ // <one-to-two-expressions> ::= <expression> [<expression>]
1738
+ int arity = -1;
1739
+ if (ParseOperatorName(state, &arity) &&
1740
+ arity > 0 && // 0 arity => disabled.
1741
+ (arity < 3 || ParseExpression(state)) &&
1742
+ (arity < 2 || ParseExpression(state)) &&
1743
+ (arity < 1 || ParseExpression(state))) {
1744
+ return true;
1745
+ }
1746
+ }
1747
+ state->parse_state = copy;
1748
+
1749
+ // sizeof type
1750
+ if (ParseTwoCharToken(state, "st") && ParseType(state)) {
1751
+ return true;
1752
+ }
1753
+ state->parse_state = copy;
1754
+
1755
+ // Object and pointer member access expressions.
1756
+ if ((ParseTwoCharToken(state, "dt") || ParseTwoCharToken(state, "pt")) &&
1757
+ ParseExpression(state) && ParseType(state)) {
1758
+ return true;
1759
+ }
1760
+ state->parse_state = copy;
1761
+
1762
+ // Pointer-to-member access expressions. This parses the same as a binary
1763
+ // operator, but it's implemented separately because "ds" shouldn't be
1764
+ // accepted in other contexts that parse an operator name.
1765
+ if (ParseTwoCharToken(state, "ds") && ParseExpression(state) &&
1766
+ ParseExpression(state)) {
1767
+ return true;
1768
+ }
1769
+ state->parse_state = copy;
1770
+
1771
+ // Parameter pack expansion
1772
+ if (ParseTwoCharToken(state, "sp") && ParseExpression(state)) {
1773
+ return true;
1774
+ }
1775
+ state->parse_state = copy;
1776
+
1777
+ return ParseUnresolvedName(state);
1778
+ }
1779
+
1780
+ // <expr-primary> ::= L <type> <(value) number> E
1781
+ // ::= L <type> <(value) float> E
1782
+ // ::= L <mangled-name> E
1783
+ // // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
1784
+ // ::= LZ <encoding> E
1785
+ //
1786
+ // Warning, subtle: the "bug" LZ production above is ambiguous with the first
1787
+ // production where <type> starts with <local-name>, which can lead to
1788
+ // exponential backtracking in two scenarios:
1789
+ //
1790
+ // - When whatever follows the E in the <local-name> in the first production is
1791
+ // not a name, we backtrack the whole <encoding> and re-parse the whole thing.
1792
+ //
1793
+ // - When whatever follows the <local-name> in the first production is not a
1794
+ // number and this <expr-primary> may be followed by a name, we backtrack the
1795
+ // <name> and re-parse it.
1796
+ //
1797
+ // Moreover this ambiguity isn't always resolved -- for example, the following
1798
+ // has two different parses:
1799
+ //
1800
+ // _ZaaILZ4aoeuE1x1EvE
1801
+ // => operator&&<aoeu, x, E, void>
1802
+ // => operator&&<(aoeu::x)(1), void>
1803
+ //
1804
+ // To resolve this, we just do what GCC's demangler does, and refuse to parse
1805
+ // casts to <local-name> types.
1806
+ static bool ParseExprPrimary(State *state) {
1807
+ ComplexityGuard guard(state);
1808
+ if (guard.IsTooComplex()) return false;
1809
+ ParseState copy = state->parse_state;
1810
+
1811
+ // The "LZ" special case: if we see LZ, we commit to accept "LZ <encoding> E"
1812
+ // or fail, no backtracking.
1813
+ if (ParseTwoCharToken(state, "LZ")) {
1814
+ if (ParseEncoding(state) && ParseOneCharToken(state, 'E')) {
1815
+ return true;
1816
+ }
1817
+
1818
+ state->parse_state = copy;
1819
+ return false;
1820
+ }
1821
+
1822
+ // The merged cast production.
1823
+ if (ParseOneCharToken(state, 'L') && ParseType(state) &&
1824
+ ParseExprCastValue(state)) {
1825
+ return true;
1826
+ }
1827
+ state->parse_state = copy;
1828
+
1829
+ if (ParseOneCharToken(state, 'L') && ParseMangledName(state) &&
1830
+ ParseOneCharToken(state, 'E')) {
1831
+ return true;
1832
+ }
1833
+ state->parse_state = copy;
1834
+
1835
+ return false;
1836
+ }
1837
+
1838
+ // <number> or <float>, followed by 'E', as described above ParseExprPrimary.
1839
+ static bool ParseExprCastValue(State *state) {
1840
+ ComplexityGuard guard(state);
1841
+ if (guard.IsTooComplex()) return false;
1842
+ // We have to be able to backtrack after accepting a number because we could
1843
+ // have e.g. "7fffE", which will accept "7" as a number but then fail to find
1844
+ // the 'E'.
1845
+ ParseState copy = state->parse_state;
1846
+ if (ParseNumber(state, nullptr) && ParseOneCharToken(state, 'E')) {
1847
+ return true;
1848
+ }
1849
+ state->parse_state = copy;
1850
+
1851
+ if (ParseFloatNumber(state) && ParseOneCharToken(state, 'E')) {
1852
+ return true;
1853
+ }
1854
+ state->parse_state = copy;
1855
+
1856
+ return false;
1857
+ }
1858
+
1859
+ // <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
1860
+ // ::= Z <(function) encoding> E s [<discriminator>]
1861
+ //
1862
+ // Parsing a common prefix of these two productions together avoids an
1863
+ // exponential blowup of backtracking. Parse like:
1864
+ // <local-name> := Z <encoding> E <local-name-suffix>
1865
+ // <local-name-suffix> ::= s [<discriminator>]
1866
+ // ::= <name> [<discriminator>]
1867
+
1868
+ static bool ParseLocalNameSuffix(State *state) {
1869
+ ComplexityGuard guard(state);
1870
+ if (guard.IsTooComplex()) return false;
1871
+
1872
+ if (MaybeAppend(state, "::") && ParseName(state) &&
1873
+ Optional(ParseDiscriminator(state))) {
1874
+ return true;
1875
+ }
1876
+
1877
+ // Since we're not going to overwrite the above "::" by re-parsing the
1878
+ // <encoding> (whose trailing '\0' byte was in the byte now holding the
1879
+ // first ':'), we have to rollback the "::" if the <name> parse failed.
1880
+ if (state->parse_state.append) {
1881
+ state->out[state->parse_state.out_cur_idx - 2] = '\0';
1882
+ }
1883
+
1884
+ return ParseOneCharToken(state, 's') && Optional(ParseDiscriminator(state));
1885
+ }
1886
+
1887
+ static bool ParseLocalName(State *state) {
1888
+ ComplexityGuard guard(state);
1889
+ if (guard.IsTooComplex()) return false;
1890
+ ParseState copy = state->parse_state;
1891
+ if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
1892
+ ParseOneCharToken(state, 'E') && ParseLocalNameSuffix(state)) {
1893
+ return true;
1894
+ }
1895
+ state->parse_state = copy;
1896
+ return false;
1897
+ }
1898
+
1899
+ // <discriminator> := _ <(non-negative) number>
1900
+ static bool ParseDiscriminator(State *state) {
1901
+ ComplexityGuard guard(state);
1902
+ if (guard.IsTooComplex()) return false;
1903
+ ParseState copy = state->parse_state;
1904
+ if (ParseOneCharToken(state, '_') && ParseNumber(state, nullptr)) {
1905
+ return true;
1906
+ }
1907
+ state->parse_state = copy;
1908
+ return false;
1909
+ }
1910
+
1911
+ // <substitution> ::= S_
1912
+ // ::= S <seq-id> _
1913
+ // ::= St, etc.
1914
+ //
1915
+ // "St" is special in that it's not valid as a standalone name, and it *is*
1916
+ // allowed to precede a name without being wrapped in "N...E". This means that
1917
+ // if we accept it on its own, we can accept "St1a" and try to parse
1918
+ // template-args, then fail and backtrack, accept "St" on its own, then "1a" as
1919
+ // an unqualified name and re-parse the same template-args. To block this
1920
+ // exponential backtracking, we disable it with 'accept_std=false' in
1921
+ // problematic contexts.
1922
+ static bool ParseSubstitution(State *state, bool accept_std) {
1923
+ ComplexityGuard guard(state);
1924
+ if (guard.IsTooComplex()) return false;
1925
+ if (ParseTwoCharToken(state, "S_")) {
1926
+ MaybeAppend(state, "?"); // We don't support substitutions.
1927
+ return true;
1928
+ }
1929
+
1930
+ ParseState copy = state->parse_state;
1931
+ if (ParseOneCharToken(state, 'S') && ParseSeqId(state) &&
1932
+ ParseOneCharToken(state, '_')) {
1933
+ MaybeAppend(state, "?"); // We don't support substitutions.
1934
+ return true;
1935
+ }
1936
+ state->parse_state = copy;
1937
+
1938
+ // Expand abbreviations like "St" => "std".
1939
+ if (ParseOneCharToken(state, 'S')) {
1940
+ const AbbrevPair *p;
1941
+ for (p = kSubstitutionList; p->abbrev != nullptr; ++p) {
1942
+ if (RemainingInput(state)[0] == p->abbrev[1] &&
1943
+ (accept_std || p->abbrev[1] != 't')) {
1944
+ MaybeAppend(state, "std");
1945
+ if (p->real_name[0] != '\0') {
1946
+ MaybeAppend(state, "::");
1947
+ MaybeAppend(state, p->real_name);
1948
+ }
1949
+ ++state->parse_state.mangled_idx;
1950
+ return true;
1951
+ }
1952
+ }
1953
+ }
1954
+ state->parse_state = copy;
1955
+ return false;
1956
+ }
1957
+
1958
+ // Parse <mangled-name>, optionally followed by either a function-clone suffix
1959
+ // or version suffix. Returns true only if all of "mangled_cur" was consumed.
1960
+ static bool ParseTopLevelMangledName(State *state) {
1961
+ ComplexityGuard guard(state);
1962
+ if (guard.IsTooComplex()) return false;
1963
+ if (ParseMangledName(state)) {
1964
+ if (RemainingInput(state)[0] != '\0') {
1965
+ // Drop trailing function clone suffix, if any.
1966
+ if (IsFunctionCloneSuffix(RemainingInput(state))) {
1967
+ return true;
1968
+ }
1969
+ // Append trailing version suffix if any.
1970
+ // ex. _Z3foo@@GLIBCXX_3.4
1971
+ if (RemainingInput(state)[0] == '@') {
1972
+ MaybeAppend(state, RemainingInput(state));
1973
+ return true;
1974
+ }
1975
+ return false; // Unconsumed suffix.
1976
+ }
1977
+ return true;
1978
+ }
1979
+ return false;
1980
+ }
1981
+
1982
+ static bool Overflowed(const State *state) {
1983
+ return state->parse_state.out_cur_idx >= state->out_end_idx;
1984
+ }
1985
+
1986
+ // The demangler entry point.
1987
+ bool Demangle(const char* mangled, char* out, size_t out_size) {
1988
+ State state;
1989
+ InitState(&state, mangled, out, out_size);
1990
+ return ParseTopLevelMangledName(&state) && !Overflowed(&state) &&
1991
+ state.parse_state.out_cur_idx > 0;
1992
+ }
1993
+
1994
+ std::string DemangleString(const char* mangled) {
1995
+ std::string out;
1996
+ int status = 0;
1997
+ char* demangled = nullptr;
1998
+ #if ABSL_INTERNAL_HAS_CXA_DEMANGLE
1999
+ demangled = abi::__cxa_demangle(mangled, nullptr, nullptr, &status);
2000
+ #endif
2001
+ if (status == 0 && demangled != nullptr) {
2002
+ out.append(demangled);
2003
+ free(demangled);
2004
+ } else {
2005
+ out.append(mangled);
2006
+ }
2007
+ return out;
2008
+ }
2009
+
2010
+ } // namespace debugging_internal
2011
+ ABSL_NAMESPACE_END
2012
+ } // namespace absl
weight/_dep/abseil-cpp/absl/debugging/internal/demangle.h ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
16
+ #define ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
17
+
18
+ #include <string>
19
+ #include "absl/base/config.h"
20
+
21
+ namespace absl {
22
+ ABSL_NAMESPACE_BEGIN
23
+ namespace debugging_internal {
24
+
25
+ // Demangle `mangled`. On success, return true and write the
26
+ // demangled symbol name to `out`. Otherwise, return false.
27
+ // `out` is modified even if demangling is unsuccessful.
28
+ //
29
+ // This function provides an alternative to libstdc++'s abi::__cxa_demangle,
30
+ // which is not async signal safe (it uses malloc internally). It's intended to
31
+ // be used in async signal handlers to symbolize stack traces.
32
+ //
33
+ // Note that this demangler doesn't support full demangling. More
34
+ // specifically, it doesn't print types of function parameters and
35
+ // types of template arguments. It just skips them. However, it's
36
+ // still very useful to extract basic information such as class,
37
+ // function, constructor, destructor, and operator names.
38
+ //
39
+ // See the implementation note in demangle.cc if you are interested.
40
+ //
41
+ // Example:
42
+ //
43
+ // | Mangled Name | Demangle | DemangleString
44
+ // |---------------|-------------|-----------------------
45
+ // | _Z1fv | f() | f()
46
+ // | _Z1fi | f() | f(int)
47
+ // | _Z3foo3bar | foo() | foo(bar)
48
+ // | _Z1fIiEvi | f<>() | void f<int>(int)
49
+ // | _ZN1N1fE | N::f | N::f
50
+ // | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar()
51
+ // | _Zrm1XS_" | operator%() | operator%(X, X)
52
+ // | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo()
53
+ // | _Z1fSs | f() | f(std::basic_string<char,
54
+ // | | | std::char_traits<char>,
55
+ // | | | std::allocator<char> >)
56
+ //
57
+ // See the unit test for more examples.
58
+ //
59
+ // Note: we might want to write demanglers for ABIs other than Itanium
60
+ // C++ ABI in the future.
61
+ bool Demangle(const char* mangled, char* out, size_t out_size);
62
+
63
+ // A wrapper around `abi::__cxa_demangle()`. On success, returns the demangled
64
+ // name. On failure, returns the input mangled name.
65
+ //
66
+ // This function is not async-signal-safe.
67
+ std::string DemangleString(const char* mangled);
68
+
69
+ } // namespace debugging_internal
70
+ ABSL_NAMESPACE_END
71
+ } // namespace absl
72
+
73
+ #endif // ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
weight/_dep/abseil-cpp/absl/debugging/internal/demangle_test.cc ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "absl/debugging/internal/demangle.h"
16
+
17
+ #include <cstdlib>
18
+ #include <string>
19
+
20
+ #include "gmock/gmock.h"
21
+ #include "gtest/gtest.h"
22
+ #include "absl/base/config.h"
23
+ #include "absl/debugging/internal/stack_consumption.h"
24
+ #include "absl/log/log.h"
25
+ #include "absl/memory/memory.h"
26
+
27
+ namespace absl {
28
+ ABSL_NAMESPACE_BEGIN
29
+ namespace debugging_internal {
30
+ namespace {
31
+
32
+ using ::testing::ContainsRegex;
33
+
34
+ // Test corner cases of boundary conditions.
35
+ TEST(Demangle, CornerCases) {
36
+ char tmp[10];
37
+ EXPECT_TRUE(Demangle("_Z6foobarv", tmp, sizeof(tmp)));
38
+ // sizeof("foobar()") == 9
39
+ EXPECT_STREQ("foobar()", tmp);
40
+ EXPECT_TRUE(Demangle("_Z6foobarv", tmp, 9));
41
+ EXPECT_STREQ("foobar()", tmp);
42
+ EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 8)); // Not enough.
43
+ EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 1));
44
+ EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 0));
45
+ EXPECT_FALSE(Demangle("_Z6foobarv", nullptr, 0)); // Should not cause SEGV.
46
+ EXPECT_FALSE(Demangle("_Z1000000", tmp, 9));
47
+ }
48
+
49
+ // Test handling of functions suffixed with .clone.N, which is used
50
+ // by GCC 4.5.x (and our locally-modified version of GCC 4.4.x), and
51
+ // .constprop.N and .isra.N, which are used by GCC 4.6.x. These
52
+ // suffixes are used to indicate functions which have been cloned
53
+ // during optimization. We ignore these suffixes.
54
+ TEST(Demangle, Clones) {
55
+ char tmp[20];
56
+ EXPECT_TRUE(Demangle("_ZL3Foov", tmp, sizeof(tmp)));
57
+ EXPECT_STREQ("Foo()", tmp);
58
+ EXPECT_TRUE(Demangle("_ZL3Foov.clone.3", tmp, sizeof(tmp)));
59
+ EXPECT_STREQ("Foo()", tmp);
60
+ EXPECT_TRUE(Demangle("_ZL3Foov.constprop.80", tmp, sizeof(tmp)));
61
+ EXPECT_STREQ("Foo()", tmp);
62
+ EXPECT_TRUE(Demangle("_ZL3Foov.isra.18", tmp, sizeof(tmp)));
63
+ EXPECT_STREQ("Foo()", tmp);
64
+ EXPECT_TRUE(Demangle("_ZL3Foov.isra.2.constprop.18", tmp, sizeof(tmp)));
65
+ EXPECT_STREQ("Foo()", tmp);
66
+ // Demangle suffixes produced by -funique-internal-linkage-names.
67
+ EXPECT_TRUE(Demangle("_ZL3Foov.__uniq.12345", tmp, sizeof(tmp)));
68
+ EXPECT_STREQ("Foo()", tmp);
69
+ EXPECT_TRUE(Demangle("_ZL3Foov.__uniq.12345.isra.2.constprop.18", tmp,
70
+ sizeof(tmp)));
71
+ EXPECT_STREQ("Foo()", tmp);
72
+ // Suffixes without the number should also demangle.
73
+ EXPECT_TRUE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp)));
74
+ EXPECT_STREQ("Foo()", tmp);
75
+ // Suffixes with just the number should also demangle.
76
+ EXPECT_TRUE(Demangle("_ZL3Foov.123", tmp, sizeof(tmp)));
77
+ EXPECT_STREQ("Foo()", tmp);
78
+ // (.clone. followed by non-number), should also demangle.
79
+ EXPECT_TRUE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp)));
80
+ EXPECT_STREQ("Foo()", tmp);
81
+ // (.clone. followed by multiple numbers), should also demangle.
82
+ EXPECT_TRUE(Demangle("_ZL3Foov.clone.123.456", tmp, sizeof(tmp)));
83
+ EXPECT_STREQ("Foo()", tmp);
84
+ // (a long valid suffix), should demangle.
85
+ EXPECT_TRUE(Demangle("_ZL3Foov.part.9.165493.constprop.775.31805", tmp,
86
+ sizeof(tmp)));
87
+ EXPECT_STREQ("Foo()", tmp);
88
+ // Invalid (. without anything else), should not demangle.
89
+ EXPECT_FALSE(Demangle("_ZL3Foov.", tmp, sizeof(tmp)));
90
+ // Invalid (. with mix of alpha and digits), should not demangle.
91
+ EXPECT_FALSE(Demangle("_ZL3Foov.abc123", tmp, sizeof(tmp)));
92
+ // Invalid (.clone. not followed by number), should not demangle.
93
+ EXPECT_FALSE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp)));
94
+ // Invalid (.constprop. not followed by number), should not demangle.
95
+ EXPECT_FALSE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp)));
96
+ }
97
+
98
+ // Test the GNU abi_tag extension.
99
+ TEST(Demangle, AbiTags) {
100
+ char tmp[80];
101
+
102
+ // Mangled name generated via:
103
+ // struct [[gnu::abi_tag("abc")]] A{};
104
+ // A a;
105
+ EXPECT_TRUE(Demangle("_Z1aB3abc", tmp, sizeof(tmp)));
106
+ EXPECT_STREQ("a[abi:abc]", tmp);
107
+
108
+ // Mangled name generated via:
109
+ // struct B {
110
+ // B [[gnu::abi_tag("xyz")]] (){};
111
+ // };
112
+ // B b;
113
+ EXPECT_TRUE(Demangle("_ZN1BC2B3xyzEv", tmp, sizeof(tmp)));
114
+ EXPECT_STREQ("B::B[abi:xyz]()", tmp);
115
+
116
+ // Mangled name generated via:
117
+ // [[gnu::abi_tag("foo", "bar")]] void C() {}
118
+ EXPECT_TRUE(Demangle("_Z1CB3barB3foov", tmp, sizeof(tmp)));
119
+ EXPECT_STREQ("C[abi:bar][abi:foo]()", tmp);
120
+ }
121
+
122
+ // Tests that verify that Demangle footprint is within some limit.
123
+ // They are not to be run under sanitizers as the sanitizers increase
124
+ // stack consumption by about 4x.
125
+ #if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \
126
+ !defined(ABSL_HAVE_ADDRESS_SANITIZER) && \
127
+ !defined(ABSL_HAVE_MEMORY_SANITIZER) && \
128
+ !defined(ABSL_HAVE_THREAD_SANITIZER)
129
+
130
+ static const char *g_mangled;
131
+ static char g_demangle_buffer[4096];
132
+ static char *g_demangle_result;
133
+
134
+ static void DemangleSignalHandler(int signo) {
135
+ if (Demangle(g_mangled, g_demangle_buffer, sizeof(g_demangle_buffer))) {
136
+ g_demangle_result = g_demangle_buffer;
137
+ } else {
138
+ g_demangle_result = nullptr;
139
+ }
140
+ }
141
+
142
+ // Call Demangle and figure out the stack footprint of this call.
143
+ static const char *DemangleStackConsumption(const char *mangled,
144
+ int *stack_consumed) {
145
+ g_mangled = mangled;
146
+ *stack_consumed = GetSignalHandlerStackConsumption(DemangleSignalHandler);
147
+ LOG(INFO) << "Stack consumption of Demangle: " << *stack_consumed;
148
+ return g_demangle_result;
149
+ }
150
+
151
+ // Demangle stack consumption should be within 8kB for simple mangled names
152
+ // with some level of nesting. With alternate signal stack we have 64K,
153
+ // but some signal handlers run on thread stack, and could have arbitrarily
154
+ // little space left (so we don't want to make this number too large).
155
+ const int kStackConsumptionUpperLimit = 8192;
156
+
157
+ // Returns a mangled name nested to the given depth.
158
+ static std::string NestedMangledName(int depth) {
159
+ std::string mangled_name = "_Z1a";
160
+ if (depth > 0) {
161
+ mangled_name += "IXL";
162
+ mangled_name += NestedMangledName(depth - 1);
163
+ mangled_name += "EEE";
164
+ }
165
+ return mangled_name;
166
+ }
167
+
168
+ TEST(Demangle, DemangleStackConsumption) {
169
+ // Measure stack consumption of Demangle for nested mangled names of varying
170
+ // depth. Since Demangle is implemented as a recursive descent parser,
171
+ // stack consumption will grow as the nesting depth increases. By measuring
172
+ // the stack consumption for increasing depths, we can see the growing
173
+ // impact of any stack-saving changes made to the code for Demangle.
174
+ int stack_consumed = 0;
175
+
176
+ const char *demangled =
177
+ DemangleStackConsumption("_Z6foobarv", &stack_consumed);
178
+ EXPECT_STREQ("foobar()", demangled);
179
+ EXPECT_GT(stack_consumed, 0);
180
+ EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
181
+
182
+ const std::string nested_mangled_name0 = NestedMangledName(0);
183
+ demangled = DemangleStackConsumption(nested_mangled_name0.c_str(),
184
+ &stack_consumed);
185
+ EXPECT_STREQ("a", demangled);
186
+ EXPECT_GT(stack_consumed, 0);
187
+ EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
188
+
189
+ const std::string nested_mangled_name1 = NestedMangledName(1);
190
+ demangled = DemangleStackConsumption(nested_mangled_name1.c_str(),
191
+ &stack_consumed);
192
+ EXPECT_STREQ("a<>", demangled);
193
+ EXPECT_GT(stack_consumed, 0);
194
+ EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
195
+
196
+ const std::string nested_mangled_name2 = NestedMangledName(2);
197
+ demangled = DemangleStackConsumption(nested_mangled_name2.c_str(),
198
+ &stack_consumed);
199
+ EXPECT_STREQ("a<>", demangled);
200
+ EXPECT_GT(stack_consumed, 0);
201
+ EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
202
+
203
+ const std::string nested_mangled_name3 = NestedMangledName(3);
204
+ demangled = DemangleStackConsumption(nested_mangled_name3.c_str(),
205
+ &stack_consumed);
206
+ EXPECT_STREQ("a<>", demangled);
207
+ EXPECT_GT(stack_consumed, 0);
208
+ EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
209
+ }
210
+
211
+ #endif // Stack consumption tests
212
+
213
+ static void TestOnInput(const char* input) {
214
+ static const int kOutSize = 1048576;
215
+ auto out = absl::make_unique<char[]>(kOutSize);
216
+ Demangle(input, out.get(), kOutSize);
217
+ }
218
+
219
+ TEST(DemangleRegression, NegativeLength) {
220
+ TestOnInput("_ZZn4");
221
+ }
222
+
223
+ TEST(DemangleRegression, DeeplyNestedArrayType) {
224
+ const int depth = 100000;
225
+ std::string data = "_ZStI";
226
+ data.reserve(data.size() + 3 * depth + 1);
227
+ for (int i = 0; i < depth; i++) {
228
+ data += "A1_";
229
+ }
230
+ TestOnInput(data.c_str());
231
+ }
232
+
233
+ struct Base {
234
+ virtual ~Base() = default;
235
+ };
236
+
237
+ struct Derived : public Base {};
238
+
239
+ TEST(DemangleStringTest, SupportsSymbolNameReturnedByTypeId) {
240
+ EXPECT_EQ(DemangleString(typeid(int).name()), "int");
241
+ // We want to test that `DemangleString` can demangle the symbol names
242
+ // returned by `typeid`, but without hard-coding the actual demangled values
243
+ // (because they are platform-specific).
244
+ EXPECT_THAT(
245
+ DemangleString(typeid(Base).name()),
246
+ ContainsRegex("absl.*debugging_internal.*anonymous namespace.*::Base"));
247
+ EXPECT_THAT(DemangleString(typeid(Derived).name()),
248
+ ContainsRegex(
249
+ "absl.*debugging_internal.*anonymous namespace.*::Derived"));
250
+ }
251
+
252
+ } // namespace
253
+ } // namespace debugging_internal
254
+ ABSL_NAMESPACE_END
255
+ } // namespace absl
weight/_dep/abseil-cpp/absl/debugging/internal/elf_mem_image.cc ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2017 The Abseil Authors.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ // Allow dynamic symbol lookup in an in-memory Elf image.
16
+ //
17
+
18
+ #include "absl/debugging/internal/elf_mem_image.h"
19
+
20
+ #ifdef ABSL_HAVE_ELF_MEM_IMAGE // defined in elf_mem_image.h
21
+
22
+ #include <string.h>
23
+ #include <cassert>
24
+ #include <cstddef>
25
+ #include "absl/base/config.h"
26
+ #include "absl/base/internal/raw_logging.h"
27
+
28
+ // From binutils/include/elf/common.h (this doesn't appear to be documented
29
+ // anywhere else).
30
+ //
31
+ // /* This flag appears in a Versym structure. It means that the symbol
32
+ // is hidden, and is only visible with an explicit version number.
33
+ // This is a GNU extension. */
34
+ // #define VERSYM_HIDDEN 0x8000
35
+ //
36
+ // /* This is the mask for the rest of the Versym information. */
37
+ // #define VERSYM_VERSION 0x7fff
38
+
39
+ #define VERSYM_VERSION 0x7fff
40
+
41
+ namespace absl {
42
+ ABSL_NAMESPACE_BEGIN
43
+ namespace debugging_internal {
44
+
45
+ namespace {
46
+
47
+ #if __SIZEOF_POINTER__ == 4
48
+ const int kElfClass = ELFCLASS32;
49
+ int ElfBind(const ElfW(Sym) *symbol) { return ELF32_ST_BIND(symbol->st_info); }
50
+ int ElfType(const ElfW(Sym) *symbol) { return ELF32_ST_TYPE(symbol->st_info); }
51
+ #elif __SIZEOF_POINTER__ == 8
52
+ const int kElfClass = ELFCLASS64;
53
+ int ElfBind(const ElfW(Sym) *symbol) { return ELF64_ST_BIND(symbol->st_info); }
54
+ int ElfType(const ElfW(Sym) *symbol) { return ELF64_ST_TYPE(symbol->st_info); }
55
+ #else
56
+ const int kElfClass = -1;
57
+ int ElfBind(const ElfW(Sym) *) {
58
+ ABSL_RAW_LOG(FATAL, "Unexpected word size");
59
+ return 0;
60
+ }
61
+ int ElfType(const ElfW(Sym) *) {
62
+ ABSL_RAW_LOG(FATAL, "Unexpected word size");
63
+ return 0;
64
+ }
65
+ #endif
66
+
67
+ // Extract an element from one of the ELF tables, cast it to desired type.
68
+ // This is just a simple arithmetic and a glorified cast.
69
+ // Callers are responsible for bounds checking.
70
+ template <typename T>
71
+ const T *GetTableElement(const ElfW(Ehdr) * ehdr, ElfW(Off) table_offset,
72
+ ElfW(Word) element_size, size_t index) {
73
+ return reinterpret_cast<const T*>(reinterpret_cast<const char *>(ehdr)
74
+ + table_offset
75
+ + index * element_size);
76
+ }
77
+
78
+ } // namespace
79
+
80
+ // The value of this variable doesn't matter; it's used only for its
81
+ // unique address.
82
+ const int ElfMemImage::kInvalidBaseSentinel = 0;
83
+
84
+ ElfMemImage::ElfMemImage(const void *base) {
85
+ ABSL_RAW_CHECK(base != kInvalidBase, "bad pointer");
86
+ Init(base);
87
+ }
88
+
89
+ int ElfMemImage::GetNumSymbols() const {
90
+ if (!hash_) {
91
+ return 0;
92
+ }
93
+ // See http://www.caldera.com/developers/gabi/latest/ch5.dynamic.html#hash
94
+ return static_cast<int>(hash_[1]);
95
+ }
96
+
97
+ const ElfW(Sym) *ElfMemImage::GetDynsym(int index) const {
98
+ ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
99
+ return dynsym_ + index;
100
+ }
101
+
102
+ const ElfW(Versym) *ElfMemImage::GetVersym(int index) const {
103
+ ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
104
+ return versym_ + index;
105
+ }
106
+
107
+ const ElfW(Phdr) *ElfMemImage::GetPhdr(int index) const {
108
+ ABSL_RAW_CHECK(index >= 0 && index < ehdr_->e_phnum, "index out of range");
109
+ return GetTableElement<ElfW(Phdr)>(ehdr_, ehdr_->e_phoff, ehdr_->e_phentsize,
110
+ static_cast<size_t>(index));
111
+ }
112
+
113
+ const char *ElfMemImage::GetDynstr(ElfW(Word) offset) const {
114
+ ABSL_RAW_CHECK(offset < strsize_, "offset out of range");
115
+ return dynstr_ + offset;
116
+ }
117
+
118
+ const void *ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
119
+ if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) {
120
+ // Symbol corresponds to "special" (e.g. SHN_ABS) section.
121
+ return reinterpret_cast<const void *>(sym->st_value);
122
+ }
123
+ ABSL_RAW_CHECK(link_base_ < sym->st_value, "symbol out of range");
124
+ return GetTableElement<char>(ehdr_, 0, 1, sym->st_value - link_base_);
125
+ }
126
+
127
+ const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const {
128
+ ABSL_RAW_CHECK(0 <= index && static_cast<size_t>(index) <= verdefnum_,
129
+ "index out of range");
130
+ const ElfW(Verdef) *version_definition = verdef_;
131
+ while (version_definition->vd_ndx < index && version_definition->vd_next) {
132
+ const char *const version_definition_as_char =
133
+ reinterpret_cast<const char *>(version_definition);
134
+ version_definition =
135
+ reinterpret_cast<const ElfW(Verdef) *>(version_definition_as_char +
136
+ version_definition->vd_next);
137
+ }
138
+ return version_definition->vd_ndx == index ? version_definition : nullptr;
139
+ }
140
+
141
+ const ElfW(Verdaux) *ElfMemImage::GetVerdefAux(
142
+ const ElfW(Verdef) *verdef) const {
143
+ return reinterpret_cast<const ElfW(Verdaux) *>(verdef+1);
144
+ }
145
+
146
+ const char *ElfMemImage::GetVerstr(ElfW(Word) offset) const {
147
+ ABSL_RAW_CHECK(offset < strsize_, "offset out of range");
148
+ return dynstr_ + offset;
149
+ }
150
+
151
+ void ElfMemImage::Init(const void *base) {
152
+ ehdr_ = nullptr;
153
+ dynsym_ = nullptr;
154
+ dynstr_ = nullptr;
155
+ versym_ = nullptr;
156
+ verdef_ = nullptr;
157
+ hash_ = nullptr;
158
+ strsize_ = 0;
159
+ verdefnum_ = 0;
160
+ // Sentinel: PT_LOAD .p_vaddr can't possibly be this.
161
+ link_base_ = ~ElfW(Addr){0}; // NOLINT(readability/braces)
162
+ if (!base) {
163
+ return;
164
+ }
165
+ const char *const base_as_char = reinterpret_cast<const char *>(base);
166
+ if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
167
+ base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
168
+ assert(false);
169
+ return;
170
+ }
171
+ int elf_class = base_as_char[EI_CLASS];
172
+ if (elf_class != kElfClass) {
173
+ assert(false);
174
+ return;
175
+ }
176
+ switch (base_as_char[EI_DATA]) {
177
+ case ELFDATA2LSB: {
178
+ #ifndef ABSL_IS_LITTLE_ENDIAN
179
+ assert(false);
180
+ return;
181
+ #endif
182
+ break;
183
+ }
184
+ case ELFDATA2MSB: {
185
+ #ifndef ABSL_IS_BIG_ENDIAN
186
+ assert(false);
187
+ return;
188
+ #endif
189
+ break;
190
+ }
191
+ default: {
192
+ assert(false);
193
+ return;
194
+ }
195
+ }
196
+
197
+ ehdr_ = reinterpret_cast<const ElfW(Ehdr) *>(base);
198
+ const ElfW(Phdr) *dynamic_program_header = nullptr;
199
+ for (int i = 0; i < ehdr_->e_phnum; ++i) {
200
+ const ElfW(Phdr) *const program_header = GetPhdr(i);
201
+ switch (program_header->p_type) {
202
+ case PT_LOAD:
203
+ if (!~link_base_) {
204
+ link_base_ = program_header->p_vaddr;
205
+ }
206
+ break;
207
+ case PT_DYNAMIC:
208
+ dynamic_program_header = program_header;
209
+ break;
210
+ }
211
+ }
212
+ if (!~link_base_ || !dynamic_program_header) {
213
+ assert(false);
214
+ // Mark this image as not present. Can not recur infinitely.
215
+ Init(nullptr);
216
+ return;
217
+ }
218
+ ptrdiff_t relocation =
219
+ base_as_char - reinterpret_cast<const char *>(link_base_);
220
+ ElfW(Dyn)* dynamic_entry = reinterpret_cast<ElfW(Dyn)*>(
221
+ static_cast<intptr_t>(dynamic_program_header->p_vaddr) + relocation);
222
+ for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
223
+ const auto value =
224
+ static_cast<intptr_t>(dynamic_entry->d_un.d_val) + relocation;
225
+ switch (dynamic_entry->d_tag) {
226
+ case DT_HASH:
227
+ hash_ = reinterpret_cast<ElfW(Word) *>(value);
228
+ break;
229
+ case DT_SYMTAB:
230
+ dynsym_ = reinterpret_cast<ElfW(Sym) *>(value);
231
+ break;
232
+ case DT_STRTAB:
233
+ dynstr_ = reinterpret_cast<const char *>(value);
234
+ break;
235
+ case DT_VERSYM:
236
+ versym_ = reinterpret_cast<ElfW(Versym) *>(value);
237
+ break;
238
+ case DT_VERDEF:
239
+ verdef_ = reinterpret_cast<ElfW(Verdef) *>(value);
240
+ break;
241
+ case DT_VERDEFNUM:
242
+ verdefnum_ = static_cast<size_t>(dynamic_entry->d_un.d_val);
243
+ break;
244
+ case DT_STRSZ:
245
+ strsize_ = static_cast<size_t>(dynamic_entry->d_un.d_val);
246
+ break;
247
+ default:
248
+ // Unrecognized entries explicitly ignored.
249
+ break;
250
+ }
251
+ }
252
+ if (!hash_ || !dynsym_ || !dynstr_ || !versym_ ||
253
+ !verdef_ || !verdefnum_ || !strsize_) {
254
+ assert(false); // invalid VDSO
255
+ // Mark this image as not present. Can not recur infinitely.
256
+ Init(nullptr);
257
+ return;
258
+ }
259
+ }
260
+
261
+ bool ElfMemImage::LookupSymbol(const char *name,
262
+ const char *version,
263
+ int type,
264
+ SymbolInfo *info_out) const {
265
+ for (const SymbolInfo& info : *this) {
266
+ if (strcmp(info.name, name) == 0 && strcmp(info.version, version) == 0 &&
267
+ ElfType(info.symbol) == type) {
268
+ if (info_out) {
269
+ *info_out = info;
270
+ }
271
+ return true;
272
+ }
273
+ }
274
+ return false;
275
+ }
276
+
277
+ bool ElfMemImage::LookupSymbolByAddress(const void *address,
278
+ SymbolInfo *info_out) const {
279
+ for (const SymbolInfo& info : *this) {
280
+ const char *const symbol_start =
281
+ reinterpret_cast<const char *>(info.address);
282
+ const char *const symbol_end = symbol_start + info.symbol->st_size;
283
+ if (symbol_start <= address && address < symbol_end) {
284
+ if (info_out) {
285
+ // Client wants to know details for that symbol (the usual case).
286
+ if (ElfBind(info.symbol) == STB_GLOBAL) {
287
+ // Strong symbol; just return it.
288
+ *info_out = info;
289
+ return true;
290
+ } else {
291
+ // Weak or local. Record it, but keep looking for a strong one.
292
+ *info_out = info;
293
+ }
294
+ } else {
295
+ // Client only cares if there is an overlapping symbol.
296
+ return true;
297
+ }
298
+ }
299
+ }
300
+ return false;
301
+ }
302
+
303
+ ElfMemImage::SymbolIterator::SymbolIterator(const void *const image, int index)
304
+ : index_(index), image_(image) {
305
+ }
306
+
307
+ const ElfMemImage::SymbolInfo *ElfMemImage::SymbolIterator::operator->() const {
308
+ return &info_;
309
+ }
310
+
311
+ const ElfMemImage::SymbolInfo& ElfMemImage::SymbolIterator::operator*() const {
312
+ return info_;
313
+ }
314
+
315
+ bool ElfMemImage::SymbolIterator::operator==(const SymbolIterator &rhs) const {
316
+ return this->image_ == rhs.image_ && this->index_ == rhs.index_;
317
+ }
318
+
319
+ bool ElfMemImage::SymbolIterator::operator!=(const SymbolIterator &rhs) const {
320
+ return !(*this == rhs);
321
+ }
322
+
323
+ ElfMemImage::SymbolIterator &ElfMemImage::SymbolIterator::operator++() {
324
+ this->Update(1);
325
+ return *this;
326
+ }
327
+
328
+ ElfMemImage::SymbolIterator ElfMemImage::begin() const {
329
+ SymbolIterator it(this, 0);
330
+ it.Update(0);
331
+ return it;
332
+ }
333
+
334
+ ElfMemImage::SymbolIterator ElfMemImage::end() const {
335
+ return SymbolIterator(this, GetNumSymbols());
336
+ }
337
+
338
+ void ElfMemImage::SymbolIterator::Update(int increment) {
339
+ const ElfMemImage *image = reinterpret_cast<const ElfMemImage *>(image_);
340
+ ABSL_RAW_CHECK(image->IsPresent() || increment == 0, "");
341
+ if (!image->IsPresent()) {
342
+ return;
343
+ }
344
+ index_ += increment;
345
+ if (index_ >= image->GetNumSymbols()) {
346
+ index_ = image->GetNumSymbols();
347
+ return;
348
+ }
349
+ const ElfW(Sym) *symbol = image->GetDynsym(index_);
350
+ const ElfW(Versym) *version_symbol = image->GetVersym(index_);
351
+ ABSL_RAW_CHECK(symbol && version_symbol, "");
352
+ const char *const symbol_name = image->GetDynstr(symbol->st_name);
353
+ #if defined(__NetBSD__)
354
+ const int version_index = version_symbol->vs_vers & VERSYM_VERSION;
355
+ #else
356
+ const ElfW(Versym) version_index = version_symbol[0] & VERSYM_VERSION;
357
+ #endif
358
+ const ElfW(Verdef) *version_definition = nullptr;
359
+ const char *version_name = "";
360
+ if (symbol->st_shndx == SHN_UNDEF) {
361
+ // Undefined symbols reference DT_VERNEED, not DT_VERDEF, and
362
+ // version_index could well be greater than verdefnum_, so calling
363
+ // GetVerdef(version_index) may trigger assertion.
364
+ } else {
365
+ version_definition = image->GetVerdef(version_index);
366
+ }
367
+ if (version_definition) {
368
+ // I am expecting 1 or 2 auxiliary entries: 1 for the version itself,
369
+ // optional 2nd if the version has a parent.
370
+ ABSL_RAW_CHECK(
371
+ version_definition->vd_cnt == 1 || version_definition->vd_cnt == 2,
372
+ "wrong number of entries");
373
+ const ElfW(Verdaux) *version_aux = image->GetVerdefAux(version_definition);
374
+ version_name = image->GetVerstr(version_aux->vda_name);
375
+ }
376
+ info_.name = symbol_name;
377
+ info_.version = version_name;
378
+ info_.address = image->GetSymAddr(symbol);
379
+ info_.symbol = symbol;
380
+ }
381
+
382
+ } // namespace debugging_internal
383
+ ABSL_NAMESPACE_END
384
+ } // namespace absl
385
+
386
+ #endif // ABSL_HAVE_ELF_MEM_IMAGE
weight/_dep/abseil-cpp/absl/debugging/internal/elf_mem_image.h ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * Copyright 2017 The Abseil Authors.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ // Allow dynamic symbol lookup for in-memory Elf images.
18
+
19
+ #ifndef ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
20
+ #define ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
21
+
22
+ // Including this will define the __GLIBC__ macro if glibc is being
23
+ // used.
24
+ #include <climits>
25
+
26
+ #include "absl/base/config.h"
27
+
28
+ // Maybe one day we can rewrite this file not to require the elf
29
+ // symbol extensions in glibc, but for right now we need them.
30
+ #ifdef ABSL_HAVE_ELF_MEM_IMAGE
31
+ #error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set
32
+ #endif
33
+
34
+ #if defined(__ELF__) && !defined(__OpenBSD__) && !defined(__QNX__) && \
35
+ !defined(__native_client__) && !defined(__asmjs__) && \
36
+ !defined(__wasm__) && !defined(__HAIKU__) && !defined(__sun) && \
37
+ !defined(__VXWORKS__) && !defined(__hexagon__)
38
+ #define ABSL_HAVE_ELF_MEM_IMAGE 1
39
+ #endif
40
+
41
+ #ifdef ABSL_HAVE_ELF_MEM_IMAGE
42
+
43
+ #include <link.h> // for ElfW
44
+
45
+ #if defined(__FreeBSD__) && !defined(ElfW)
46
+ #define ElfW(x) __ElfN(x)
47
+ #endif
48
+
49
+ namespace absl {
50
+ ABSL_NAMESPACE_BEGIN
51
+ namespace debugging_internal {
52
+
53
+ // An in-memory ELF image (may not exist on disk).
54
+ class ElfMemImage {
55
+ private:
56
+ // Sentinel: there could never be an elf image at &kInvalidBaseSentinel.
57
+ static const int kInvalidBaseSentinel;
58
+
59
+ public:
60
+ // Sentinel: there could never be an elf image at this address.
61
+ static constexpr const void *const kInvalidBase =
62
+ static_cast<const void*>(&kInvalidBaseSentinel);
63
+
64
+ // Information about a single vdso symbol.
65
+ // All pointers are into .dynsym, .dynstr, or .text of the VDSO.
66
+ // Do not free() them or modify through them.
67
+ struct SymbolInfo {
68
+ const char *name; // E.g. "__vdso_getcpu"
69
+ const char *version; // E.g. "LINUX_2.6", could be ""
70
+ // for unversioned symbol.
71
+ const void *address; // Relocated symbol address.
72
+ const ElfW(Sym) *symbol; // Symbol in the dynamic symbol table.
73
+ };
74
+
75
+ // Supports iteration over all dynamic symbols.
76
+ class SymbolIterator {
77
+ public:
78
+ friend class ElfMemImage;
79
+ const SymbolInfo *operator->() const;
80
+ const SymbolInfo &operator*() const;
81
+ SymbolIterator& operator++();
82
+ bool operator!=(const SymbolIterator &rhs) const;
83
+ bool operator==(const SymbolIterator &rhs) const;
84
+ private:
85
+ SymbolIterator(const void *const image, int index);
86
+ void Update(int incr);
87
+ SymbolInfo info_;
88
+ int index_;
89
+ const void *const image_;
90
+ };
91
+
92
+
93
+ explicit ElfMemImage(const void *base);
94
+ void Init(const void *base);
95
+ bool IsPresent() const { return ehdr_ != nullptr; }
96
+ const ElfW(Phdr)* GetPhdr(int index) const;
97
+ const ElfW(Sym)* GetDynsym(int index) const;
98
+ const ElfW(Versym)* GetVersym(int index) const;
99
+ const ElfW(Verdef)* GetVerdef(int index) const;
100
+ const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const;
101
+ const char* GetDynstr(ElfW(Word) offset) const;
102
+ const void* GetSymAddr(const ElfW(Sym) *sym) const;
103
+ const char* GetVerstr(ElfW(Word) offset) const;
104
+ int GetNumSymbols() const;
105
+
106
+ SymbolIterator begin() const;
107
+ SymbolIterator end() const;
108
+
109
+ // Look up versioned dynamic symbol in the image.
110
+ // Returns false if image is not present, or doesn't contain given
111
+ // symbol/version/type combination.
112
+ // If info_out is non-null, additional details are filled in.
113
+ bool LookupSymbol(const char *name, const char *version,
114
+ int symbol_type, SymbolInfo *info_out) const;
115
+
116
+ // Find info about symbol (if any) which overlaps given address.
117
+ // Returns true if symbol was found; false if image isn't present
118
+ // or doesn't have a symbol overlapping given address.
119
+ // If info_out is non-null, additional details are filled in.
120
+ bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
121
+
122
+ private:
123
+ const ElfW(Ehdr) *ehdr_;
124
+ const ElfW(Sym) *dynsym_;
125
+ const ElfW(Versym) *versym_;
126
+ const ElfW(Verdef) *verdef_;
127
+ const ElfW(Word) *hash_;
128
+ const char *dynstr_;
129
+ size_t strsize_;
130
+ size_t verdefnum_;
131
+ ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD).
132
+ };
133
+
134
+ } // namespace debugging_internal
135
+ ABSL_NAMESPACE_END
136
+ } // namespace absl
137
+
138
+ #endif // ABSL_HAVE_ELF_MEM_IMAGE
139
+
140
+ #endif // ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
weight/_dep/abseil-cpp/absl/debugging/internal/examine_stack.cc ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Copyright 2018 The Abseil Authors.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // https://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ //
16
+
17
+ #include "absl/debugging/internal/examine_stack.h"
18
+
19
+ #ifndef _WIN32
20
+ #include <unistd.h>
21
+ #endif
22
+
23
+ #include "absl/base/config.h"
24
+
25
+ #ifdef ABSL_HAVE_MMAP
26
+ #include <sys/mman.h>
27
+ #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
28
+ #define MAP_ANONYMOUS MAP_ANON
29
+ #endif
30
+ #endif
31
+
32
+ #if defined(__linux__) || defined(__APPLE__)
33
+ #include <sys/ucontext.h>
34
+ #endif
35
+
36
+ #include <csignal>
37
+ #include <cstdio>
38
+
39
+ #include "absl/base/attributes.h"
40
+ #include "absl/base/internal/raw_logging.h"
41
+ #include "absl/base/macros.h"
42
+ #include "absl/debugging/stacktrace.h"
43
+ #include "absl/debugging/symbolize.h"
44
+
45
+ namespace absl {
46
+ ABSL_NAMESPACE_BEGIN
47
+ namespace debugging_internal {
48
+
49
+ namespace {
50
+ constexpr int kDefaultDumpStackFramesLimit = 64;
51
+ // The %p field width for printf() functions is two characters per byte,
52
+ // and two extra for the leading "0x".
53
+ constexpr int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
54
+
55
+ ABSL_CONST_INIT SymbolizeUrlEmitter debug_stack_trace_hook = nullptr;
56
+
57
+ // Async-signal safe mmap allocator.
58
+ void* Allocate(size_t num_bytes) {
59
+ #ifdef ABSL_HAVE_MMAP
60
+ void* p = ::mmap(nullptr, num_bytes, PROT_READ | PROT_WRITE,
61
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
62
+ return p == MAP_FAILED ? nullptr : p;
63
+ #else
64
+ (void)num_bytes;
65
+ return nullptr;
66
+ #endif // ABSL_HAVE_MMAP
67
+ }
68
+
69
+ void Deallocate(void* p, size_t size) {
70
+ #ifdef ABSL_HAVE_MMAP
71
+ ::munmap(p, size);
72
+ #else
73
+ (void)p;
74
+ (void)size;
75
+ #endif // ABSL_HAVE_MMAP
76
+ }
77
+
78
+ // Print a program counter only.
79
+ void DumpPC(OutputWriter* writer, void* writer_arg, void* const pc,
80
+ const char* const prefix) {
81
+ char buf[100];
82
+ snprintf(buf, sizeof(buf), "%s@ %*p\n", prefix, kPrintfPointerFieldWidth, pc);
83
+ writer(buf, writer_arg);
84
+ }
85
+
86
+ // Print a program counter and the corresponding stack frame size.
87
+ void DumpPCAndFrameSize(OutputWriter* writer, void* writer_arg, void* const pc,
88
+ int framesize, const char* const prefix) {
89
+ char buf[100];
90
+ if (framesize <= 0) {
91
+ snprintf(buf, sizeof(buf), "%s@ %*p (unknown)\n", prefix,
92
+ kPrintfPointerFieldWidth, pc);
93
+ } else {
94
+ snprintf(buf, sizeof(buf), "%s@ %*p %9d\n", prefix,
95
+ kPrintfPointerFieldWidth, pc, framesize);
96
+ }
97
+ writer(buf, writer_arg);
98
+ }
99
+
100
+ // Print a program counter and the corresponding symbol.
101
+ void DumpPCAndSymbol(OutputWriter* writer, void* writer_arg, void* const pc,
102
+ const char* const prefix) {
103
+ char tmp[1024];
104
+ const char* symbol = "(unknown)";
105
+ // Symbolizes the previous address of pc because pc may be in the
106
+ // next function. The overrun happens when the function ends with
107
+ // a call to a function annotated noreturn (e.g. CHECK).
108
+ // If symbolization of pc-1 fails, also try pc on the off-chance
109
+ // that we crashed on the first instruction of a function (that
110
+ // actually happens very often for e.g. __restore_rt).
111
+ const uintptr_t prev_pc = reinterpret_cast<uintptr_t>(pc) - 1;
112
+ if (absl::Symbolize(reinterpret_cast<const char*>(prev_pc), tmp,
113
+ sizeof(tmp)) ||
114
+ absl::Symbolize(pc, tmp, sizeof(tmp))) {
115
+ symbol = tmp;
116
+ }
117
+ char buf[1024];
118
+ snprintf(buf, sizeof(buf), "%s@ %*p %s\n", prefix, kPrintfPointerFieldWidth,
119
+ pc, symbol);
120
+ writer(buf, writer_arg);
121
+ }
122
+
123
+ // Print a program counter, its stack frame size, and its symbol name.
124
+ // Note that there is a separate symbolize_pc argument. Return addresses may be
125
+ // at the end of the function, and this allows the caller to back up from pc if
126
+ // appropriate.
127
+ void DumpPCAndFrameSizeAndSymbol(OutputWriter* writer, void* writer_arg,
128
+ void* const pc, void* const symbolize_pc,
129
+ int framesize, const char* const prefix) {
130
+ char tmp[1024];
131
+ const char* symbol = "(unknown)";
132
+ if (absl::Symbolize(symbolize_pc, tmp, sizeof(tmp))) {
133
+ symbol = tmp;
134
+ }
135
+ char buf[1024];
136
+ if (framesize <= 0) {
137
+ snprintf(buf, sizeof(buf), "%s@ %*p (unknown) %s\n", prefix,
138
+ kPrintfPointerFieldWidth, pc, symbol);
139
+ } else {
140
+ snprintf(buf, sizeof(buf), "%s@ %*p %9d %s\n", prefix,
141
+ kPrintfPointerFieldWidth, pc, framesize, symbol);
142
+ }
143
+ writer(buf, writer_arg);
144
+ }
145
+
146
+ } // namespace
147
+
148
+ void RegisterDebugStackTraceHook(SymbolizeUrlEmitter hook) {
149
+ debug_stack_trace_hook = hook;
150
+ }
151
+
152
+ SymbolizeUrlEmitter GetDebugStackTraceHook() { return debug_stack_trace_hook; }
153
+
154
+ // Returns the program counter from signal context, nullptr if
155
+ // unknown. vuc is a ucontext_t*. We use void* to avoid the use of
156
+ // ucontext_t on non-POSIX systems.
157
+ void* GetProgramCounter(void* const vuc) {
158
+ #ifdef __linux__
159
+ if (vuc != nullptr) {
160
+ ucontext_t* context = reinterpret_cast<ucontext_t*>(vuc);
161
+ #if defined(__aarch64__)
162
+ return reinterpret_cast<void*>(context->uc_mcontext.pc);
163
+ #elif defined(__alpha__)
164
+ return reinterpret_cast<void*>(context->uc_mcontext.sc_pc);
165
+ #elif defined(__arm__)
166
+ return reinterpret_cast<void*>(context->uc_mcontext.arm_pc);
167
+ #elif defined(__hppa__)
168
+ return reinterpret_cast<void*>(context->uc_mcontext.sc_iaoq[0]);
169
+ #elif defined(__i386__)
170
+ if (14 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs))
171
+ return reinterpret_cast<void*>(context->uc_mcontext.gregs[14]);
172
+ #elif defined(__ia64__)
173
+ return reinterpret_cast<void*>(context->uc_mcontext.sc_ip);
174
+ #elif defined(__m68k__)
175
+ return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]);
176
+ #elif defined(__mips__)
177
+ return reinterpret_cast<void*>(context->uc_mcontext.pc);
178
+ #elif defined(__powerpc64__)
179
+ return reinterpret_cast<void*>(context->uc_mcontext.gp_regs[32]);
180
+ #elif defined(__powerpc__)
181
+ return reinterpret_cast<void*>(context->uc_mcontext.uc_regs->gregs[32]);
182
+ #elif defined(__riscv)
183
+ return reinterpret_cast<void*>(context->uc_mcontext.__gregs[REG_PC]);
184
+ #elif defined(__s390__) && !defined(__s390x__)
185
+ return reinterpret_cast<void*>(context->uc_mcontext.psw.addr & 0x7fffffff);
186
+ #elif defined(__s390__) && defined(__s390x__)
187
+ return reinterpret_cast<void*>(context->uc_mcontext.psw.addr);
188
+ #elif defined(__sh__)
189
+ return reinterpret_cast<void*>(context->uc_mcontext.pc);
190
+ #elif defined(__sparc__) && !defined(__arch64__)
191
+ return reinterpret_cast<void*>(context->uc_mcontext.gregs[19]);
192
+ #elif defined(__sparc__) && defined(__arch64__)
193
+ return reinterpret_cast<void*>(context->uc_mcontext.mc_gregs[19]);
194
+ #elif defined(__x86_64__)
195
+ if (16 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs))
196
+ return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]);
197
+ #elif defined(__e2k__)
198
+ return reinterpret_cast<void*>(context->uc_mcontext.cr0_hi);
199
+ #elif defined(__loongarch__)
200
+ return reinterpret_cast<void*>(context->uc_mcontext.__pc);
201
+ #else
202
+ #error "Undefined Architecture."
203
+ #endif
204
+ }
205
+ #elif defined(__APPLE__)
206
+ if (vuc != nullptr) {
207
+ ucontext_t* signal_ucontext = reinterpret_cast<ucontext_t*>(vuc);
208
+ #if defined(__aarch64__)
209
+ return reinterpret_cast<void*>(
210
+ __darwin_arm_thread_state64_get_pc(signal_ucontext->uc_mcontext->__ss));
211
+ #elif defined(__arm__)
212
+ #if __DARWIN_UNIX03
213
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__pc);
214
+ #else
215
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.pc);
216
+ #endif
217
+ #elif defined(__i386__)
218
+ #if __DARWIN_UNIX03
219
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__eip);
220
+ #else
221
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.eip);
222
+ #endif
223
+ #elif defined(__x86_64__)
224
+ #if __DARWIN_UNIX03
225
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__rip);
226
+ #else
227
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.rip);
228
+ #endif
229
+ #endif
230
+ }
231
+ #elif defined(__akaros__)
232
+ auto* ctx = reinterpret_cast<struct user_context*>(vuc);
233
+ return reinterpret_cast<void*>(get_user_ctx_pc(ctx));
234
+ #endif
235
+ static_cast<void>(vuc);
236
+ return nullptr;
237
+ }
238
+
239
+ void DumpPCAndFrameSizesAndStackTrace(void* const pc, void* const stack[],
240
+ int frame_sizes[], int depth,
241
+ int min_dropped_frames,
242
+ bool symbolize_stacktrace,
243
+ OutputWriter* writer, void* writer_arg) {
244
+ if (pc != nullptr) {
245
+ // We don't know the stack frame size for PC, use 0.
246
+ if (symbolize_stacktrace) {
247
+ DumpPCAndFrameSizeAndSymbol(writer, writer_arg, pc, pc, 0, "PC: ");
248
+ } else {
249
+ DumpPCAndFrameSize(writer, writer_arg, pc, 0, "PC: ");
250
+ }
251
+ }
252
+ for (int i = 0; i < depth; i++) {
253
+ if (symbolize_stacktrace) {
254
+ // Pass the previous address of pc as the symbol address because pc is a
255
+ // return address, and an overrun may occur when the function ends with a
256
+ // call to a function annotated noreturn (e.g. CHECK). Note that we don't
257
+ // do this for pc above, as the adjustment is only correct for return
258
+ // addresses.
259
+ DumpPCAndFrameSizeAndSymbol(writer, writer_arg, stack[i],
260
+ reinterpret_cast<char*>(stack[i]) - 1,
261
+ frame_sizes[i], " ");
262
+ } else {
263
+ DumpPCAndFrameSize(writer, writer_arg, stack[i], frame_sizes[i], " ");
264
+ }
265
+ }
266
+ if (min_dropped_frames > 0) {
267
+ char buf[100];
268
+ snprintf(buf, sizeof(buf), " @ ... and at least %d more frames\n",
269
+ min_dropped_frames);
270
+ writer(buf, writer_arg);
271
+ }
272
+ }
273
+
274
+ // Dump current stack trace as directed by writer.
275
+ // Make sure this function is not inlined to avoid skipping too many top frames.
276
+ ABSL_ATTRIBUTE_NOINLINE
277
+ void DumpStackTrace(int min_dropped_frames, int max_num_frames,
278
+ bool symbolize_stacktrace, OutputWriter* writer,
279
+ void* writer_arg) {
280
+ // Print stack trace
281
+ void* stack_buf[kDefaultDumpStackFramesLimit];
282
+ void** stack = stack_buf;
283
+ int num_stack = kDefaultDumpStackFramesLimit;
284
+ size_t allocated_bytes = 0;
285
+
286
+ if (num_stack >= max_num_frames) {
287
+ // User requested fewer frames than we already have space for.
288
+ num_stack = max_num_frames;
289
+ } else {
290
+ const size_t needed_bytes =
291
+ static_cast<size_t>(max_num_frames) * sizeof(stack[0]);
292
+ void* p = Allocate(needed_bytes);
293
+ if (p != nullptr) { // We got the space.
294
+ num_stack = max_num_frames;
295
+ stack = reinterpret_cast<void**>(p);
296
+ allocated_bytes = needed_bytes;
297
+ }
298
+ }
299
+
300
+ int depth = absl::GetStackTrace(stack, num_stack, min_dropped_frames + 1);
301
+ for (int i = 0; i < depth; i++) {
302
+ if (symbolize_stacktrace) {
303
+ DumpPCAndSymbol(writer, writer_arg, stack[static_cast<size_t>(i)],
304
+ " ");
305
+ } else {
306
+ DumpPC(writer, writer_arg, stack[static_cast<size_t>(i)], " ");
307
+ }
308
+ }
309
+
310
+ auto hook = GetDebugStackTraceHook();
311
+ if (hook != nullptr) {
312
+ (*hook)(stack, depth, writer, writer_arg);
313
+ }
314
+
315
+ if (allocated_bytes != 0) Deallocate(stack, allocated_bytes);
316
+ }
317
+
318
+ } // namespace debugging_internal
319
+ ABSL_NAMESPACE_END
320
+ } // namespace absl
weight/_dep/abseil-cpp/absl/debugging/internal/examine_stack.h ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Copyright 2018 The Abseil Authors.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // https://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ //
16
+
17
+ #ifndef ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
18
+ #define ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
19
+
20
+ #include "absl/base/config.h"
21
+
22
+ namespace absl {
23
+ ABSL_NAMESPACE_BEGIN
24
+ namespace debugging_internal {
25
+
26
+ // Type of function used for printing in stack trace dumping, etc.
27
+ // We avoid closures to keep things simple.
28
+ typedef void OutputWriter(const char*, void*);
29
+
30
+ // RegisterDebugStackTraceHook() allows to register a single routine
31
+ // `hook` that is called each time DumpStackTrace() is called.
32
+ // `hook` may be called from a signal handler.
33
+ typedef void (*SymbolizeUrlEmitter)(void* const stack[], int depth,
34
+ OutputWriter* writer, void* writer_arg);
35
+
36
+ // Registration of SymbolizeUrlEmitter for use inside of a signal handler.
37
+ // This is inherently unsafe and must be signal safe code.
38
+ void RegisterDebugStackTraceHook(SymbolizeUrlEmitter hook);
39
+ SymbolizeUrlEmitter GetDebugStackTraceHook();
40
+
41
+ // Returns the program counter from signal context, or nullptr if
42
+ // unknown. `vuc` is a ucontext_t*. We use void* to avoid the use of
43
+ // ucontext_t on non-POSIX systems.
44
+ void* GetProgramCounter(void* const vuc);
45
+
46
+ // Uses `writer` to dump the program counter, stack trace, and stack
47
+ // frame sizes.
48
+ void DumpPCAndFrameSizesAndStackTrace(void* const pc, void* const stack[],
49
+ int frame_sizes[], int depth,
50
+ int min_dropped_frames,
51
+ bool symbolize_stacktrace,
52
+ OutputWriter* writer, void* writer_arg);
53
+
54
+ // Dump current stack trace omitting the topmost `min_dropped_frames` stack
55
+ // frames.
56
+ void DumpStackTrace(int min_dropped_frames, int max_num_frames,
57
+ bool symbolize_stacktrace, OutputWriter* writer,
58
+ void* writer_arg);
59
+
60
+ } // namespace debugging_internal
61
+ ABSL_NAMESPACE_END
62
+ } // namespace absl
63
+
64
+ #endif // ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
weight/_dep/abseil-cpp/absl/debugging/internal/stack_consumption.cc ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Copyright 2018 The Abseil Authors.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // https://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+
16
+ #include "absl/debugging/internal/stack_consumption.h"
17
+
18
+ #ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
19
+
20
+ #include <signal.h>
21
+ #include <string.h>
22
+ #include <sys/mman.h>
23
+ #include <unistd.h>
24
+
25
+ #include "absl/base/attributes.h"
26
+ #include "absl/base/internal/raw_logging.h"
27
+
28
+ #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
29
+ #define MAP_ANONYMOUS MAP_ANON
30
+ #endif
31
+
32
+ namespace absl {
33
+ ABSL_NAMESPACE_BEGIN
34
+ namespace debugging_internal {
35
+ namespace {
36
+
37
+ // This code requires that we know the direction in which the stack
38
+ // grows. It is commonly believed that this can be detected by putting
39
+ // a variable on the stack and then passing its address to a function
40
+ // that compares the address of this variable to the address of a
41
+ // variable on the function's own stack. However, this is unspecified
42
+ // behavior in C++: If two pointers p and q of the same type point to
43
+ // different objects that are not members of the same object or
44
+ // elements of the same array or to different functions, or if only
45
+ // one of them is null, the results of p<q, p>q, p<=q, and p>=q are
46
+ // unspecified. Therefore, instead we hardcode the direction of the
47
+ // stack on platforms we know about.
48
+ #if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \
49
+ defined(__aarch64__) || defined(__riscv)
50
+ constexpr bool kStackGrowsDown = true;
51
+ #else
52
+ #error Need to define kStackGrowsDown
53
+ #endif
54
+
55
+ // To measure the stack footprint of some code, we create a signal handler
56
+ // (for SIGUSR2 say) that exercises this code on an alternate stack. This
57
+ // alternate stack is initialized to some known pattern (0x55, 0x55, 0x55,
58
+ // ...). We then self-send this signal, and after the signal handler returns,
59
+ // look at the alternate stack buffer to see what portion has been touched.
60
+ //
61
+ // This trick gives us the the stack footprint of the signal handler. But the
62
+ // signal handler, even before the code for it is exercised, consumes some
63
+ // stack already. We however only want the stack usage of the code inside the
64
+ // signal handler. To measure this accurately, we install two signal handlers:
65
+ // one that does nothing and just returns, and the user-provided signal
66
+ // handler. The difference between the stack consumption of these two signals
67
+ // handlers should give us the stack foorprint of interest.
68
+
69
+ void EmptySignalHandler(int) {}
70
+
71
+ // This is arbitrary value, and could be increase further, at the cost of
72
+ // memset()ting it all to known sentinel value.
73
+ constexpr int kAlternateStackSize = 64 << 10; // 64KiB
74
+
75
+ constexpr int kSafetyMargin = 32;
76
+ constexpr char kAlternateStackFillValue = 0x55;
77
+
78
+ // These helper functions look at the alternate stack buffer, and figure
79
+ // out what portion of this buffer has been touched - this is the stack
80
+ // consumption of the signal handler running on this alternate stack.
81
+ // This function will return -1 if the alternate stack buffer has not been
82
+ // touched. It will abort the program if the buffer has overflowed or is about
83
+ // to overflow.
84
+ int GetStackConsumption(const void* const altstack) {
85
+ const char* begin;
86
+ int increment;
87
+ if (kStackGrowsDown) {
88
+ begin = reinterpret_cast<const char*>(altstack);
89
+ increment = 1;
90
+ } else {
91
+ begin = reinterpret_cast<const char*>(altstack) + kAlternateStackSize - 1;
92
+ increment = -1;
93
+ }
94
+
95
+ for (int usage_count = kAlternateStackSize; usage_count > 0; --usage_count) {
96
+ if (*begin != kAlternateStackFillValue) {
97
+ ABSL_RAW_CHECK(usage_count <= kAlternateStackSize - kSafetyMargin,
98
+ "Buffer has overflowed or is about to overflow");
99
+ return usage_count;
100
+ }
101
+ begin += increment;
102
+ }
103
+
104
+ ABSL_RAW_LOG(FATAL, "Unreachable code");
105
+ return -1;
106
+ }
107
+
108
+ } // namespace
109
+
110
+ int GetSignalHandlerStackConsumption(void (*signal_handler)(int)) {
111
+ // The alt-signal-stack cannot be heap allocated because there is a
112
+ // bug in glibc-2.2 where some signal handler setup code looks at the
113
+ // current stack pointer to figure out what thread is currently running.
114
+ // Therefore, the alternate stack must be allocated from the main stack
115
+ // itself.
116
+ void* altstack = mmap(nullptr, kAlternateStackSize, PROT_READ | PROT_WRITE,
117
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
118
+ ABSL_RAW_CHECK(altstack != MAP_FAILED, "mmap() failed");
119
+
120
+ // Set up the alt-signal-stack (and save the older one).
121
+ stack_t sigstk;
122
+ memset(&sigstk, 0, sizeof(sigstk));
123
+ sigstk.ss_sp = altstack;
124
+ sigstk.ss_size = kAlternateStackSize;
125
+ sigstk.ss_flags = 0;
126
+ stack_t old_sigstk;
127
+ memset(&old_sigstk, 0, sizeof(old_sigstk));
128
+ ABSL_RAW_CHECK(sigaltstack(&sigstk, &old_sigstk) == 0,
129
+ "sigaltstack() failed");
130
+
131
+ // Set up SIGUSR1 and SIGUSR2 signal handlers (and save the older ones).
132
+ struct sigaction sa;
133
+ memset(&sa, 0, sizeof(sa));
134
+ struct sigaction old_sa1, old_sa2;
135
+ sigemptyset(&sa.sa_mask);
136
+ sa.sa_flags = SA_ONSTACK;
137
+
138
+ // SIGUSR1 maps to EmptySignalHandler.
139
+ sa.sa_handler = EmptySignalHandler;
140
+ ABSL_RAW_CHECK(sigaction(SIGUSR1, &sa, &old_sa1) == 0, "sigaction() failed");
141
+
142
+ // SIGUSR2 maps to signal_handler.
143
+ sa.sa_handler = signal_handler;
144
+ ABSL_RAW_CHECK(sigaction(SIGUSR2, &sa, &old_sa2) == 0, "sigaction() failed");
145
+
146
+ // Send SIGUSR1 signal and measure the stack consumption of the empty
147
+ // signal handler.
148
+ // The first signal might use more stack space. Run once and ignore the
149
+ // results to get that out of the way.
150
+ ABSL_RAW_CHECK(kill(getpid(), SIGUSR1) == 0, "kill() failed");
151
+
152
+ memset(altstack, kAlternateStackFillValue, kAlternateStackSize);
153
+ ABSL_RAW_CHECK(kill(getpid(), SIGUSR1) == 0, "kill() failed");
154
+ int base_stack_consumption = GetStackConsumption(altstack);
155
+
156
+ // Send SIGUSR2 signal and measure the stack consumption of signal_handler.
157
+ ABSL_RAW_CHECK(kill(getpid(), SIGUSR2) == 0, "kill() failed");
158
+ int signal_handler_stack_consumption = GetStackConsumption(altstack);
159
+
160
+ // Now restore the old alt-signal-stack and signal handlers.
161
+ if (old_sigstk.ss_sp == nullptr && old_sigstk.ss_size == 0 &&
162
+ (old_sigstk.ss_flags & SS_DISABLE)) {
163
+ // https://git.musl-libc.org/cgit/musl/commit/src/signal/sigaltstack.c?id=7829f42a2c8944555439380498ab8b924d0f2070
164
+ // The original stack has ss_size==0 and ss_flags==SS_DISABLE, but some
165
+ // versions of musl have a bug that rejects ss_size==0. Work around this by
166
+ // setting ss_size to MINSIGSTKSZ, which should be ignored by the kernel
167
+ // when SS_DISABLE is set.
168
+ old_sigstk.ss_size = static_cast<size_t>(MINSIGSTKSZ);
169
+ }
170
+ ABSL_RAW_CHECK(sigaltstack(&old_sigstk, nullptr) == 0,
171
+ "sigaltstack() failed");
172
+ ABSL_RAW_CHECK(sigaction(SIGUSR1, &old_sa1, nullptr) == 0,
173
+ "sigaction() failed");
174
+ ABSL_RAW_CHECK(sigaction(SIGUSR2, &old_sa2, nullptr) == 0,
175
+ "sigaction() failed");
176
+
177
+ ABSL_RAW_CHECK(munmap(altstack, kAlternateStackSize) == 0, "munmap() failed");
178
+ if (signal_handler_stack_consumption != -1 && base_stack_consumption != -1) {
179
+ return signal_handler_stack_consumption - base_stack_consumption;
180
+ }
181
+ return -1;
182
+ }
183
+
184
+ } // namespace debugging_internal
185
+ ABSL_NAMESPACE_END
186
+ } // namespace absl
187
+
188
+ #else
189
+
190
+ // https://github.com/abseil/abseil-cpp/issues/1465
191
+ // CMake builds on Apple platforms error when libraries are empty.
192
+ // Our CMake configuration can avoid this error on header-only libraries,
193
+ // but since this library is conditionally empty, including a single
194
+ // variable is an easy workaround.
195
+ #ifdef __APPLE__
196
+ namespace absl {
197
+ ABSL_NAMESPACE_BEGIN
198
+ namespace debugging_internal {
199
+ extern const char kAvoidEmptyStackConsumptionLibraryWarning;
200
+ const char kAvoidEmptyStackConsumptionLibraryWarning = 0;
201
+ } // namespace debugging_internal
202
+ ABSL_NAMESPACE_END
203
+ } // namespace absl
204
+ #endif // __APPLE__
205
+
206
+ #endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
weight/_dep/abseil-cpp/absl/debugging/internal/stack_consumption.h ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Copyright 2018 The Abseil Authors.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // https://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+
16
+ // Helper function for measuring stack consumption of signal handlers.
17
+
18
+ #ifndef ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_
19
+ #define ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_
20
+
21
+ #include "absl/base/config.h"
22
+
23
+ // The code in this module is not portable.
24
+ // Use this feature test macro to detect its availability.
25
+ #ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
26
+ #error ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION cannot be set directly
27
+ #elif !defined(__APPLE__) && !defined(_WIN32) && \
28
+ (defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \
29
+ defined(__aarch64__) || defined(__riscv))
30
+ #define ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION 1
31
+
32
+ namespace absl {
33
+ ABSL_NAMESPACE_BEGIN
34
+ namespace debugging_internal {
35
+
36
+ // Returns the stack consumption in bytes for the code exercised by
37
+ // signal_handler. To measure stack consumption, signal_handler is registered
38
+ // as a signal handler, so the code that it exercises must be async-signal
39
+ // safe. The argument of signal_handler is an implementation detail of signal
40
+ // handlers and should ignored by the code for signal_handler. Use global
41
+ // variables to pass information between your test code and signal_handler.
42
+ int GetSignalHandlerStackConsumption(void (*signal_handler)(int));
43
+
44
+ } // namespace debugging_internal
45
+ ABSL_NAMESPACE_END
46
+ } // namespace absl
47
+
48
+ #endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
49
+
50
+ #endif // ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_