From 94a77ab3adee9f3ab184e23fe0c38d4cb5086635 Mon Sep 17 00:00:00 2001 From: James Gill <jagill@fb.com> Date: Fri, 15 Mar 2019 06:13:18 -0700 Subject: [PATCH] Implement c++20 contains method on F14Map and F14Set Summary: contains() is part of the c++20 spec. This implements it, and refactors count() to use contains(). Reviewed By: nbronson Differential Revision: D14426805 fbshipit-source-id: 2435124e9c0a8eeb4e53109f0ddac884c227c781 --- folly/container/F14Map.h | 14 ++++++++++++-- folly/container/F14Set.h | 14 ++++++++++++-- folly/container/test/F14MapTest.cpp | 16 ++++++++++++++++ folly/container/test/F14SetTest.cpp | 16 ++++++++++++++++ 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/folly/container/F14Map.h b/folly/container/F14Map.h index b91594bbb..bc6452dfe 100644 --- a/folly/container/F14Map.h +++ b/folly/container/F14Map.h @@ -748,13 +748,13 @@ class F14BasicMap { } FOLLY_ALWAYS_INLINE size_type count(key_type const& key) const { - return table_.find(key).atEnd() ? 0 : 1; + return contains(key) ? 1 : 0; } template <typename K> FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, size_type> count( K const& key) const { - return table_.find(key).atEnd() ? 0 : 1; + return contains(key) ? 1 : 0; } // prehash(key) does the work of evaluating hash_function()(key) @@ -823,6 +823,16 @@ class F14BasicMap { return table_.makeConstIter(table_.find(token, key)); } + FOLLY_ALWAYS_INLINE bool contains(key_type const& key) const { + return !table_.find(key).atEnd(); + } + + template <typename K> + FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, bool> contains( + K const& key) const { + return !table_.find(key).atEnd(); + } + std::pair<iterator, iterator> equal_range(key_type const& key) { return equal_range(*this, key); } diff --git a/folly/container/F14Set.h b/folly/container/F14Set.h index 78fdd3894..da99772f7 100644 --- a/folly/container/F14Set.h +++ b/folly/container/F14Set.h @@ -530,13 +530,13 @@ class F14BasicSet { //// PUBLIC - Lookup FOLLY_ALWAYS_INLINE size_type count(key_type const& key) const { - return table_.find(key).atEnd() ? 0 : 1; + return contains(key) ? 1 : 0; } template <typename K> FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, size_type> count( K const& key) const { - return table_.find(key).atEnd() ? 0 : 1; + return contains(key) ? 1 : 0; } // prehash(key) does the work of evaluating hash_function()(key) @@ -605,6 +605,16 @@ class F14BasicSet { return table_.makeIter(table_.find(token, key)); } + FOLLY_ALWAYS_INLINE bool contains(key_type const& key) const { + return !table_.find(key).atEnd(); + } + + template <typename K> + FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, bool> contains( + K const& key) const { + return !table_.find(key).atEnd(); + } + std::pair<iterator, iterator> equal_range(key_type const& key) { return equal_range(*this, key); } diff --git a/folly/container/test/F14MapTest.cpp b/folly/container/test/F14MapTest.cpp index 4e00191af..c942d29b6 100644 --- a/folly/container/test/F14MapTest.cpp +++ b/folly/container/test/F14MapTest.cpp @@ -277,6 +277,8 @@ void runSimple() { EXPECT_EQ(h8.size(), 2); EXPECT_EQ(h8.count(s("abc")), 1); EXPECT_EQ(h8.count(s("xyz")), 0); + EXPECT_TRUE(h8.contains(s("abc"))); + EXPECT_FALSE(h8.contains(s("xyz"))); EXPECT_TRUE(h7 != h8); EXPECT_TRUE(h8 != h9); @@ -294,6 +296,10 @@ void runSimple() { EXPECT_EQ(h5.count(k), 1); EXPECT_EQ(h6.count(k), 1); EXPECT_EQ(h8.count(k), 1); + EXPECT_TRUE(h4.contains(k)); + EXPECT_TRUE(h5.contains(k)); + EXPECT_TRUE(h6.contains(k)); + EXPECT_TRUE(h8.contains(k)); } EXPECT_TRUE(h2 == h7); @@ -485,6 +491,8 @@ void runRandom() { EXPECT_EQ(t->second.val_, r->second.val_); } EXPECT_EQ(t0.count(k), r0.count(k)); + // TODO: When std::unordered_map supports c++20: + // EXPECT_EQ(t0.contains(k), r0.contains(k)); } else if (pct < 60) { // equal_range auto t = t0.equal_range(k); @@ -1183,10 +1191,13 @@ void runInsertAndEmplace(std::string const& name) { M m; typename M::key_type k; EXPECT_EQ(m.count(k), 0); + EXPECT_FALSE(m.contains(k)); m.emplace(); EXPECT_EQ(m.count(k), 1); + EXPECT_TRUE(m.contains(k)); m.emplace(); EXPECT_EQ(m.count(k), 1); + EXPECT_TRUE(m.contains(k)); } TEST(F14ValueMap, destructuring) { @@ -1308,6 +1319,10 @@ TEST(F14ValueMap, heterogeneousLookup) { EXPECT_TRUE(ref.end() == ref.find(ref.prehash(buddy), buddy)); EXPECT_EQ(hello, ref.find(ref.prehash(hello), hello)->first); + // contains + EXPECT_FALSE(ref.contains(buddy)); + EXPECT_TRUE(ref.contains(hello)); + // equal_range EXPECT_TRUE(std::make_pair(ref.end(), ref.end()) == ref.equal_range(buddy)); EXPECT_TRUE( @@ -1403,6 +1418,7 @@ void runHeterogeneousInsertTest() { resetTracking(); EXPECT_EQ(map.count(10), 0); + EXPECT_FALSE(map.contains(10)); EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 0) << Tracked<1>::counts; diff --git a/folly/container/test/F14SetTest.cpp b/folly/container/test/F14SetTest.cpp index 679789d64..638196f89 100644 --- a/folly/container/test/F14SetTest.cpp +++ b/folly/container/test/F14SetTest.cpp @@ -269,6 +269,8 @@ void runSimple() { EXPECT_EQ(h8.size(), 2); EXPECT_EQ(h8.count(s("abc")), 1); EXPECT_EQ(h8.count(s("xyz")), 0); + EXPECT_TRUE(h8.contains(s("abc"))); + EXPECT_FALSE(h8.contains(s("xyz"))); EXPECT_TRUE(h7 != h8); EXPECT_TRUE(h8 != h9); @@ -286,6 +288,10 @@ void runSimple() { EXPECT_EQ(h5.count(k), 1); EXPECT_EQ(h6.count(k), 1); EXPECT_EQ(h8.count(k), 1); + EXPECT_TRUE(h4.contains(k)); + EXPECT_TRUE(h5.contains(k)); + EXPECT_TRUE(h6.contains(k)); + EXPECT_TRUE(h8.contains(k)); } h8.clear(); @@ -439,6 +445,8 @@ void runRandom() { EXPECT_EQ(*t, *r); } EXPECT_EQ(t0.count(k), r0.count(k)); + // TODO: When std::unordered_set supports c++20: + // EXPECT_EQ(t0.contains(k), r0.contains(k)); } else if (pct < 60) { // equal_range auto t = t0.equal_range(k); @@ -829,10 +837,13 @@ void runInsertAndEmplace() { S s; typename S::value_type k; EXPECT_EQ(s.count(k), 0); + EXPECT_FALSE(s.contains(k)); s.emplace(); EXPECT_EQ(s.count(k), 1); + EXPECT_TRUE(s.contains(k)); s.emplace(); EXPECT_EQ(s.count(k), 1); + EXPECT_TRUE(s.contains(k)); } TEST(F14ValueSet, destructuring) { @@ -982,6 +993,10 @@ TEST(F14ValueSet, heterogeneous) { EXPECT_TRUE(ref.end() == ref.find(ref.prehash(buddy), buddy)); EXPECT_EQ(hello, *ref.find(ref.prehash(hello), hello)); + // contains + EXPECT_FALSE(ref.contains(buddy)); + EXPECT_TRUE(ref.contains(hello)); + // equal_range EXPECT_TRUE(std::make_pair(ref.end(), ref.end()) == ref.equal_range(buddy)); EXPECT_TRUE( @@ -1073,6 +1088,7 @@ void runHeterogeneousInsertTest() { resetTracking(); EXPECT_EQ(set.count(10), 0); + EXPECT_FALSE(set.contains(10)); EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 0) << Tracked<1>::counts; -- 2.26.2