Skip to content

Commit 9d51fa7

Browse files
goldvitalycopybara-github
authored andcommitted
Add Group::MaskFullOrSentinel implementation without usage.
It is intended to be used for optimization experiments for iteration. PiperOrigin-RevId: 761692460 Change-Id: Ia642e2f3a627ee24d4a09ef2edb8948d49206699
1 parent 4e94319 commit 9d51fa7

File tree

2 files changed

+108
-51
lines changed

2 files changed

+108
-51
lines changed

absl/container/internal/hashtable_control_bytes.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,15 @@ struct GroupSse2Impl {
324324
_mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl))));
325325
}
326326

327+
// Returns a bitmask representing the positions of full or sentinel slots.
328+
// Note: for `is_small()` tables group may contain the "same" slot twice:
329+
// original and mirrored.
330+
NonIterableBitMaskType MaskFullOrSentinel() const {
331+
auto special = _mm_set1_epi8(static_cast<char>(ctrl_t::kSentinel) - 1);
332+
return NonIterableBitMaskType(static_cast<uint16_t>(
333+
_mm_movemask_epi8(_mm_cmpgt_epi8_fixed(ctrl, special))));
334+
}
335+
327336
// Returns the number of trailing empty or deleted elements in the group.
328337
uint32_t CountLeadingEmptyOrDeleted() const {
329338
auto special = _mm_set1_epi8(static_cast<char>(ctrl_t::kSentinel));
@@ -406,6 +415,15 @@ struct GroupAArch64Impl {
406415
return NonIterableBitMaskType(mask);
407416
}
408417

418+
NonIterableBitMaskType MaskFullOrSentinel() const {
419+
uint64_t mask = vget_lane_u64(
420+
vreinterpret_u64_u8(
421+
vcgt_s8(vreinterpret_s8_u8(ctrl),
422+
vdup_n_s8(static_cast<int8_t>(ctrl_t::kSentinel) - 1))),
423+
0);
424+
return NonIterableBitMaskType(mask);
425+
}
426+
409427
uint32_t CountLeadingEmptyOrDeleted() const {
410428
uint64_t mask =
411429
vget_lane_u64(vreinterpret_u64_u8(vcle_s8(
@@ -481,6 +499,10 @@ struct GroupPortableImpl {
481499
return NonIterableBitMaskType((ctrl & ~(ctrl << 7)) & kMsbs8Bytes);
482500
}
483501

502+
auto MaskFullOrSentinel() const {
503+
return NonIterableBitMaskType((~ctrl | (ctrl << 7)) & kMsbs8Bytes);
504+
}
505+
484506
uint32_t CountLeadingEmptyOrDeleted() const {
485507
// ctrl | ~(ctrl >> 7) will have the lowest bit set to zero for kEmpty and
486508
// kDeleted. We lower all other bits and count number of trailing zeros.

absl/container/internal/hashtable_control_bytes_test.cc

Lines changed: 86 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -127,125 +127,160 @@ TEST(BitMask, LeadingTrailing) {
127127
EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x8000000000000000).TrailingZeros()), 7);
128128
}
129129

130-
TEST(Group, Match) {
131-
if (Group::kWidth == 16) {
130+
template <class GroupTypeParam>
131+
class GroupTest : public testing::Test {};
132+
using GroupTypes =
133+
::testing::Types<Group, GroupPortableImpl, GroupFullEmptyOrDeleted>;
134+
TYPED_TEST_SUITE(GroupTest, GroupTypes);
135+
136+
TYPED_TEST(GroupTest, Match) {
137+
using GroupType = TypeParam;
138+
if (GroupType::kWidth == 16) {
132139
ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3),
133140
ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
134141
CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1),
135142
CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)};
136-
EXPECT_THAT(Group{group}.Match(0), ElementsAre());
137-
EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15));
138-
EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10));
139-
EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9));
140-
EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8));
141-
} else if (Group::kWidth == 8) {
143+
EXPECT_THAT(GroupType{group}.Match(0), ElementsAre());
144+
EXPECT_THAT(GroupType{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15));
145+
EXPECT_THAT(GroupType{group}.Match(3), ElementsAre(3, 10));
146+
EXPECT_THAT(GroupType{group}.Match(5), ElementsAre(5, 9));
147+
EXPECT_THAT(GroupType{group}.Match(7), ElementsAre(7, 8));
148+
} else if (GroupType::kWidth == 8) {
142149
ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2),
143150
ctrl_t::kDeleted, CtrlT(2), CtrlT(1),
144151
ctrl_t::kSentinel, CtrlT(1)};
145-
EXPECT_THAT(Group{group}.Match(0), ElementsAre());
146-
EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7));
147-
EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4));
152+
EXPECT_THAT(GroupType{group}.Match(0), ElementsAre());
153+
EXPECT_THAT(GroupType{group}.Match(1), ElementsAre(1, 5, 7));
154+
EXPECT_THAT(GroupType{group}.Match(2), ElementsAre(2, 4));
148155
} else {
149-
FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
156+
FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
150157
}
151158
}
152159

153-
TEST(Group, MaskEmpty) {
154-
if (Group::kWidth == 16) {
160+
TYPED_TEST(GroupTest, MaskEmpty) {
161+
using GroupType = TypeParam;
162+
if (GroupType::kWidth == 16) {
155163
ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3),
156164
ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
157165
CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1),
158166
CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)};
159-
EXPECT_THAT(Group{group}.MaskEmpty().LowestBitSet(), 0);
160-
EXPECT_THAT(Group{group}.MaskEmpty().HighestBitSet(), 4);
161-
} else if (Group::kWidth == 8) {
167+
EXPECT_THAT(GroupType{group}.MaskEmpty().LowestBitSet(), 0);
168+
EXPECT_THAT(GroupType{group}.MaskEmpty().HighestBitSet(), 4);
169+
} else if (GroupType::kWidth == 8) {
162170
ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2),
163171
ctrl_t::kDeleted, CtrlT(2), CtrlT(1),
164172
ctrl_t::kSentinel, CtrlT(1)};
165-
EXPECT_THAT(Group{group}.MaskEmpty().LowestBitSet(), 0);
166-
EXPECT_THAT(Group{group}.MaskEmpty().HighestBitSet(), 0);
173+
EXPECT_THAT(GroupType{group}.MaskEmpty().LowestBitSet(), 0);
174+
EXPECT_THAT(GroupType{group}.MaskEmpty().HighestBitSet(), 0);
167175
} else {
168-
FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
176+
FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
169177
}
170178
}
171179

172-
TEST(Group, MaskFull) {
173-
if (Group::kWidth == 16) {
180+
TYPED_TEST(GroupTest, MaskFull) {
181+
using GroupType = TypeParam;
182+
if (GroupType::kWidth == 16) {
174183
ctrl_t group[] = {
175184
ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3),
176185
ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
177186
CtrlT(7), CtrlT(5), ctrl_t::kDeleted, CtrlT(1),
178187
CtrlT(1), ctrl_t::kSentinel, ctrl_t::kEmpty, CtrlT(1)};
179-
EXPECT_THAT(Group{group}.MaskFull(),
188+
EXPECT_THAT(GroupType{group}.MaskFull(),
180189
ElementsAre(1, 3, 5, 7, 8, 9, 11, 12, 15));
181-
} else if (Group::kWidth == 8) {
190+
} else if (GroupType::kWidth == 8) {
182191
ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kEmpty,
183192
ctrl_t::kDeleted, CtrlT(2), ctrl_t::kSentinel,
184193
ctrl_t::kSentinel, CtrlT(1)};
185-
EXPECT_THAT(Group{group}.MaskFull(), ElementsAre(1, 4, 7));
194+
EXPECT_THAT(GroupType{group}.MaskFull(), ElementsAre(1, 4, 7));
186195
} else {
187-
FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
196+
FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
188197
}
189198
}
190199

191-
TEST(Group, MaskNonFull) {
192-
if (Group::kWidth == 16) {
200+
TYPED_TEST(GroupTest, MaskNonFull) {
201+
using GroupType = TypeParam;
202+
if (GroupType::kWidth == 16) {
193203
ctrl_t group[] = {
194204
ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3),
195205
ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
196206
CtrlT(7), CtrlT(5), ctrl_t::kDeleted, CtrlT(1),
197207
CtrlT(1), ctrl_t::kSentinel, ctrl_t::kEmpty, CtrlT(1)};
198-
EXPECT_THAT(Group{group}.MaskNonFull(),
208+
EXPECT_THAT(GroupType{group}.MaskNonFull(),
199209
ElementsAre(0, 2, 4, 6, 10, 13, 14));
200-
} else if (Group::kWidth == 8) {
210+
} else if (GroupType::kWidth == 8) {
201211
ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kEmpty,
202212
ctrl_t::kDeleted, CtrlT(2), ctrl_t::kSentinel,
203213
ctrl_t::kSentinel, CtrlT(1)};
204-
EXPECT_THAT(Group{group}.MaskNonFull(), ElementsAre(0, 2, 3, 5, 6));
214+
EXPECT_THAT(GroupType{group}.MaskNonFull(), ElementsAre(0, 2, 3, 5, 6));
205215
} else {
206-
FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
216+
FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
207217
}
208218
}
209219

210-
TEST(Group, MaskEmptyOrDeleted) {
211-
if (Group::kWidth == 16) {
220+
TYPED_TEST(GroupTest, MaskEmptyOrDeleted) {
221+
using GroupType = TypeParam;
222+
if (GroupType::kWidth == 16) {
212223
ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kEmpty, CtrlT(3),
213224
ctrl_t::kDeleted, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
214225
CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1),
215226
CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)};
216-
EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
217-
EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().HighestBitSet(), 4);
218-
} else if (Group::kWidth == 8) {
227+
EXPECT_THAT(GroupType{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
228+
EXPECT_THAT(GroupType{group}.MaskEmptyOrDeleted().HighestBitSet(), 4);
229+
} else if (GroupType::kWidth == 8) {
219230
ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2),
220231
ctrl_t::kDeleted, CtrlT(2), CtrlT(1),
221232
ctrl_t::kSentinel, CtrlT(1)};
222-
EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
223-
EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().HighestBitSet(), 3);
233+
EXPECT_THAT(GroupType{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
234+
EXPECT_THAT(GroupType{group}.MaskEmptyOrDeleted().HighestBitSet(), 3);
235+
} else {
236+
FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
237+
}
238+
}
239+
240+
TYPED_TEST(GroupTest, MaskFullOrSentinel) {
241+
using GroupType = TypeParam;
242+
if (GroupType::kWidth == 16) {
243+
ctrl_t group[] = {
244+
ctrl_t::kEmpty, ctrl_t::kDeleted, ctrl_t::kEmpty, CtrlT(3),
245+
ctrl_t::kDeleted, CtrlT(5), ctrl_t::kSentinel, ctrl_t::kEmpty,
246+
ctrl_t::kEmpty, ctrl_t::kDeleted, ctrl_t::kDeleted, ctrl_t::kDeleted,
247+
ctrl_t::kEmpty, ctrl_t::kDeleted, ctrl_t::kDeleted, ctrl_t::kDeleted,
248+
};
249+
EXPECT_THAT(GroupType{group}.MaskFullOrSentinel().LowestBitSet(), 3);
250+
EXPECT_THAT(GroupType{group}.MaskFullOrSentinel().HighestBitSet(), 6);
251+
} else if (GroupType::kWidth == 8) {
252+
ctrl_t group[] = {ctrl_t::kEmpty, ctrl_t::kDeleted, CtrlT(2),
253+
ctrl_t::kDeleted, CtrlT(2), ctrl_t::kSentinel,
254+
ctrl_t::kDeleted, ctrl_t::kEmpty};
255+
EXPECT_THAT(GroupType{group}.MaskFullOrSentinel().LowestBitSet(), 2);
256+
EXPECT_THAT(GroupType{group}.MaskFullOrSentinel().HighestBitSet(), 5);
224257
} else {
225-
FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
258+
FAIL() << "No test coverage for Group::kWidth==" << GroupType::kWidth;
226259
}
227260
}
228261

229-
TEST(Group, CountLeadingEmptyOrDeleted) {
262+
TYPED_TEST(GroupTest, CountLeadingEmptyOrDeleted) {
263+
using GroupType = TypeParam;
230264
const std::vector<ctrl_t> empty_examples = {ctrl_t::kEmpty, ctrl_t::kDeleted};
231265
const std::vector<ctrl_t> full_examples = {
232266
CtrlT(0), CtrlT(1), CtrlT(2), CtrlT(3),
233267
CtrlT(5), CtrlT(9), CtrlT(127), ctrl_t::kSentinel};
234268

235269
for (ctrl_t empty : empty_examples) {
236-
std::vector<ctrl_t> e(Group::kWidth, empty);
237-
EXPECT_EQ(Group::kWidth, Group{e.data()}.CountLeadingEmptyOrDeleted());
270+
std::vector<ctrl_t> e(GroupType::kWidth, empty);
271+
EXPECT_EQ(GroupType::kWidth,
272+
GroupType{e.data()}.CountLeadingEmptyOrDeleted());
238273
for (ctrl_t full : full_examples) {
239-
for (size_t i = 0; i != Group::kWidth; ++i) {
240-
std::vector<ctrl_t> f(Group::kWidth, empty);
274+
for (size_t i = 0; i != GroupType::kWidth; ++i) {
275+
std::vector<ctrl_t> f(GroupType::kWidth, empty);
241276
f[i] = full;
242-
EXPECT_EQ(i, Group{f.data()}.CountLeadingEmptyOrDeleted());
277+
EXPECT_EQ(i, GroupType{f.data()}.CountLeadingEmptyOrDeleted());
243278
}
244-
std::vector<ctrl_t> f(Group::kWidth, empty);
245-
f[Group::kWidth * 2 / 3] = full;
246-
f[Group::kWidth / 2] = full;
247-
EXPECT_EQ(Group::kWidth / 2,
248-
Group{f.data()}.CountLeadingEmptyOrDeleted());
279+
std::vector<ctrl_t> f(GroupType::kWidth, empty);
280+
f[GroupType::kWidth * 2 / 3] = full;
281+
f[GroupType::kWidth / 2] = full;
282+
EXPECT_EQ(GroupType::kWidth / 2,
283+
GroupType{f.data()}.CountLeadingEmptyOrDeleted());
249284
}
250285
}
251286
}

0 commit comments

Comments
 (0)