forked from OSchip/llvm-project
[ADT] Adds equality operators for DenseMap and DenseSet, and an initializer_list
constructor for DenseMap (DenseSet already had an initializer_list constructor). These changes make it easier to migrate existing code that uses std::map and std::set (which support initializer_list construction and equality comparison) to DenseMap and DenseSet. llvm-svn: 344522
This commit is contained in:
parent
397704ca40
commit
cb1f0cf54b
|
@ -25,6 +25,7 @@
|
|||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
|
@ -38,6 +39,9 @@ namespace detail {
|
|||
// implementation without requiring two members.
|
||||
template <typename KeyT, typename ValueT>
|
||||
struct DenseMapPair : public std::pair<KeyT, ValueT> {
|
||||
|
||||
using std::pair<KeyT, ValueT>::pair;
|
||||
|
||||
KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; }
|
||||
const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; }
|
||||
ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
|
||||
|
@ -640,6 +644,40 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// Equality comparison for DenseMap.
|
||||
///
|
||||
/// Iterates over elements of LHS confirming that each (key, value) pair in LHS
|
||||
/// is also in RHS, and that no additional pairs are in RHS.
|
||||
/// Equivalent to N calls to RHS.find and N value comparisons. Amortized
|
||||
/// complexity is linear, worst case is O(N^2) (if every hash collides).
|
||||
template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
|
||||
typename BucketT>
|
||||
bool operator==(
|
||||
const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
|
||||
const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
|
||||
if (LHS.size() != RHS.size())
|
||||
return false;
|
||||
|
||||
for (auto &KV : LHS) {
|
||||
auto I = RHS.find(KV.first);
|
||||
if (I == RHS.end() || I->second != KV.second)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Inequality comparison for DenseMap.
|
||||
///
|
||||
/// Equivalent to !(LHS == RHS). See operator== for performance notes.
|
||||
template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
|
||||
typename BucketT>
|
||||
bool operator!=(
|
||||
const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
|
||||
const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
template <typename KeyT, typename ValueT,
|
||||
typename KeyInfoT = DenseMapInfo<KeyT>,
|
||||
typename BucketT = llvm::detail::DenseMapPair<KeyT, ValueT>>
|
||||
|
@ -677,6 +715,11 @@ public:
|
|||
this->insert(I, E);
|
||||
}
|
||||
|
||||
DenseMap(std::initializer_list<typename BaseT::value_type> Vals) {
|
||||
init(Vals.size());
|
||||
this->insert(Vals.begin(), Vals.end());
|
||||
}
|
||||
|
||||
~DenseMap() {
|
||||
this->destroyAll();
|
||||
operator delete(Buckets);
|
||||
|
|
|
@ -214,6 +214,34 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// Equality comparison for DenseSet.
|
||||
///
|
||||
/// Iterates over elements of LHS confirming that each element is also a member
|
||||
/// of RHS, and that RHS contains no additional values.
|
||||
/// Equivalent to N calls to RHS.count. Amortized complexity is linear, worst
|
||||
/// case is O(N^2) (if every hash collides).
|
||||
template <typename ValueT, typename MapTy, typename ValueInfoT>
|
||||
bool operator==(const DenseSetImpl<ValueT, MapTy, ValueInfoT> &LHS,
|
||||
const DenseSetImpl<ValueT, MapTy, ValueInfoT> &RHS) {
|
||||
if (LHS.size() != RHS.size())
|
||||
return false;
|
||||
|
||||
for (auto &E : LHS)
|
||||
if (!RHS.count(E))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Inequality comparison for DenseSet.
|
||||
///
|
||||
/// Equivalent to !(LHS == RHS). See operator== for performance notes.
|
||||
template <typename ValueT, typename MapTy, typename ValueInfoT>
|
||||
bool operator!=(const DenseSetImpl<ValueT, MapTy, ValueInfoT> &LHS,
|
||||
const DenseSetImpl<ValueT, MapTy, ValueInfoT> &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
/// Implements a dense probed hash-table based set.
|
||||
|
|
|
@ -362,6 +362,26 @@ int CountCopyAndMove::Move = 0;
|
|||
|
||||
} // anonymous namespace
|
||||
|
||||
// Test initializer list construction.
|
||||
TEST(DenseMapCustomTest, InitializerList) {
|
||||
DenseMap<int, int> M({{0, 0}, {0, 1}, {1, 2}});
|
||||
EXPECT_EQ(2u, M.size());
|
||||
EXPECT_EQ(1u, M.count(0));
|
||||
EXPECT_EQ(0, M[0]);
|
||||
EXPECT_EQ(1u, M.count(1));
|
||||
EXPECT_EQ(2, M[1]);
|
||||
}
|
||||
|
||||
// Test initializer list construction.
|
||||
TEST(DenseMapCustomTest, EqualityComparison) {
|
||||
DenseMap<int, int> M1({{0, 0}, {1, 2}});
|
||||
DenseMap<int, int> M2({{0, 0}, {1, 2}});
|
||||
DenseMap<int, int> M3({{0, 0}, {1, 3}});
|
||||
|
||||
EXPECT_EQ(M1, M2);
|
||||
EXPECT_NE(M1, M3);
|
||||
}
|
||||
|
||||
// Test for the default minimum size of a DenseMap
|
||||
TEST(DenseMapCustomTest, DefaultMinReservedSizeTest) {
|
||||
// IF THIS VALUE CHANGE, please update InitialSizeTest, InitFromIterator, and
|
||||
|
|
|
@ -121,6 +121,15 @@ TYPED_TEST(DenseSetTest, FindAsTest) {
|
|||
EXPECT_TRUE(set.find_as("d") == set.end());
|
||||
}
|
||||
|
||||
TYPED_TEST(DenseSetTest, EqualityComparisonTest) {
|
||||
TypeParam set1({1, 2, 3, 4});
|
||||
TypeParam set2({4, 3, 2, 1});
|
||||
TypeParam set3({2, 3, 4, 5});
|
||||
|
||||
EXPECT_EQ(set1, set2);
|
||||
EXPECT_NE(set1, set3);
|
||||
}
|
||||
|
||||
// Simple class that counts how many moves and copy happens when growing a map
|
||||
struct CountCopyAndMove {
|
||||
static int Move;
|
||||
|
|
Loading…
Reference in New Issue