From 0c7313bb5f2baa2fb2c95ddff001601083737fca Mon Sep 17 00:00:00 2001 From: Matej Ferencevic <matej.ferencevic@memgraph.io> Date: Fri, 24 Jan 2020 10:22:34 +0100 Subject: [PATCH] Remove unused datastructures Reviewers: teon.banek Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D2639 --- src/data_structures/bitset/static_bitset.hpp | 99 ------------ src/data_structures/queue.hpp | 90 ----------- src/data_structures/union_find.hpp | 90 ----------- tests/unit/CMakeLists.txt | 6 - tests/unit/datastructure_union_find.cpp | 80 ---------- tests/unit/queue.cpp | 154 ------------------- 6 files changed, 519 deletions(-) delete mode 100644 src/data_structures/bitset/static_bitset.hpp delete mode 100644 src/data_structures/queue.hpp delete mode 100644 src/data_structures/union_find.hpp delete mode 100644 tests/unit/datastructure_union_find.cpp delete mode 100644 tests/unit/queue.cpp diff --git a/src/data_structures/bitset/static_bitset.hpp b/src/data_structures/bitset/static_bitset.hpp deleted file mode 100644 index 0a0300aac..000000000 --- a/src/data_structures/bitset/static_bitset.hpp +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once - -#include <algorithm> -#include <bitset> -#include <iostream> -#include <string> - -#include "glog/logging.h" - -/** - * Bitset data structure with a number of bits provided in constructor. - * @tparam TStore type of underlying bit storage: int32, int64, char, etc. - */ -template <typename TStore> -class Bitset { - public: - /** - * Create bitset. - * @param sz size of bitset - */ - Bitset(size_t sz) : block_size_(8 * sizeof(TStore)) { - if (sz % block_size_ != 0) sz += block_size_; - blocks_.resize(sz / block_size_); - } - /** - * Set bit to one. - * @param idx position of bit. - */ - void Set(int idx) { - DCHECK(idx >= 0) << "Invalid bit location."; - DCHECK(idx < static_cast<int64_t>(blocks_.size()) * block_size_) - << "Invalid bit location."; - int bucket = idx / block_size_; - blocks_[bucket] |= TStore(1) << idx % block_size_; - } - /** - * Return bit at position. - * @param idx position of bit. - * @return 1/0. - */ - bool At(int idx) const { - DCHECK(idx >= 0) << "Invalid bit location."; - DCHECK(idx < static_cast<int64_t>(blocks_.size()) * block_size_) - << "Invalid bit location."; - int bucket = idx / block_size_; - return (blocks_[bucket] >> (idx % block_size_)) & 1; - } - /** - * Intersect two bitsets - * @param other bitset. - * @return intersection. - */ - Bitset<TStore> Intersect(const Bitset<TStore> &other) const { - DCHECK(this->blocks_.size() == other.blocks_.size()) - << "Bitsets are not of equal size."; - Bitset<TStore> ret(this->blocks_.size() * this->block_size_); - for (int i = 0; i < (int)this->blocks_.size(); ++i) { - ret.blocks_[i] = this->blocks_[i] & other.blocks_[i]; - continue; - } - return ret; - } - /** - * Positions of bits set to 1. - * @return positions of bits set to 1. - */ - std::vector<int> Ones() const { - std::vector<int> ret; - int ret_idx = 0; - for (auto x : blocks_) { - while (x) { - auto pos = CountTrailingZeroes(x & -x); - x -= x & -x; - ret.push_back(ret_idx + pos); - } - ret_idx += block_size_; - } - return ret; - } - - private: - /** - * Calculate number of trailing zeroes in a binary number, usually a power - * of two. - * @return number of trailing zeroes. - */ - size_t CountTrailingZeroes(TStore v) const { - size_t ret = 0; - while (v >> 32) ret += 32, v >>= 32; - if (v >> 16) ret += 16, v >>= 16; - if (v >> 8) ret += 8, v >>= 8; - if (v >> 4) ret += 4, v >>= 4; - if (v >> 2) ret += 2, v >>= 2; - if (v >> 1) ret += 1, v >>= 1; - return ret; - } - std::vector<TStore> blocks_; - const size_t block_size_; -}; diff --git a/src/data_structures/queue.hpp b/src/data_structures/queue.hpp deleted file mode 100644 index ffaa738db..000000000 --- a/src/data_structures/queue.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once - -#include <atomic> -#include <condition_variable> -#include <cstdint> -#include <iostream> -#include <mutex> -#include <optional> -#include <queue> -#include <thread> - -#include "glog/logging.h" - -// Thread safe queue. Probably doesn't perform very well, but it works. -template <typename T> -class Queue { - public: - Queue() = default; - Queue(const Queue &) = delete; - Queue &operator=(const Queue &) = delete; - Queue(Queue &&) = delete; - Queue &operator=(Queue &&) = delete; - - void Push(T x) { - std::unique_lock<std::mutex> guard(mutex_); - queue_.emplace(std::move(x)); - guard.unlock(); - cvar_.notify_one(); - } - - template <typename... Args> - void Emplace(Args &&... args) { - std::unique_lock<std::mutex> guard(mutex_); - queue_.emplace(std::forward<Args>(args)...); - guard.unlock(); - cvar_.notify_one(); - } - - int64_t size() const { - std::unique_lock<std::mutex> guard(mutex_); - return queue_.size(); - } - - bool empty() const { - std::unique_lock<std::mutex> guard(mutex_); - return queue_.empty(); - } - - // Block until there is an element in the queue and then pop it from the queue - // and return it. Function can return nullopt if Queue is signaled via - // Shutdown function or if there is no element to pop after timeout elapses. - std::optional<T> AwaitPop(std::chrono::system_clock::duration timeout = - std::chrono::system_clock::duration::max()) { - std::unique_lock<std::mutex> guard(mutex_); - auto now = std::chrono::system_clock::now(); - auto until = std::chrono::system_clock::time_point::max() - timeout > now - ? now + timeout - : std::chrono::system_clock::time_point::max(); - cvar_.wait_until(guard, until, - [this] { return !queue_.empty() || !alive_; }); - if (queue_.empty() || !alive_) return std::nullopt; - std::optional<T> x(std::move(queue_.front())); - queue_.pop(); - return x; - } - - // Nonblocking version of above function. - std::optional<T> MaybePop() { - std::unique_lock<std::mutex> guard(mutex_); - if (queue_.empty()) return std::nullopt; - std::optional<T> x(std::move(queue_.front())); - queue_.pop(); - return x; - } - - // Notify all threads waiting on conditional variable to stop waiting. New - // threads that try to Await will not block. - void Shutdown() { - std::unique_lock<std::mutex> guard(mutex_); - alive_ = false; - guard.unlock(); - cvar_.notify_all(); - } - - private: - bool alive_ = true; - std::queue<T> queue_; - std::condition_variable cvar_; - mutable std::mutex mutex_; -}; diff --git a/src/data_structures/union_find.hpp b/src/data_structures/union_find.hpp deleted file mode 100644 index 98e3fd92d..000000000 --- a/src/data_structures/union_find.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once - -#include <memory> -#include <vector> - -template <class uintXX_t = uint32_t> -/** - * UnionFind data structure. Provides means of connectivity - * setting and checking in O(alpha(n)) amortized complexity. Memory - * complexity is linear. - */ -class UnionFind { - public: - /** - * Constructor, creates a UnionFind structure of fixed size. - * - * @param n Number of elements in the data structure. - */ - explicit UnionFind(uintXX_t n) : set_count_(n), rank_(n), parent_(n) { - for (auto i = 0; i < n; ++i) rank_[i] = 0, parent_[i] = i; - } - - /** - * Connects two elements (and thereby the sets they belong - * to). If they are already connected the function has no effect. - * - * Has O(alpha(n)) amortized time complexity. - * - * @param p First element. - * @param q Second element. - */ - void Connect(uintXX_t p, uintXX_t q) { - auto rp = Root(p); - auto rq = Root(q); - - // if roots are equal, we don't have to do anything - if (rp == rq) return; - - // merge the subtree with the smaller rank to the root of the subtree with - // the larger rank - if (rank_[rp] < rank_[rq]) - parent_[rp] = rq; - else if (rank_[rp] > rank_[rq]) - parent_[rq] = rp; - else - parent_[rq] = rp, rank_[rp] += 1; - - // update the number of groups - set_count_--; - } - - /** - * Indicates if two elements are connected. Has amortized O(alpha(n)) time - * complexity. - * - * @param p First element. - * @param q Second element. - * @return See above. - */ - bool Find(uintXX_t p, uintXX_t q) { return Root(p) == Root(q); } - - /** - * Returns the number of disjoint sets in this UnionFind. - * - * @return See above. - */ - uintXX_t Size() const { return set_count_; } - - private: - uintXX_t set_count_; - - // array of subtree ranks - std::vector<uintXX_t> rank_; - - // array of tree indices - std::vector<uintXX_t> parent_; - - uintXX_t Root(uintXX_t p) { - auto r = p; - auto newp = p; - - // find the node connected to itself, that's the root - while (parent_[r] != r) r = parent_[r]; - - // do some path compression to enable faster searches - while (p != r) newp = parent_[p], parent_[p] = r, p = newp; - - return r; - } -}; diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index ef396303e..0850bc20f 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -24,9 +24,6 @@ target_link_libraries(${test_prefix}bolt_encoder mg-communication mg-query) add_unit_test(commit_log_v2.cpp) target_link_libraries(${test_prefix}commit_log_v2 glog gflags) -add_unit_test(datastructure_union_find.cpp) -target_link_libraries(${test_prefix}datastructure_union_find glog gflags) - add_unit_test(kvstore.cpp) target_link_libraries(${test_prefix}kvstore kvstore_lib glog) @@ -112,9 +109,6 @@ target_link_libraries(${test_prefix}typed_value mg-query) # END mg-query -add_unit_test(queue.cpp) -target_link_libraries(${test_prefix}queue glog gflags) - add_unit_test(skip_list.cpp) target_link_libraries(${test_prefix}skip_list mg-utils) diff --git a/tests/unit/datastructure_union_find.cpp b/tests/unit/datastructure_union_find.cpp deleted file mode 100644 index 73c450662..000000000 --- a/tests/unit/datastructure_union_find.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include <stdlib.h> -#include <iostream> - -#include "gtest/gtest.h" - -#include "data_structures/union_find.hpp" - -void ExpectFully(UnionFind<> &uf, bool connected, int from = 0, int to = -1) { - if (to == -1) to = uf.Size(); - - for (int i = from; i < to; i++) - for (int j = from; j < to; j++) - if (i != j) EXPECT_EQ(uf.Find(i, j), connected); -} - -TEST(UnionFindTest, InitialSizeTest) { - for (int i = 0; i < 10; i++) { - UnionFind<> uf(i); - EXPECT_EQ(i, uf.Size()); - } -} - -TEST(UnionFindTest, ModifiedSizeTest) { - UnionFind<> uf(10); - EXPECT_EQ(10, uf.Size()); - - uf.Connect(0, 0); - EXPECT_EQ(10, uf.Size()); - - uf.Connect(0, 1); - EXPECT_EQ(9, uf.Size()); - - uf.Connect(2, 3); - EXPECT_EQ(8, uf.Size()); - - uf.Connect(0, 2); - EXPECT_EQ(7, uf.Size()); - - uf.Connect(1, 3); - EXPECT_EQ(7, uf.Size()); -} - -TEST(UnionFindTest, Disconectivity) { - UnionFind<> uf(10); - ExpectFully(uf, false); -} - -TEST(UnionFindTest, ConnectivityAlongChain) { - UnionFind<> uf(10); - for (unsigned int i = 1; i < uf.Size(); i++) uf.Connect(i - 1, i); - ExpectFully(uf, true); -} - -TEST(UnionFindTest, ConnectivityOnTree) { - UnionFind<> uf(10); - ExpectFully(uf, false); - - uf.Connect(0, 1); - uf.Connect(0, 2); - ExpectFully(uf, true, 0, 3); - ExpectFully(uf, false, 2); - - uf.Connect(2, 3); - ExpectFully(uf, true, 0, 4); - ExpectFully(uf, false, 3); -} - -TEST(UnionFindTest, DisjointChains) { - UnionFind<> uf(30); - for (int i = 0; i < 30; i++) uf.Connect(i, i % 10 == 0 ? i : i - 1); - - for (int i = 0; i < 30; i++) - for (int j = 0; j < 30; j++) - EXPECT_EQ(uf.Find(i, j), (j - (j % 10)) == (i - (i % 10))); -} - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/tests/unit/queue.cpp b/tests/unit/queue.cpp deleted file mode 100644 index e46148e3e..000000000 --- a/tests/unit/queue.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include <atomic> -#include <chrono> -#include <optional> -#include <string> -#include <thread> -#include <utility> - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "data_structures/queue.hpp" - -namespace { - -using namespace std::literals::chrono_literals; - -TEST(Queue, PushMaybePop) { - Queue<int> q; - q.Push(1); - EXPECT_EQ(*q.MaybePop(), 1); - EXPECT_EQ(q.MaybePop(), std::nullopt); - - q.Push(2); - q.Push(3); - EXPECT_EQ(*q.MaybePop(), 2); - - q.Push(4); - q.Push(5); - EXPECT_EQ(*q.MaybePop(), 3); - EXPECT_EQ(*q.MaybePop(), 4); - EXPECT_EQ(*q.MaybePop(), 5); - EXPECT_EQ(q.MaybePop(), std::nullopt); -} - -TEST(Queue, Emplace) { - Queue<std::pair<std::string, int>> q; - q.Emplace("abc", 123); - EXPECT_THAT(*q.MaybePop(), testing::Pair("abc", 123)); -} - -TEST(Queue, Size) { - Queue<int> q; - EXPECT_EQ(q.size(), 0); - - q.Push(1); - EXPECT_EQ(q.size(), 1); - - q.Push(1); - EXPECT_EQ(q.size(), 2); - - q.MaybePop(); - EXPECT_EQ(q.size(), 1); - - q.MaybePop(); - EXPECT_EQ(q.size(), 0); - q.MaybePop(); - EXPECT_EQ(q.size(), 0); -} - -TEST(Queue, Empty) { - Queue<int> q; - EXPECT_TRUE(q.empty()); - - q.Push(1); - EXPECT_FALSE(q.empty()); - - q.MaybePop(); - EXPECT_TRUE(q.empty()); -} - -TEST(Queue, AwaitPop) { - Queue<int> q; - std::thread t([&] { - q.Push(1); - q.Push(2); - std::this_thread::sleep_for(200ms); - q.Push(3); - q.Push(4); - }); - - EXPECT_EQ(*q.AwaitPop(), 1); - std::this_thread::sleep_for(1000ms); - EXPECT_EQ(*q.AwaitPop(), 2); - EXPECT_EQ(*q.AwaitPop(), 3); - EXPECT_EQ(*q.AwaitPop(), 4); - t.join(); - - std::thread t2([&] { - std::this_thread::sleep_for(100ms); - q.Shutdown(); - }); - std::this_thread::sleep_for(200ms); - EXPECT_EQ(q.AwaitPop(), std::nullopt); - t2.join(); -} - -TEST(Queue, AwaitPopTimeout) { - std::this_thread::sleep_for(1000ms); - Queue<int> q; - EXPECT_EQ(q.AwaitPop(100ms), std::nullopt); -} - -TEST(Queue, Concurrent) { - Queue<int> q; - - const int kNumProducers = 10; - const int kNumConsumers = 10; - const int kNumElementsPerProducer = 300000; - - std::vector<std::thread> producers; - std::atomic<int> next{0}; - - for (int i = 0; i < kNumProducers; ++i) { - producers.emplace_back([&] { - for (int i = 0; i < kNumElementsPerProducer; ++i) { - q.Push(next++); - } - }); - } - - std::vector<std::thread> consumers; - std::vector<int> retrieved[kNumConsumers]; - std::atomic<int> num_retrieved{0}; - for (int i = 0; i < kNumConsumers; ++i) { - consumers.emplace_back( - [&](int thread_id) { - while (true) { - int count = num_retrieved++; - if (count >= kNumProducers * kNumElementsPerProducer) break; - retrieved[thread_id].push_back(*q.AwaitPop()); - } - }, - i); - } - - for (auto &t : consumers) { - t.join(); - } - for (auto &t : producers) { - t.join(); - } - - EXPECT_EQ(q.MaybePop(), std::nullopt); - - std::set<int> all_elements; - for (auto &r : retrieved) { - all_elements.insert(r.begin(), r.end()); - } - EXPECT_EQ(all_elements.size(), kNumProducers * kNumElementsPerProducer); - EXPECT_EQ(*all_elements.begin(), 0); - EXPECT_EQ(*all_elements.rbegin(), - kNumProducers * kNumElementsPerProducer - 1); -} -} // namespace