--- /dev/null
+#include <folly/concurrency/ConcurrentHashMap.h>
+#include <folly/AtomicHashMap.h>
+#include <folly/AtomicUnorderedMap.h>
+
+#include <gtest/gtest.h>
+
+#include <memory>
+
+namespace {
+
+const unsigned s_nInsertPercentage = 10;
+
+const size_t kConcurrentHashMapSize = 10000;
+const size_t kConcurrentHashMapPassCount = 36000;
+
+const size_t kAtomicHashMapSize = 10000;
+const size_t kAtomicHashMapPassCount = 250000;
+
+const size_t kAtomicUnorderedInsertMapSize = 10000;
+const size_t kAtomicUnorderedInsertMapPassCount = 500000;
+
+typedef folly::ConcurrentHashMap<size_t, size_t> ConcurrentHashMap;
+typedef folly::AtomicHashMap<size_t, size_t> AtomicHashMap;
+typedef folly::AtomicUnorderedInsertMap64<size_t, size_t>
+ AtomicUnorderedInsertMap;
+}
+
+template <typename Key>
+bool map_contains(const AtomicUnorderedInsertMap* map, Key key) {
+ return map->find(key) != map->cend();
+}
+
+template <typename Key>
+bool map_contains(const ConcurrentHashMap* map, Key key) {
+ return map->find(key) != map->cend();
+}
+
+template <typename Map, typename Key>
+bool map_contains(const Map* map, Key key) {
+ return map->find(key) != map->end();
+}
+
+template <typename Map>
+void run_atomic_unordered_insert_map(size_t map_size, size_t pass_count) {
+ size_t nInsertedNum = 0;
+ size_t nFindSuccess = 0;
+ std::unique_ptr<Map> map(new Map(map_size));
+ for (size_t count = 0; count < pass_count; count++) {
+ for (size_t i = 0; i < map_size; ++i) {
+ // The number to operate on the map.
+ size_t n = map_size + i;
+ // Insert
+ if (i % s_nInsertPercentage == 1) {
+ auto iter = map->find(i);
+ if (iter != map->cend()) {
+ if (iter->second == n) {
+ map->emplace(i, n / 2);
+ } else {
+ map->emplace(i, n);
+ }
+ } else {
+ map->emplace(i, n);
+ }
+ nInsertedNum++;
+ }
+ // Find
+ {
+ if (map_contains(map.get(), i)) {
+ ++nFindSuccess;
+ }
+ }
+ }
+ }
+ EXPECT_EQ(nFindSuccess, nInsertedNum);
+}
+
+template <typename Map>
+void run_atomic_hashmap(size_t map_size, size_t pass_count) {
+ size_t nInsertedNum = 0;
+ size_t nFindSuccess = 0;
+ std::unique_ptr<Map> map(new Map(map_size));
+ for (size_t count = 0; count < pass_count; count++) {
+ for (size_t i = 0; i < map_size; ++i) {
+ // The number to operate on the map.
+ size_t n = map_size + i;
+ // Insert
+ if (i % s_nInsertPercentage == 1) {
+ auto iter = map->find(i);
+ if (iter != map->end()) {
+ if (iter->second == n) {
+ iter->second = n / 2;
+ } else {
+ iter->second = n;
+ }
+ } else {
+ map->insert({i, n});
+ }
+ nInsertedNum++;
+ }
+ // Find
+ {
+ if (map_contains(map.get(), i)) {
+ ++nFindSuccess;
+ }
+ }
+ }
+ }
+ EXPECT_EQ(nFindSuccess, nInsertedNum);
+}
+
+template <typename Map>
+void run_concurrent_hashmap(size_t map_size, size_t pass_count) {
+ size_t nInsertedNum = 0;
+ size_t nFindSuccess = 0;
+ std::unique_ptr<Map> map(new Map(map_size));
+ for (size_t count = 0; count < pass_count; count++) {
+ for (size_t i = 0; i < map_size; ++i) {
+ // The number to operate on the map.
+ size_t n = map_size + i;
+ // Insert
+ if (i % s_nInsertPercentage == 1) {
+ auto iter = map->insert({i, n});
+ nInsertedNum++;
+ }
+ // Find
+ {
+ if (map_contains(map.get(), i)) {
+ ++nFindSuccess;
+ }
+ }
+ // Delete
+ if (i % s_nInsertPercentage == 1) {
+ if (map_contains(map.get(), i)) {
+ map->erase(i);
+ }
+ }
+ }
+ }
+ EXPECT_EQ(nFindSuccess, nInsertedNum);
+}
+
+class FollyMapInsDelFindTest: public ::testing::Test {
+};
+
+TEST_F(FollyMapInsDelFindTest, FollyConcurrentHashMap) {
+ run_concurrent_hashmap<ConcurrentHashMap>(
+ kConcurrentHashMapSize,
+ kConcurrentHashMapPassCount);
+}
+
+TEST_F(FollyMapInsDelFindTest, FollyAtomicHashMap) {
+ run_atomic_hashmap<AtomicHashMap>(
+ kAtomicHashMapSize,
+ kAtomicHashMapPassCount);
+}
+
+TEST_F(FollyMapInsDelFindTest, FollyAtomicUnorderedInsertMap) {
+ run_atomic_unordered_insert_map<AtomicUnorderedInsertMap>(
+ kAtomicUnorderedInsertMapSize,
+ kAtomicUnorderedInsertMapPassCount);
+}
+
+int main(int argc, char** argv) {
+ // Init Google test
+ ::testing::InitGoogleTest(&argc, argv);
+ int result = RUN_ALL_TESTS();
+ return result;
+}