enumset: add iterator based constructor/insert (#5344)

Expanding a bit the EnumSet API to have iterator-based
insert and constructors (like the STL).
This is also a pre-requisite from the capability-trimming pass as
it allows to build a const set from a constexpr std::array easily.

Signed-off-by: Nathan Gauër <brioche@google.com>
This commit is contained in:
Nathan Gauër 2023-07-20 19:54:50 +02:00 committed by GitHub
parent daad2295c9
commit 17d9669d51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 20 deletions

View File

@ -204,6 +204,14 @@ class EnumSet {
}
}
// Creates a set initialized with the content of the range [begin; end[.
template <class InputIt>
EnumSet(InputIt begin, InputIt end) : EnumSet() {
for (; begin != end; ++begin) {
insert(*begin);
}
}
// Copies the EnumSet `other` into a new EnumSet.
EnumSet(const EnumSet& other)
: buckets_(other.buckets_), size_(other.size_) {}
@ -256,6 +264,15 @@ class EnumSet {
// insertion.
iterator insert(const_iterator, T&& value) { return insert(value).first; }
// Inserts all the values in the range [`first`; `last[.
// Similar to `std::unordered_set::insert`.
template <class InputIt>
void insert(InputIt first, InputIt last) {
for (auto it = first; it != last; ++it) {
insert(*it);
}
}
// Removes the value `value` into the set.
// Similar to `std::unordered_set::erase`.
// Returns the number of erased elements.

View File

@ -286,6 +286,30 @@ constexpr std::array kCapabilities{
spv::Capability::Max,
};
namespace {
std::vector<TestEnum> enumerateValuesFromToWithStep(size_t start, size_t end,
size_t step) {
assert(end > start && "end > start");
std::vector<TestEnum> orderedValues;
for (size_t i = start; i < end; i += step) {
orderedValues.push_back(static_cast<TestEnum>(i));
}
return orderedValues;
}
EnumSet<TestEnum> createSetUnorderedInsertion(
const std::vector<TestEnum>& values) {
std::vector shuffledValues(values.cbegin(), values.cend());
std::mt19937 rng(0);
std::shuffle(shuffledValues.begin(), shuffledValues.end(), rng);
EnumSet<TestEnum> set;
for (auto value : shuffledValues) {
set.insert(value);
}
return set;
}
} // namespace
TEST(EnumSet, IsEmpty1) {
EnumSet<TestEnum> set;
EXPECT_TRUE(set.empty());
@ -439,29 +463,58 @@ TEST(EnumSet, DefaultIsEmpty) {
}
}
namespace {
std::vector<TestEnum> enumerateValuesFromToWithStep(size_t start, size_t end,
size_t step) {
assert(end > start && "end > start");
std::vector<TestEnum> orderedValues;
for (size_t i = start; i < end; i += step) {
orderedValues.push_back(static_cast<TestEnum>(i));
}
return orderedValues;
TEST(EnumSet, EqualityCompareEmpty) {
EnumSet<TestEnum> set1;
EnumSet<TestEnum> set2;
EXPECT_TRUE(set1 == set2);
EXPECT_FALSE(set1 != set2);
}
EnumSet<TestEnum> createSetUnorderedInsertion(
const std::vector<TestEnum>& values) {
std::vector shuffledValues(values.cbegin(), values.cend());
std::mt19937 rng(0);
std::shuffle(shuffledValues.begin(), shuffledValues.end(), rng);
EnumSet<TestEnum> set;
for (auto value : shuffledValues) {
set.insert(value);
}
return set;
TEST(EnumSet, EqualityCompareSame) {
EnumSet<TestEnum> set1;
EnumSet<TestEnum> set2;
set1.insert(TestEnum::ONE);
set1.insert(TestEnum::TWENTY);
set2.insert(TestEnum::TWENTY);
set2.insert(TestEnum::ONE);
EXPECT_TRUE(set1 == set2);
EXPECT_FALSE(set1 != set2);
}
TEST(EnumSet, EqualityCompareDifferent) {
EnumSet<TestEnum> set1;
EnumSet<TestEnum> set2;
set1.insert(TestEnum::ONE);
set1.insert(TestEnum::TWENTY);
set2.insert(TestEnum::FIVE);
set2.insert(TestEnum::ONE);
EXPECT_FALSE(set1 == set2);
EXPECT_TRUE(set1 != set2);
}
TEST(EnumSet, ConstructFromIterators) {
auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1);
EnumSet<TestEnum> set1 = createSetUnorderedInsertion(orderedValues);
EnumSet<TestEnum> set2(orderedValues.cbegin(), orderedValues.cend());
EXPECT_EQ(set1, set2);
}
TEST(EnumSet, InsertUsingIteratorRange) {
auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1);
EnumSet<TestEnum> set1 = createSetUnorderedInsertion(orderedValues);
EnumSet<TestEnum> set2;
set2.insert(orderedValues.cbegin(), orderedValues.cend());
EXPECT_EQ(set1, set2);
}
} // namespace
TEST(CapabilitySet, RangeBasedLoopOrderIsEnumOrder) {
auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1);