Move unused datastructures to poc

Reviewers: buda

Reviewed By: buda

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D526
This commit is contained in:
Mislav Bradac 2017-07-06 17:47:28 +02:00
parent 88153595ce
commit 0588de76bb
68 changed files with 542 additions and 829 deletions

View File

@ -26,5 +26,9 @@ foreach(poc_cpp ${poc_cpps})
# link libraries
target_link_libraries(${target_name} memgraph_lib)
# gtest
target_link_libraries(${target_name} gtest gtest_main gmock)
# google-benchmark
target_link_libraries(${target_name} benchmark ${CMAKE_THREAD_LIBS_INIT})
endforeach()

View File

@ -3,10 +3,10 @@
#include <thread>
#include <vector>
#include "memory/allocator.hpp"
#include "memory/maker.hpp"
#include "utils/assert.hpp"
#include "utils/measure_time.hpp"
#include "utils/memory/allocator.hpp"
#include "utils/memory/maker.hpp"
struct TestStructure {
TestStructure(int a, int b, int c, int d) : a(a), b(b), c(c), d(d) {}

View File

@ -1,6 +1,6 @@
#include "gtest/gtest.h"
#include "utils/memory/allocator.hpp"
#include "memory/allocator.hpp"
TEST(AllocatorTest, ABlockOfIntegersCanBeAllocated) {
constexpr int N = 100;

View File

@ -2,7 +2,7 @@
#include <functional>
#include "data_structures/bloom/bloom_filter.hpp"
#include "bloom_filter.hpp"
#include "utils/hashing/fnv64.hpp"
using StringHashFunction = std::function<uint64_t(const std::string &)>;

View File

@ -4,7 +4,7 @@
#include <benchmark/benchmark_api.h>
#include <glog/logging.h>
#include "data_structures/bloom/bloom_filter.hpp"
#include "bloom_filter.hpp"
#include "utils/hashing/fnv64.hpp"
#include "utils/random/random_generator.hpp"

View File

@ -1,6 +1,6 @@
#include "gtest/gtest.h"
#include <gtest/gtest.h>
#include "utils/memory/block_allocator.hpp"
#include "memory/block_allocator.hpp"
TEST(BlockAllocatorTest, UnusedVsReleaseSize) {
BlockAllocator<64> block_allocator(10);

View File

@ -1,6 +1,7 @@
#pragma once
#include <bitset>
#include <functional>
#include <iostream>
#include <vector>

View File

@ -5,8 +5,8 @@
#include <gflags/gflags.h>
#include <glog/logging.h>
#include "data_structures/bloom/bloom_filter.hpp"
#include "data_structures/concurrent/concurrent_bloom_map.hpp"
#include "bloom_filter.hpp"
#include "concurrent_bloom_map.hpp"
#include "utils/hashing/fnv64.hpp"
#include "utils/random/random_generator.hpp"

View File

@ -50,7 +50,8 @@ class HP {
hp.clear(*this);
}
reference& operator=(reference&& other) { return *this; }
// TODO: ???
reference& operator=(reference&&) { return *this; }
private:
reference(int64_t idx) : idx(idx) {}

View File

@ -3,6 +3,7 @@
#include <atomic>
#include <memory>
// I heard this is patented.
template <class T>
class atomic_shared_ptr final {
public:

View File

@ -2,9 +2,9 @@
#include <cmath>
#include "memory/block_allocator.hpp"
#include "utils/exceptions.hpp"
#include "utils/likely.hpp"
#include "utils/memory/block_allocator.hpp"
// http://en.cppreference.com/w/cpp/language/new

51
poc/ptr_int.hpp Normal file
View File

@ -0,0 +1,51 @@
#pragma once
#include <cinttypes>
constexpr std::size_t log2(std::size_t n) {
return ((n < 2) ? 0 : 1 + log2(n >> 1));
}
template <typename PtrT>
struct PointerPackTraits {
// here is a place to embed something like platform specific things
// TODO: cover more cases
constexpr static int free_bits = log2(alignof(PtrT));
static auto get_ptr(uintptr_t value) { return (PtrT)(value); }
};
template <typename PtrT, int IntBits, typename IntT = unsigned,
typename PtrTraits = PointerPackTraits<PtrT>>
class PtrInt {
private:
constexpr static int int_shift = PtrTraits::free_bits - IntBits;
constexpr static uintptr_t ptr_mask =
~(uintptr_t)(((intptr_t)1 << PtrTraits::free_bits) - 1);
constexpr static uintptr_t int_mask =
(uintptr_t)(((intptr_t)1 << IntBits) - 1);
uintptr_t value{0};
public:
PtrInt(PtrT pointer, IntT integer) {
set_ptr(pointer);
set_int(integer);
}
auto set_ptr(PtrT pointer) {
auto integer = static_cast<uintptr_t>(get_int());
auto ptr = reinterpret_cast<uintptr_t>(pointer);
value = (ptr_mask & ptr) | (integer << int_shift);
}
auto set_int(IntT integer) {
auto ptr = reinterpret_cast<uintptr_t>(get_ptr());
auto int_shifted = static_cast<uintptr_t>(integer << int_shift);
value = (int_mask & int_shifted) | ptr;
}
auto get_ptr() const { return PtrTraits::get_ptr(value & ptr_mask); }
auto get_int() const { return (IntT)((value >> int_shift) & int_mask); }
};

26
poc/ptr_int_test.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <gtest/gtest.h>
#include "ptr_int.hpp"
TEST(PtrInt, SizeOf) {
ASSERT_EQ(sizeof(PtrInt<int *, 1, int>), sizeof(uintptr_t));
}
TEST(PtrInt, ConstructionAndRead) {
auto ptr1 = std::make_unique<int>(2);
PtrInt<int *, 2, int> pack1(ptr1.get(), 1);
ASSERT_EQ(pack1.get_int(), 1);
ASSERT_EQ(pack1.get_ptr(), ptr1.get());
auto ptr2 = std::make_unique<int>(2);
PtrInt<int *, 3, int> pack2(ptr2.get(), 4);
ASSERT_EQ(pack2.get_int(), 4);
ASSERT_EQ(pack2.get_ptr(), ptr2.get());
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,9 +1,11 @@
#pragma once
#include <cstring>
#include <functional>
#include "option_ptr.hpp"
#include "utils/assert.hpp"
#include "utils/crtp.hpp"
#include "utils/option_ptr.hpp"
// RobinHood base.
// Entries are POINTERS alligned to 8B.
@ -286,3 +288,174 @@ class RhBase {
friend class IteratorBase<Iterator>;
friend class IteratorBase<ConstIterator>;
};
/**
* HashMap with RobinHood collision resolution policy.
* Single threaded.
* Entries are saved as pointers alligned to 8B.
* Entries must know thers key.
* D must have method const K & get_key()
* K must be comparable with ==.
* HashMap behaves as if it isn't owner of entries.
* BE CAREFUL - this structure assumes that the pointer to Data is 8-alligned!
*/
template <class K, class D, size_t init_size_pow2 = 2>
class RhHashMap : public RhBase<K, D, init_size_pow2> {
typedef RhBase<K, D, init_size_pow2> base;
using base::array;
using base::index;
using base::capacity;
using base::count;
using typename base::Combined;
void increase_size() {
size_t old_size = capacity;
auto a = array;
if (base::increase_size()) {
for (int i = 0; i < old_size; i++) {
if (a[i].valid()) {
insert(a[i].ptr());
}
}
}
free(a);
}
public:
using base::RhBase;
bool contains(const K &key) { return find(key).is_present(); }
OptionPtr<D> find(const K key) {
size_t mask = this->mask();
size_t now = index(key, mask);
size_t off = 0;
size_t border = 8 <= capacity ? 8 : capacity;
while (off < border) {
Combined other = array[now];
if (other.valid()) {
auto other_off = other.off();
if (other_off == off && key == other.ptr()->get_key()) {
// Found data.
return OptionPtr<D>(other.ptr());
} else if (other_off < off) { // Other is rich
break;
} // Else other has equal or greater offset, so he is poor.
} else {
// Empty slot means that there is no searched data.
break;
}
off++;
now = (now + 1) & mask;
}
return OptionPtr<D>();
}
// Inserts element. Returns true if element wasn't in the map.
bool insert(D *data) {
permanent_assert(!(((uint64_t) static_cast<void *>(data) & 7)),
"Data is not 8-alligned.");
if (count < capacity) {
size_t mask = this->mask();
auto key = std::ref(data->get_key());
size_t now = index(key, mask);
size_t off = 0;
size_t border = 8 <= capacity ? 8 : capacity;
while (off < border) {
Combined other = array[now];
if (other.valid()) {
auto other_off = other.off();
if (other_off == off && key == other.ptr()->get_key()) {
// Element already exists.
return false;
} else if (other_off < off) { // Other is rich
// Set data.
array[now] = Combined(data, off);
// Move other data to the higher indexes,
while (other.increment_off()) {
now = (now + 1) & mask;
auto tmp = array[now];
array[now] = other;
other = tmp;
if (!other.valid()) {
count++;
return true;
}
}
data = other.ptr();
break; // Cant insert removed element because it would
// be to far from his real place.
} // Else other has equal or greater offset, so he is poor.
} else {
// Data can be placed in this empty slot.
array[now] = Combined(data, off);
count++;
return true;
}
off++;
now = (now + 1) & mask;
}
}
// There isn't enough space for element pointed by data so whe must
// increase array.
increase_size();
return insert(data);
}
// Removes element. Returns removed element if it existed.
OptionPtr<D> remove(const K &key) {
size_t mask = this->mask();
size_t now = index(key, mask);
size_t off = 0;
size_t border = 8 <= capacity ? 8 : capacity;
while (off < border) {
Combined other = array[now];
if (other.valid()) {
auto other_off = other.off();
auto other_ptr = other.ptr();
if (other_off == off && key == other_ptr->get_key()) { // Found it
auto before = now;
// Whe must move other elements one slot lower.
do {
// This is alright even for off=0 on found element
// because it wont be seen.
other.decrement_off_unsafe();
array[before] = other;
before = now;
now = (now + 1) & mask;
other = array[now];
} while (other.valid() &&
other.off() > 0); // Exit if whe encounter empty
// slot or data which is exactly
// in slot which it want's to be.
array[before] = Combined();
count--;
return OptionPtr<D>(other_ptr);
} else if (other_off < off) { // Other is rich
break;
} // Else other has equal or greater offset, so he is poor.
} else {
// If the element to be removed existed in map it would be here.
break;
}
off++;
now = (now + 1) & mask;
}
return OptionPtr<D>();
}
};

View File

@ -1,7 +1,7 @@
#include "gtest/gtest.h"
#include <memory>
#include "data_structures/map/rh_hashmap.hpp"
#include "rh_hashmap.hpp"
class Data {
private:

View File

@ -1,6 +1,6 @@
#include "gtest/gtest.h"
#include "utils/memory/stack_allocator.hpp"
#include "memory/stack_allocator.hpp"
struct Object {
int a;

View File

@ -3,9 +3,9 @@
#include "gtest/gtest.h"
#include "data_structures/union_find/union_find.hpp"
#include "union_find.hpp"
void _expect_fully(UnionFind<> &uf, bool connected, int from = 0, int to = -1) {
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++)
@ -42,27 +42,27 @@ TEST(UnionFindTest, ModifiedSizeTest) {
TEST(UnionFindTest, Disconectivity) {
UnionFind<> uf(10);
_expect_fully(uf, false);
ExpectFully(uf, false);
}
TEST(UnionFindTest, ConnectivityAlongChain) {
UnionFind<> uf(10);
for (unsigned int i = 1; i < uf.size(); i++) uf.connect(i - 1, i);
_expect_fully(uf, true);
ExpectFully(uf, true);
}
TEST(UnionFindTest, ConnectivityOnTree) {
UnionFind<> uf(10);
_expect_fully(uf, false);
ExpectFully(uf, false);
uf.connect(0, 1);
uf.connect(0, 2);
_expect_fully(uf, true, 0, 3);
_expect_fully(uf, false, 2);
ExpectFully(uf, true, 0, 3);
ExpectFully(uf, false, 2);
uf.connect(2, 3);
_expect_fully(uf, true, 0, 4);
_expect_fully(uf, false, 3);
ExpectFully(uf, true, 0, 4);
ExpectFully(uf, false, 3);
}
TEST(UnionFindTest, DisjointChains) {

View File

@ -1,177 +0,0 @@
#include <functional>
#include "data_structures/map/rh_common.hpp"
#include "utils/assert.hpp"
#include "utils/crtp.hpp"
#include "utils/option_ptr.hpp"
/**
* HashMap with RobinHood collision resolution policy.
* Single threaded.
* Entries are saved as pointers alligned to 8B.
* Entries must know thers key.
* D must have method const K & get_key()
* K must be comparable with ==.
* HashMap behaves as if it isn't owner of entries.
* BE CAREFUL - this structure assumes that the pointer to Data is 8-alligned!
*/
template <class K, class D, size_t init_size_pow2 = 2>
class RhHashMap : public RhBase<K, D, init_size_pow2> {
typedef RhBase<K, D, init_size_pow2> base;
using base::array;
using base::index;
using base::capacity;
using base::count;
using typename base::Combined;
void increase_size() {
size_t old_size = capacity;
auto a = array;
if (base::increase_size()) {
for (int i = 0; i < old_size; i++) {
if (a[i].valid()) {
insert(a[i].ptr());
}
}
}
free(a);
}
public:
using base::RhBase;
bool contains(const K &key) { return find(key).is_present(); }
OptionPtr<D> find(const K key) {
size_t mask = this->mask();
size_t now = index(key, mask);
size_t off = 0;
size_t border = 8 <= capacity ? 8 : capacity;
while (off < border) {
Combined other = array[now];
if (other.valid()) {
auto other_off = other.off();
if (other_off == off && key == other.ptr()->get_key()) {
// Found data.
return OptionPtr<D>(other.ptr());
} else if (other_off < off) { // Other is rich
break;
} // Else other has equal or greater offset, so he is poor.
} else {
// Empty slot means that there is no searched data.
break;
}
off++;
now = (now + 1) & mask;
}
return OptionPtr<D>();
}
// Inserts element. Returns true if element wasn't in the map.
bool insert(D *data) {
permanent_assert(!(((uint64_t) static_cast<void *>(data) & 7)),
"Data is not 8-alligned.");
if (count < capacity) {
size_t mask = this->mask();
auto key = std::ref(data->get_key());
size_t now = index(key, mask);
size_t off = 0;
size_t border = 8 <= capacity ? 8 : capacity;
while (off < border) {
Combined other = array[now];
if (other.valid()) {
auto other_off = other.off();
if (other_off == off && key == other.ptr()->get_key()) {
// Element already exists.
return false;
} else if (other_off < off) { // Other is rich
// Set data.
array[now] = Combined(data, off);
// Move other data to the higher indexes,
while (other.increment_off()) {
now = (now + 1) & mask;
auto tmp = array[now];
array[now] = other;
other = tmp;
if (!other.valid()) {
count++;
return true;
}
}
data = other.ptr();
break; // Cant insert removed element because it would
// be to far from his real place.
} // Else other has equal or greater offset, so he is poor.
} else {
// Data can be placed in this empty slot.
array[now] = Combined(data, off);
count++;
return true;
}
off++;
now = (now + 1) & mask;
}
}
// There isn't enough space for element pointed by data so whe must
// increase array.
increase_size();
return insert(data);
}
// Removes element. Returns removed element if it existed.
OptionPtr<D> remove(const K &key) {
size_t mask = this->mask();
size_t now = index(key, mask);
size_t off = 0;
size_t border = 8 <= capacity ? 8 : capacity;
while (off < border) {
Combined other = array[now];
if (other.valid()) {
auto other_off = other.off();
auto other_ptr = other.ptr();
if (other_off == off && key == other_ptr->get_key()) { // Found it
auto before = now;
// Whe must move other elements one slot lower.
do {
// This is alright even for off=0 on found element
// because it wont be seen.
other.decrement_off_unsafe();
array[before] = other;
before = now;
now = (now + 1) & mask;
other = array[now];
} while (other.valid() &&
other.off() > 0); // Exit if whe encounter empty
// slot or data which is exactly
// in slot which it want's to be.
array[before] = Combined();
count--;
return OptionPtr<D>(other_ptr);
} else if (other_off < off) { // Other is rich
break;
} // Else other has equal or greater offset, so he is poor.
} else {
// If the element to be removed existed in map it would be here.
break;
}
off++;
now = (now + 1) & mask;
}
return OptionPtr<D>();
}
};

View File

@ -1,58 +0,0 @@
#pragma once
#include "utils/assert.hpp"
// data structure namespace short ds
// TODO: document strategy related to namespace naming
// (namespace names should be short but eazy to memorize)
namespace ds {
// static array is data structure which size (capacity) can be known at compile
// time
// this data structure isn't concurrent
template <typename T, size_t N>
class static_array {
public:
// default constructor
static_array() {}
// explicit constructor which populates the data array with
// initial values, array structure after initialization
// is N * [initial_value]
explicit static_array(const T &initial_value) {
for (size_t i = 0; i < size(); ++i) {
data[i] = initial_value;
}
}
// returns array size
size_t size() const { return N; }
// returns element reference on specific index
T &operator[](size_t index) {
debug_assert(index < N, "Index " << index << " must be less than " << N);
return data[index];
}
// returns const element reference on specific index
const T &operator[](size_t index) const {
debug_assert(index < N, "Index " << index << " must be less than " << N);
return data[index];
}
// returns begin iterator
T *begin() { return &data[0]; }
// returns const begin iterator
const T *begin() const { return &data[0]; }
// returns end iterator
T *end() { return &data[N]; }
// returns const end iterator
const T *end() const { return &data[N]; }
private:
T data[N];
};
}

View File

@ -1,69 +0,0 @@
#include "dbms/cleaner.hpp"
#include <chrono>
#include <ctime>
#include <thread>
#include "database/db_transaction.hpp"
#include "threading/thread.hpp"
#include "logging/default.hpp"
Cleaning::Cleaning(ConcurrentMap<std::string, GraphDb> &dbs,
size_t cleaning_cycle)
: dbms(dbs), cleaning_cycle(cleaning_cycle) {
// Start the cleaning thread
cleaners.push_back(
std::make_unique<Thread>([&, cleaning_cycle = cleaning_cycle ]() {
Logger logger = logging::log->logger("Cleaner");
logger.info("Started with cleaning cycle of {} sec", cleaning_cycle);
std::time_t last_clean = std::time(nullptr);
while (cleaning.load(std::memory_order_acquire)) {
std::time_t now = std::time(nullptr);
// Maybe it's cleaning time.
if (now >= last_clean + cleaning_cycle) {
logger.info("Started cleaning cyle");
// Clean all databases
for (auto &db : dbs.access()) {
logger.info("Cleaning database \"{}\"", db.first);
DbTransaction t(db.second);
try {
logger.info("Cleaning edges");
t.clean_edge_section();
logger.info("Cleaning vertices");
t.clean_vertex_section();
logger.info("Cleaning garbage");
db.second.garbage.clean();
} catch (const std::exception &e) {
logger.error("Error occured while cleaning database \"{}\"",
db.first);
logger.error("{}", e.what());
}
// NOTE: Whe should commit even if error occured.
t.trans.commit();
}
last_clean = now;
logger.info("Finished cleaning cyle");
} else {
// Cleaning isn't scheduled for now so i should sleep.
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
}));
}
Cleaning::~Cleaning() {
// Stop cleaning
cleaning.store(false, std::memory_order_release);
for (auto &t : cleaners) {
// Join with cleaners
t.get()->join();
}
}

View File

@ -1,26 +0,0 @@
#pragma once
#include "database/graph_db.hpp"
#include "threading/thread.hpp"
class Thread;
class Cleaning {
public:
// How much sec is a cleaning_cycle in which cleaner will clean at most
// once. Starts cleaner thread.
Cleaning(ConcurrentMap<std::string, GraphDb> &dbs, size_t cleaning_cycle);
// Destroys this object after this thread joins cleaning thread.
~Cleaning();
private:
ConcurrentMap<std::string, GraphDb> &dbms;
const size_t cleaning_cycle;
std::vector<std::unique_ptr<Thread>> cleaners;
// Should i continue cleaning.
std::atomic<bool> cleaning = {true};
};

View File

@ -57,13 +57,4 @@ class Dbms {
// currently active database
std::atomic<GraphDb *> active_db;
// // Cleaning thread.
// TODO re-enable cleaning
// Cleaning cleaning = {dbs, CONFIG_INTEGER(config::CLEANING_CYCLE_SEC)};
//
// // Snapshoting thread.
// TODO re-enable cleaning
// Snapshoter snapshoter = {dbs,
// CONFIG_INTEGER(config::SNAPSHOT_CYCLE_SEC)};
};

View File

@ -2,7 +2,7 @@
#include "io/network/stream_buffer.hpp"
#include "io/network/stream_listener.hpp"
#include "memory/literals.hpp"
#include "utils/memory_literals.hpp"
namespace io::network {

View File

@ -1,25 +0,0 @@
#pragma once
#include "recycler.hpp"
template <class T, class Allocator>
class DeferredRecycler : Recycler<T, Allocator> {
public:
using Recycler<T, Allocator>::acquire;
void recycle(T* item) {
auto guard = this->acquire_unique();
dirty.push_back(item);
}
void clean() {
auto guard = this->acquire_unique();
for (auto item : dirty) this->recycle_or_delete(item);
dirty.clear();
}
private:
std::queue<T*> dirty;
};

View File

@ -1,22 +0,0 @@
#pragma once
#include <vector>
#include "threading/sync/lockable.hpp"
#include "threading/sync/spinlock.hpp"
template <class T, class lock_t = SpinLock>
class FreeList : Lockable<lock_t> {
public:
void swap(std::vector<T> &dst) { std::swap(data, dst); }
void add(T element) {
auto lock = this->acquire_unique();
data.emplace_back(element);
}
size_t size() const { return data.size(); }
private:
std::vector<T> data;
};

View File

@ -1,24 +0,0 @@
#pragma once
// TODO: remove from here and from the project
#include <atomic>
#include <iostream>
#include "threading/sync/lockable.hpp"
#include "utils/crtp.hpp"
template <class Derived, class lock_t = SpinLock>
class LazyGC : public Crtp<Derived>, public Lockable<lock_t> {
public:
// AddRef method should be called by a thread
// when the thread has to do something over
// object which has to be lazy cleaned when
// the thread finish it job
void AddRef() {
auto lock = this->acquire_unique();
++reference_count_;
}
protected:
size_t reference_count_{0};
};

View File

@ -1,41 +0,0 @@
#pragma once
#include <atomic>
#include <mutex>
#include "storage/model/edge.hpp"
#include "storage/model/record.hpp"
#include "storage/model/vertex.hpp"
// TODO implement the memory engine using the allocator style allocation to
// make this class non-dependent on the memory allocation strategy
// TODO implement real recycling of vertices and edges to improve performance
class MemoryEngine {
public:
template <class T, typename... Args>
T* create(Args&&... args) {
return new T(std::forward<Args>(args)...);
}
template <class T>
T* allocate() {
return static_cast<T*>(malloc(sizeof(T)));
}
template <class T>
void recycle(Record<T>* record) {
recycle(&record->derived());
}
void recycle(Vertex* v) { delete v; }
void recycle(Edge* e) { delete e; }
private:
std::unique_lock<SpinLock> acquire() {
return std::unique_lock<SpinLock>(lock);
}
SpinLock lock;
};

View File

@ -1,41 +0,0 @@
#pragma once
#include <memory>
#include <queue>
#include "threading/sync/lockable.hpp"
#include "threading/sync/spinlock.hpp"
template <class T, class Allocator = std::allocator<T>>
class Recycler : public Lockable<SpinLock> {
static constexpr size_t default_max_reserved = 100;
public:
Recycler() = default;
Recycler(size_t max_reserved) : max_reserved(max_reserved) {}
template <class... Args>
T* acquire(Args&&... args) {
auto guard = acquire_unique();
return fetch_or_create(std::forward<Args>(args)...);
}
void release(T* item) {
auto guard = acquire_unique();
return recycle_or_delete(item);
}
protected:
Allocator alloc;
size_t max_reserved{default_max_reserved};
std::queue<T*> items;
template <class... Args>
T* fetch_or_create(Args&&... args) {
return new T(std::forward<Args>(args)...); // todo refactor :D
}
void recycle_or_delete(T* item) {
delete item; // todo refactor :D
}
};

View File

@ -2,7 +2,6 @@
#include <shared_mutex>
#include "memory/lazy_gc.hpp"
#include "storage/locking/record_lock.hpp"
#include "threading/sync/lockable.hpp"
#include "transactions/transaction.hpp"

View File

@ -1,32 +0,0 @@
#pragma once
#include <atomic>
#include <condition_variable>
#include <future>
#include <mutex>
#include <queue>
#include "threading/pool.hpp"
/**
* @brief - Singleton class which implements thread pool.
*/
class GlobalPool {
public:
// Guaranteed by the C++11 standard to be thread-safe.
static GlobalPool *getSingletonInstance() {
static GlobalPool instance;
return &instance;
}
void run(Pool::task_t f) { thread_pool_.run(f); }
GlobalPool(const GlobalPool &) = delete;
GlobalPool(const GlobalPool &&) = delete;
GlobalPool operator=(const GlobalPool &) = delete;
GlobalPool operator=(const GlobalPool &&) = delete;
private:
GlobalPool() {}
Pool thread_pool_;
};

View File

@ -24,11 +24,7 @@ namespace traversal_template {
* it is mentioned that Vertex uniqueness can result in exponential performance
* degradation. Figure out why and how.
*/
enum class Uniqueness {
None,
Vertex,
Edge
};
enum class Uniqueness { None, Vertex, Edge };
/**
* Indicates how a path should be expanded using the traversal API. For the
@ -47,14 +43,13 @@ enum class Uniqueness {
*
* Note that this implies that a Path has direction (start and finish).
*/
enum class Expansion {
Front,
Back
};
enum class Expansion { Front, Back };
/**
* Indicates which relationships from the expansion vertex should be used to expand
* the path. Direction::In means that incoming relationships are used for expansion.
* Indicates which relationships from the expansion vertex should be used to
* expand
* the path. Direction::In means that incoming relationships are used for
* expansion.
*
* For example, for the given graph data:
*
@ -64,13 +59,10 @@ enum class Expansion {
*
* p = (b)
*
* Expansion (let's assume Expansion::Back) in the Direction::In would result in:
* Expansion (let's assume Expansion::Back) in the Direction::In would result
* in:
*
* q = (b)<-[]-(a)
*/
enum class Direction {
In,
Out,
Both
};
enum class Direction { In, Out, Both };
}

View File

@ -5,9 +5,9 @@
#pragma once
#include <list>
#include <algorithm>
#include <functional>
#include <list>
#include "enums.hpp"
#include "utils/assert.hpp"
@ -26,23 +26,19 @@ namespace traversal_template {
* @tparam TVertex
* @tparam TEdge
*/
template<typename TVertex, typename TEdge>
template <typename TVertex, typename TEdge>
class Path {
public:
public:
Path() {}
size_t Size() const {
return vertices_.size();
}
size_t Size() const { return vertices_.size(); }
friend std::ostream &operator<<(std::ostream &stream, const Path &path) {
auto vertices_it = path.vertices_.begin();
auto vertices_end = path.vertices_.end();
auto edges_it = path.edges_.begin();
if (vertices_it != vertices_end)
stream << *vertices_it++;
if (vertices_it != vertices_end) stream << *vertices_it++;
while (vertices_it != vertices_end)
@ -67,7 +63,8 @@ public:
* @return A reference to this same path.
*/
Path &Start(const TVertex &v) {
debug_assert(vertices_.size() == 0, "Can only start iteration on empty path");
debug_assert(vertices_.size() == 0,
"Can only start iteration on empty path");
vertices_.push_back(v);
return *this;
}
@ -96,7 +93,8 @@ public:
* Gets the last Vertex of this path. Fails if the path contains no elements.
*/
const TVertex &Back() const {
debug_assert(vertices_.size() > 0, "Can only get a Vertex on non-empty path");
debug_assert(vertices_.size() > 0,
"Can only get a Vertex on non-empty path");
return vertices_.back();
}
@ -116,21 +114,23 @@ public:
}
/**
* Removes the last element from the path. Fails if the path contains no elements.
* Removes the last element from the path. Fails if the path contains no
* elements.
*/
void PopBack() {
debug_assert(vertices_.size() > 0, "Can only remove a vertex from a non-empty path");
debug_assert(vertices_.size() > 0,
"Can only remove a vertex from a non-empty path");
vertices_.pop_back();
if (vertices_.size() > 0)
edges_.pop_back();
if (vertices_.size() > 0) edges_.pop_back();
}
/**
* Gets the first Vertex of this path. Fails if the path contains no elements.
*/
const TVertex &Front() const {
debug_assert(vertices_.size() > 0, "Can only get a vertex from a non-empty path");
debug_assert(vertices_.size() > 0,
"Can only get a vertex from a non-empty path");
return vertices_.front();
}
@ -148,14 +148,15 @@ public:
}
/**
* Removes the first element from the path. Fails if the path contains no elements.
* Removes the first element from the path. Fails if the path contains no
* elements.
*/
void PopFront() {
debug_assert(vertices_.size() > 0, "Can only remove a vertex from a non-empty path");
debug_assert(vertices_.size() > 0,
"Can only remove a vertex from a non-empty path");
vertices_.pop_front();
if (vertices_.size() > 0)
edges_.pop_front();
if (vertices_.size() > 0) edges_.pop_front();
}
/**
@ -176,7 +177,7 @@ public:
*/
const auto &Edges() const { return edges_; }
private:
private:
std::list<TVertex> vertices_;
std::list<TEdge> edges_;
};
@ -192,7 +193,8 @@ private:
template <typename TVertex, typename TEdge>
class Paths : public std::list<std::reference_wrapper<Path<TVertex, TEdge>>> {
using Path = Path<TVertex, TEdge>;
public:
public:
bool operator==(const Paths<TVertex, TEdge> &other) const {
return std::equal(this->begin(), this->end(), other.begin(),
[](const std::reference_wrapper<Path> &p1,
@ -201,7 +203,7 @@ public:
});
}
bool operator!=(const Paths &other) const { return !(*this == other);}
bool operator!=(const Paths &other) const { return !(*this == other); }
friend std::ostream &operator<<(std::ostream &stream, const Paths &paths) {
stream << "[";
@ -214,4 +216,3 @@ public:
}
};
}

View File

@ -5,14 +5,13 @@
#pragma once
#include <list>
#include <functional>
#include <list>
#include "enums.hpp"
#include "path.hpp"
#include "utils/assert.hpp"
/**
* This namespace contains traversal class templates that must
* be parameterized with Vertex and Edge classes. This abstraction
@ -49,8 +48,7 @@ namespace traversal_template {
*/
template <typename TVertex, typename TEdge>
class UniquenessGroup {
public:
public:
UniquenessGroup(const Path<TVertex, TEdge> &path) : current_path_(path) {}
/**
@ -61,12 +59,10 @@ public:
* @return
*/
bool Contains(const TVertex &vertex) const {
if (current_path_.Contains(vertex))
return true;
if (current_path_.Contains(vertex)) return true;
for (const auto &group : subgroups_)
if (group.get().Contains(vertex))
return true;
if (group.get().Contains(vertex)) return true;
return false;
}
@ -79,12 +75,10 @@ public:
* @return
*/
bool Contains(const TEdge &edge) const {
if (current_path_.Contains(edge))
return true;
if (current_path_.Contains(edge)) return true;
for (const auto &group : subgroups_)
if (group.get().Contains(edge))
return true;
if (group.get().Contains(edge)) return true;
return false;
}
@ -95,14 +89,17 @@ public:
*
* @param subgroup
*/
void Add(const UniquenessGroup<TVertex, TEdge> &subgroup) { subgroups_.emplace_back(subgroup); }
void Add(const UniquenessGroup<TVertex, TEdge> &subgroup) {
subgroups_.emplace_back(subgroup);
}
private:
private:
// the currently traversed path of this uniqueness group
// set by the BeginType
const Path<TVertex, TEdge> &current_path_;
std::vector<std::reference_wrapper<const UniquenessGroup<TVertex, TEdge>>> subgroups_;
std::vector<std::reference_wrapper<const UniquenessGroup<TVertex, TEdge>>>
subgroups_;
};
/**
@ -116,14 +113,13 @@ private:
* @tparam TVertex
* @tparam TEdge
*/
template<typename TVisitable, typename TVertex, typename TEdge>
template <typename TVisitable, typename TVertex, typename TEdge>
class ExpandBaseType {
using TPath = Path<TVertex, TEdge>;
using VertexFilter = std::function<bool(const TVertex &)>;
using EdgeFilter = std::function<bool(const TEdge &)>;
public:
public:
/**
* @return This expander's visitable's uniqueness group.
*/
@ -131,8 +127,7 @@ public:
return visitable_.UniquenessGroup();
}
protected:
protected:
// tracking last appended path elements during traversal
TVertex const *current_vertex_ = nullptr;
TEdge const *current_edge_ = nullptr;
@ -161,18 +156,15 @@ protected:
* provided).
* @param uniqueness Which kind of uniqueness should be applied.
*/
ExpandBaseType(TVisitable &&visitable,
Expansion expansion,
Direction direction,
VertexFilter vertex_filter,
EdgeFilter edge_filter,
Uniqueness uniqueness
) : visitable_(std::forward<TVisitable>(visitable)),
expansion_(expansion),
direction_(direction),
vertex_filter_(vertex_filter),
edge_filter_(edge_filter),
uniqueness_(uniqueness) {}
ExpandBaseType(TVisitable &&visitable, Expansion expansion,
Direction direction, VertexFilter vertex_filter,
EdgeFilter edge_filter, Uniqueness uniqueness)
: visitable_(std::forward<TVisitable>(visitable)),
expansion_(expansion),
direction_(direction),
vertex_filter_(vertex_filter),
edge_filter_(edge_filter),
uniqueness_(uniqueness) {}
/**
* Visits the given visitor with every expansion of the given path
@ -183,9 +175,9 @@ protected:
* @param p
*/
void VisitExpansions(std::function<void(TPath &)> visitor, TPath &p) {
// the start or end point of the vertex
const auto &origin_vertex = expansion_ == Expansion::Back ? p.Back() : p.Front();
const auto &origin_vertex =
expansion_ == Expansion::Back ? p.Back() : p.Front();
if (direction_ == Direction::In || direction_ == Direction::Both)
VisitExpansions(origin_vertex.in(), p, visitor, Direction::In);
@ -193,7 +185,7 @@ protected:
VisitExpansions(origin_vertex.out(), p, visitor, Direction::Out);
}
private:
private:
/**
* Helper method that handles path expansion and visiting w.r.t.
* expansion params.
@ -209,21 +201,21 @@ private:
* @param visitor
* @param direction
*/
template<typename Edges>
void VisitExpansions(Edges &edges,
TPath &p,
template <typename Edges>
void VisitExpansions(Edges &edges, TPath &p,
std::function<void(TPath &)> visitor,
Direction direction) {
for (const TEdge &e : edges) {
// edge filtering and uniqueness
if (edge_filter_ && !edge_filter_(e)) continue;
if (uniqueness_ == Uniqueness::Edge && UniquenessGroup().Contains(e)) continue;
if (uniqueness_ == Uniqueness::Edge && UniquenessGroup().Contains(e))
continue;
// vertex filtering and uniqueness
const TVertex &v = (direction == Direction::In) ? e.from() : e.to();
if (vertex_filter_ && !vertex_filter_(v)) continue;
if (uniqueness_ == Uniqueness::Vertex && UniquenessGroup().Contains(v))continue;
if (uniqueness_ == Uniqueness::Vertex && UniquenessGroup().Contains(v))
continue;
current_edge_ = &e;
current_vertex_ = &v;
@ -257,15 +249,13 @@ private:
* @tparam TVertex
* @tparam TEdge
*/
template<typename TVisitable, typename TVertex, typename TEdge>
template <typename TVisitable, typename TVertex, typename TEdge>
class ExpandVariableType : public ExpandBaseType<TVisitable, TVertex, TEdge> {
using TPath = Path<TVertex, TEdge>;
using VertexFilter = std::function<bool(const TVertex &)>;
using EdgeFilter = std::function<bool(const TEdge &)>;
public:
public:
/**
* For most params see the ExpandBaseType::ExpandBaseType documentation.
*
@ -274,30 +264,26 @@ public:
* @param max_length Maximum number of vertices in a path for it to be
* visited. Exclusive.
*/
ExpandVariableType(TVisitable &&visitable,
Expansion expansion,
Direction direction,
VertexFilter vertex_filter,
EdgeFilter edge_filter,
int min_length,
int max_length,
Uniqueness uniqueness) :
ExpandBaseType<TVisitable, TVertex, TEdge>(std::forward<TVisitable>(visitable),
expansion, direction, {}, edge_filter, uniqueness),
min_length_(min_length),
max_length_(max_length),
current_vertex_filter_(vertex_filter) {
}
ExpandVariableType(TVisitable &&visitable, Expansion expansion,
Direction direction, VertexFilter vertex_filter,
EdgeFilter edge_filter, int min_length, int max_length,
Uniqueness uniqueness)
: ExpandBaseType<TVisitable, TVertex, TEdge>(
std::forward<TVisitable>(visitable), expansion, direction, {},
edge_filter, uniqueness),
min_length_(min_length),
max_length_(max_length),
current_vertex_filter_(vertex_filter) {}
/**
* Calls the given visitor function once for every path this traversal generates.
* Calls the given visitor function once for every path this traversal
* generates.
*
* @param visitor
*/
void Visit(std::function<void(TPath &)> visitor) {
this->visitable_.Visit([this, &visitor](TPath &p) {
VisitRecursive(visitor, p, p.Size());
});
this->visitable_.Visit(
[this, &visitor](TPath &p) { VisitRecursive(visitor, p, p.Size()); });
}
/**
@ -306,10 +292,8 @@ public:
*
* @return An expansion that generates paths one traversal longer.
*/
auto Expand(Expansion expansion,
Direction direction,
VertexFilter vertex_filter = {},
EdgeFilter edge_filter = {});
auto Expand(Expansion expansion, Direction direction,
VertexFilter vertex_filter = {}, EdgeFilter edge_filter = {});
/**
* Expands from this expansion along a variable number traversal.
@ -317,13 +301,10 @@ public:
*
* @return An expansion that generates paths variable length longer.
*/
auto ExpandVariable(
Expansion expansion,
Direction direction,
VertexFilter vertex_filter = {},
EdgeFilter edge_filter = {},
int min_length = 0,
int max_length = 1000);
auto ExpandVariable(Expansion expansion, Direction direction,
VertexFilter vertex_filter = {},
EdgeFilter edge_filter = {}, int min_length = 0,
int max_length = 1000);
/**
* Returns a reference to the vertex currently being traversed
@ -331,7 +312,9 @@ public:
* TRAVERSAL!!!
*/
const TVertex &CurrentVertex() const {
debug_assert(this->current_vertex_ != nullptr, "Current vertex not set, function most likely called outside of traversal");
debug_assert(this->current_vertex_ != nullptr,
"Current vertex not set, function most likely called outside "
"of traversal");
return *this->current_vertex_;
}
@ -341,18 +324,22 @@ public:
* TRAVERSAL!!!
*/
const std::list<TEdge> &CurrentEdges() const {
debug_assert(this->current_edge_ != nullptr, "Current edge not set, function most likely called outside of traversal");
debug_assert(this->current_edge_ != nullptr,
"Current edge not set, function most likely called outside of "
"traversal");
return current_edges_;
}
private:
private:
// see constructor documentation for member var explanation
const int min_length_;
const int max_length_;
// the expand variable has another vertex filter used only on the last path element
// the expand variable has another vertex filter used only on the last path
// element
// because traversal is done recursively using superclass functionality,
// so we give an empty filter to superclass so it does not end traversal, and use
// so we give an empty filter to superclass so it does not end traversal, and
// use
// this filter to see if we actually need to visit the path or not
const VertexFilter current_vertex_filter_;
@ -369,22 +356,25 @@ private:
* @param p_start_size The size of the path before variable-length expansion.
* It's necessary to keep track of it because min and max length are
* evaluated against how much this traversal generated, not against the
* actual path length (there could have been plan expansions before this variable length).
* actual path length (there could have been plan expansions before this
* variable length).
*/
void VisitRecursive(std::function<void(TPath &)> visitor, TPath &p, const size_t p_start_size) {
debug_assert(p.Size() >= p_start_size, "Current path must be greater then start size");
void VisitRecursive(std::function<void(TPath &)> visitor, TPath &p,
const size_t p_start_size) {
debug_assert(p.Size() >= p_start_size,
"Current path must be greater then start size");
size_t recursion_size = p.Size() - p_start_size;
// only append to current_edges once the first traversal happened
if (recursion_size > 0)
current_edges_.emplace_back(*this->current_edge_);
if (recursion_size > 0) current_edges_.emplace_back(*this->current_edge_);
if (recursion_size >= min_length_ && (!current_vertex_filter_ || current_vertex_filter_(*this->current_vertex_)))
if (recursion_size >= min_length_ &&
(!current_vertex_filter_ ||
current_vertex_filter_(*this->current_vertex_)))
visitor(p);
if (recursion_size >= max_length_ - 1)
return;
if (recursion_size >= max_length_ - 1) return;
// a lambda we'll inject to ExpandVisit, that calls this function
// with the expanded path
@ -394,8 +384,7 @@ private:
this->VisitExpansions(recursive_visitor, p);
if (recursion_size > 0)
current_edges_.pop_back();
if (recursion_size > 0) current_edges_.pop_back();
}
};
@ -409,36 +398,32 @@ private:
* @tparam TVertex
* @tparam TEdge
*/
template<typename TVisitable, typename TVertex, typename TEdge>
template <typename TVisitable, typename TVertex, typename TEdge>
class ExpandType : public ExpandBaseType<TVisitable, TVertex, TEdge> {
using TPath = Path<TVertex, TEdge>;
using VertexFilter = std::function<bool(const TVertex &)>;
using EdgeFilter = std::function<bool(const TEdge &)>;
public:
public:
/**
* For all params see the ExpandBaseType::ExpandBaseType documentation.
*/
ExpandType(TVisitable &&visitable,
Expansion expansion,
Direction direction,
VertexFilter vertex_filter,
EdgeFilter edge_filter,
Uniqueness uniqueness) :
ExpandBaseType<TVisitable, TVertex, TEdge>(std::forward<TVisitable>(visitable),
expansion, direction, vertex_filter, edge_filter, uniqueness) {}
ExpandType(TVisitable &&visitable, Expansion expansion, Direction direction,
VertexFilter vertex_filter, EdgeFilter edge_filter,
Uniqueness uniqueness)
: ExpandBaseType<TVisitable, TVertex, TEdge>(
std::forward<TVisitable>(visitable), expansion, direction,
vertex_filter, edge_filter, uniqueness) {}
/**
* Calls the given visitor function once for every path this traversal generates.
* Calls the given visitor function once for every path this traversal
* generates.
*
* @param visitor
*/
void Visit(std::function<void(TPath &)> visitor) {
this->visitable_.Visit([this, &visitor](TPath &p) {
this->VisitExpansions(visitor, p);
});
this->visitable_.Visit(
[this, &visitor](TPath &p) { this->VisitExpansions(visitor, p); });
}
/**
@ -447,7 +432,9 @@ public:
* TRAVERSAL!!!
*/
const TVertex &CurrentVertex() const {
debug_assert(this->current_vertex_ != nullptr, "Current vertex not set, function most likely called outside of traversal");
debug_assert(this->current_vertex_ != nullptr,
"Current vertex not set, function most likely called outside "
"of traversal");
return *this->current_vertex_;
}
@ -457,7 +444,9 @@ public:
* TRAVERSAL!!!
*/
const TEdge &CurrentEdge() const {
debug_assert(this->current_edge_ != nullptr, "Current edge not set, function most likely called outside of traversal");
debug_assert(this->current_edge_ != nullptr,
"Current edge not set, function most likely called outside of "
"traversal");
return *this->current_edge_;
}
@ -467,12 +456,11 @@ public:
*
* @return An expansion that generates paths one traversal longer.
*/
auto Expand(Expansion expansion,
Direction direction,
VertexFilter vertex_filter = {},
EdgeFilter edge_filter = {}) {
auto Expand(Expansion expansion, Direction direction,
VertexFilter vertex_filter = {}, EdgeFilter edge_filter = {}) {
return ExpandType<ExpandType<TVisitable, TVertex, TEdge> &, TVertex, TEdge>(
*this, expansion, direction, vertex_filter, edge_filter, this->uniqueness_);
*this, expansion, direction, vertex_filter, edge_filter,
this->uniqueness_);
}
/**
@ -481,15 +469,14 @@ public:
*
* @return An expansion that generates paths variable length longer.
*/
auto ExpandVariable(
Expansion expansion,
Direction direction,
VertexFilter vertex_filter = {},
EdgeFilter edge_filter = {},
int min_length = 0,
int max_length = 1000) {
return ExpandVariableType<const ExpandType<TVisitable, TVertex, TEdge> &, TVertex, TEdge>(
*this, expansion, direction, vertex_filter, edge_filter, min_length, max_length, this->uniqueness_);
auto ExpandVariable(Expansion expansion, Direction direction,
VertexFilter vertex_filter = {},
EdgeFilter edge_filter = {}, int min_length = 0,
int max_length = 1000) {
return ExpandVariableType<const ExpandType<TVisitable, TVertex, TEdge> &,
TVertex, TEdge>(
*this, expansion, direction, vertex_filter, edge_filter, min_length,
max_length, this->uniqueness_);
}
};
@ -500,17 +487,17 @@ public:
* @tparam TVertex
* @tparam TEdge
*/
template<typename TIterable, typename TVertex, typename TEdge>
template <typename TIterable, typename TVertex, typename TEdge>
class BeginType {
using TPath = Path<TVertex, TEdge>;
using VertexFilter = std::function<bool(const TVertex &)>;
using EdgeFilter = std::function<bool(const TEdge &)>;
public:
BeginType(const TIterable &vertices, VertexFilter vertex_filter) :
vertices_(vertices), vertex_filter_(vertex_filter), uniqueness_group_(path) {}
public:
BeginType(const TIterable &vertices, VertexFilter vertex_filter)
: vertices_(vertices),
vertex_filter_(vertex_filter),
uniqueness_group_(path) {}
/**
* Calls the visitor with a path containing a single vertex
@ -521,9 +508,7 @@ public:
*/
void Visit(std::function<void(TPath &)> visitor) {
for (const TVertex &v : vertices_) {
if (vertex_filter_ && !vertex_filter_(v))
continue;
if (vertex_filter_ && !vertex_filter_(v)) continue;
path.Start(v);
visitor(path);
@ -531,7 +516,6 @@ public:
}
}
/**
* The UniquenessGroup of this BeginType (the only one that
* exists for all the expansions from this Begin).
@ -546,7 +530,9 @@ public:
* TRAVERSAL!!!
*/
const TVertex &CurrentVertex() const {
debug_assert(path.Size() > 0, "Current path is empty, function most likely called outside of traversal");
debug_assert(path.Size() > 0,
"Current path is empty, function most likely called outside "
"of traversal");
return path.Front();
}
@ -556,10 +542,8 @@ public:
*
* @return An expansion that generates paths one traversal longer.
*/
auto Expand(Expansion expansion,
Direction direction,
VertexFilter vertex_filter = {},
EdgeFilter edge_filter = {},
auto Expand(Expansion expansion, Direction direction,
VertexFilter vertex_filter = {}, EdgeFilter edge_filter = {},
Uniqueness uniqueness = Uniqueness::Edge) {
return ExpandType<BeginType<TIterable, TVertex, TEdge> &, TVertex, TEdge>(
*this, expansion, direction, vertex_filter, edge_filter, uniqueness);
@ -571,21 +555,21 @@ public:
*
* @return An expansion that generates paths variable length longer.
*/
auto ExpandVariable(
Expansion expansion,
Direction direction,
VertexFilter vertex_filter = {},
EdgeFilter edge_filter = {},
int min_length = 1,
int max_length = 1000,
Uniqueness uniqueness = Uniqueness::Edge) {
return ExpandVariableType<BeginType<TIterable, TVertex, TEdge> &, TVertex, TEdge>(
*this, expansion, direction, vertex_filter, edge_filter, min_length, max_length, uniqueness);
auto ExpandVariable(Expansion expansion, Direction direction,
VertexFilter vertex_filter = {},
EdgeFilter edge_filter = {}, int min_length = 1,
int max_length = 1000,
Uniqueness uniqueness = Uniqueness::Edge) {
return ExpandVariableType<BeginType<TIterable, TVertex, TEdge> &, TVertex,
TEdge>(*this, expansion, direction, vertex_filter,
edge_filter, min_length, max_length,
uniqueness);
}
private:
private:
const TIterable &vertices_;
// the BeingType has only one path that gets appended to and emitted to visitors
// the BeingType has only one path that gets appended to and emitted to
// visitors
TPath path;
const VertexFilter vertex_filter_;
// TODO review: why do I have to have namespace:: here???
@ -601,7 +585,7 @@ private:
*
* @return A BeginType.
*/
template<typename TIterable, typename TVertex, typename TEdge>
template <typename TIterable, typename TVertex, typename TEdge>
auto Begin(const TIterable &vertices,
std::function<bool(const TVertex &)> vertex_filter = {}) {
return BeginType<TIterable, TVertex, TEdge>(vertices, vertex_filter);
@ -610,14 +594,14 @@ auto Begin(const TIterable &vertices,
/**
* Creates a start point for a recursion of Cartesian wrappers.
*/
template<typename TVisitable, typename TVertex, typename TEdge>
template <typename TVisitable, typename TVertex, typename TEdge>
class CartesianUnaryType {
using TPath = Path<TVertex, TEdge>;
using TPaths = Paths<TVertex, TEdge>;
public:
CartesianUnaryType(TVisitable &&visitable) :
visitable_(std::forward<TVisitable>(visitable)) {}
public:
CartesianUnaryType(TVisitable &&visitable)
: visitable_(std::forward<TVisitable>(visitable)) {}
void Visit(std::function<void(TPaths &)> visitor) const {
TPaths paths;
@ -628,29 +612,35 @@ public:
});
}
private:
private:
const TVisitable visitable_;
};
/**
* Provides means to visit a cartesian product of traversals.
*
* @tparam TVisitableFirst A visitable whose visitor accepts a list of path reference (recursion down).
* @tparam TVisitableOthers Visitables whose visitor accepts a single path reference.
* @tparam TVisitableFirst A visitable whose visitor accepts a list of path
* reference (recursion down).
* @tparam TVisitableOthers Visitables whose visitor accepts a single path
* reference.
*/
template<typename TVisitableFirst, typename TVisitableOthers, typename TVertex, typename TEdge>
template <typename TVisitableFirst, typename TVisitableOthers, typename TVertex,
typename TEdge>
class CartesianBinaryType {
using TPath = Path<TVertex, TEdge>;
using TPaths = Paths<TVertex, TEdge>;
public:
public:
/**
* @tparam visitable_first A visitable whose visitor accepts a list of path reference (recursion down).
* @tparam visitable_others Visitable whose visitor accepts a single path reference.
* @tparam visitable_first A visitable whose visitor accepts a list of path
* reference (recursion down).
* @tparam visitable_others Visitable whose visitor accepts a single path
* reference.
*/
CartesianBinaryType(TVisitableFirst &&visitable_first, TVisitableOthers &&visitable_others) :
visitable_first_(std::forward<TVisitableFirst>(visitable_first)),
visitable_others_(std::forward<TVisitableOthers>(visitable_others)) {}
CartesianBinaryType(TVisitableFirst &&visitable_first,
TVisitableOthers &&visitable_others)
: visitable_first_(std::forward<TVisitableFirst>(visitable_first)),
visitable_others_(std::forward<TVisitableOthers>(visitable_others)) {}
/**
* Calls the given visitor with a list of reference wrappers to Paths
@ -659,7 +649,6 @@ public:
* @param visitor
*/
void Visit(std::function<void(TPaths &)> visitor) const {
// TODO currently cartesian product does NOT check for uniqueness
// for example between edges in the emitted path combinations
@ -672,14 +661,15 @@ public:
});
}
private:
private:
const TVisitableFirst visitable_first_;
const TVisitableOthers visitable_others_;
};
/**
* Creates an object that can be visited with a function that accepts a list
* of path reference wrappers. That function will be called one for every element
* of path reference wrappers. That function will be called one for every
* element
* of a cartesian product of the given visitables (that emit paths).
*
* @tparam TVisitableFirst A visitable that emits paths.
@ -688,15 +678,16 @@ private:
* @param others An arbitrary number of visitables that emit paths.
* @return See above.
*/
template<typename TVisitable, typename TVertex, typename TEdge>
template <typename TVisitable, typename TVertex, typename TEdge>
auto Cartesian(TVisitable &&visitable) {
return CartesianUnaryType<TVisitable, TVertex, TEdge>(std::forward<TVisitable>(visitable));
return CartesianUnaryType<TVisitable, TVertex, TEdge>(
std::forward<TVisitable>(visitable));
}
/**
* Creates an object that can be visited with a function that accepts a list
* of path reference wrappers. That function will be called one for every element
* of path reference wrappers. That function will be called one for every
* element
* of a cartesian product of the given visitables (that emit paths).
*
* @tparam TVisitableFirst A visitable that emits paths.
@ -705,34 +696,32 @@ auto Cartesian(TVisitable &&visitable) {
* @param others An arbitrary number of visitables that emit paths.
* @return See above.
*/
template<typename TVisitableFirst, typename Vertex, typename Edge, typename... TVisitableOthers>
template <typename TVisitableFirst, typename Vertex, typename Edge,
typename... TVisitableOthers>
auto Cartesian(TVisitableFirst &&first, TVisitableOthers &&... others) {
return CartesianBinaryType<TVisitableFirst, decltype(Cartesian(std::forward<TVisitableOthers>(others)...)),
Vertex, Edge>(
std::forward<TVisitableFirst>(first),
Cartesian(std::forward<TVisitableOthers>(others)...)
);
return CartesianBinaryType<
TVisitableFirst,
decltype(Cartesian(std::forward<TVisitableOthers>(others)...)), Vertex,
Edge>(std::forward<TVisitableFirst>(first),
Cartesian(std::forward<TVisitableOthers>(others)...));
}
template<typename TVisitable, typename TVertex, typename TEdge>
auto ExpandVariableType<TVisitable, TVertex, TEdge>::Expand(Expansion expansion,
Direction direction,
VertexFilter vertex_filter,
EdgeFilter edge_filter) {
return ExpandType<ExpandVariableType<TVisitable, TVertex, TEdge> &, TVertex, TEdge>(
*this, expansion, direction, vertex_filter, edge_filter, this->uniqueness_);
template <typename TVisitable, typename TVertex, typename TEdge>
auto ExpandVariableType<TVisitable, TVertex, TEdge>::Expand(
Expansion expansion, Direction direction, VertexFilter vertex_filter,
EdgeFilter edge_filter) {
return ExpandType<ExpandVariableType<TVisitable, TVertex, TEdge> &, TVertex,
TEdge>(*this, expansion, direction, vertex_filter,
edge_filter, this->uniqueness_);
}
template<typename TVisitable, typename TVertex, typename TEdge>
template <typename TVisitable, typename TVertex, typename TEdge>
auto ExpandVariableType<TVisitable, TVertex, TEdge>::ExpandVariable(
Expansion expansion,
Direction direction,
VertexFilter vertex_filter,
EdgeFilter edge_filter,
int min_length,
int max_length) {
return ExpandVariableType<ExpandVariableType<TVisitable, TVertex, TEdge> &, TVertex, TEdge>(
*this, expansion, direction, vertex_filter, edge_filter, min_length, max_length, this->uniqueness_);
Expansion expansion, Direction direction, VertexFilter vertex_filter,
EdgeFilter edge_filter, int min_length, int max_length) {
return ExpandVariableType<ExpandVariableType<TVisitable, TVertex, TEdge> &,
TVertex, TEdge>(
*this, expansion, direction, vertex_filter, edge_filter, min_length,
max_length, this->uniqueness_);
}
}

View File

@ -9,8 +9,8 @@
#include "path.hpp"
#include "templates.hpp"
#include "storage/vertex_accessor.hpp"
#include "storage/edge_accessor.hpp"
#include "storage/vertex_accessor.hpp"
/**
* A specialization of the "traversal" namespace that uses
@ -25,34 +25,36 @@ using Paths = traversal_template::Paths<VertexAccessor, EdgeAccessor>;
/**
* Specialization of the traversal_template::Begin function.
*/
template<typename TCollection>
auto Begin(const TCollection &vertices, std::function<bool(const VertexAccessor &)> vertex_filter = {}) {
return traversal_template::Begin<TCollection, VertexAccessor, EdgeAccessor>(vertices, vertex_filter);
template <typename TCollection>
auto Begin(const TCollection &vertices,
std::function<bool(const VertexAccessor &)> vertex_filter = {}) {
return traversal_template::Begin<TCollection, VertexAccessor, EdgeAccessor>(
vertices, vertex_filter);
}
/**
* Specialization of the traversal_template::Cartesian function that accepts
* a single argument.
*/
template<typename TVisitable>
template <typename TVisitable>
auto Cartesian(TVisitable &&visitable) {
return traversal_template::Cartesian<TVisitable, VertexAccessor, EdgeAccessor>(
return traversal_template::Cartesian<TVisitable, VertexAccessor,
EdgeAccessor>(
std::forward<TVisitable>(visitable));
}
/**
* Specialization of the traversal_template::Cartesian function that accepts
* multiple arguments.
*/
template<typename TVisitableFirst, typename... TVisitableOthers>
template <typename TVisitableFirst, typename... TVisitableOthers>
auto Cartesian(TVisitableFirst &&first, TVisitableOthers &&... others) {
return traversal_template::CartesianBinaryType<TVisitableFirst, decltype(Cartesian(
std::forward<TVisitableOthers>(others)...)),
return traversal_template::CartesianBinaryType<
TVisitableFirst,
decltype(Cartesian(std::forward<TVisitableOthers>(others)...)),
VertexAccessor, EdgeAccessor>(
std::forward<TVisitableFirst>(first),
Cartesian(std::forward<TVisitableOthers>(others)...)
);
Cartesian(std::forward<TVisitableOthers>(others)...));
}
}

View File

@ -4,8 +4,6 @@ project(${project_name}_tests)
enable_testing()
include_directories(${catch_source_dir}/include)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/test_results/unit)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/test_results/benchmark)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/test_results/property_based)

View File

@ -11,7 +11,6 @@
#include "data_structures/concurrent/concurrent_map.hpp"
#include "data_structures/concurrent/concurrent_set.hpp"
#include "data_structures/concurrent/skiplist.hpp"
#include "data_structures/static_array.hpp"
#include "utils/assert.hpp"
#include "utils/sysinfo/memory.hpp"
@ -73,7 +72,7 @@ void check_size_list(S &acc, long long size) {
for ([[gnu::unused]] auto elem : acc) {
++iterator_counter;
}
permanent_assert(iterator_counter == size,
permanent_assert(static_cast<int64_t>(iterator_counter) == size,
"Iterator count should be " << size << ", but size is "
<< iterator_counter);
}
@ -91,7 +90,7 @@ void check_size(typename S::Accessor &acc, long long size) {
for ([[gnu::unused]] auto elem : acc) {
++iterator_counter;
}
permanent_assert(iterator_counter == size,
permanent_assert(static_cast<int64_t>(iterator_counter) == size,
"Iterator count should be " << size << ", but size is "
<< iterator_counter);
}
@ -111,7 +110,7 @@ void check_order(typename S::Accessor &acc) {
}
void check_zero(size_t key_range, long array[], const char *str) {
for (int i = 0; i < key_range; i++) {
for (int i = 0; i < static_cast<int>(key_range); i++) {
permanent_assert(array[i] == 0,
str << " doesn't hold it's guarantees. It has " << array[i]
<< " extra elements.");
@ -119,7 +118,7 @@ void check_zero(size_t key_range, long array[], const char *str) {
}
void check_set(DynamicBitset<> &db, std::vector<bool> &set) {
for (int i = 0; i < set.size(); i++) {
for (int i = 0; i < static_cast<int>(set.size()); i++) {
permanent_assert(!(set[i] ^ db.at(i)),
"Set constraints aren't fullfilled.");
}
@ -177,7 +176,7 @@ std::vector<bool> collect_set(
std::vector<bool> set;
for (auto &data : collect(futures)) {
set.resize(data.second.size());
for (int i = 0; i < data.second.size(); i++) {
for (int i = 0; i < static_cast<int>(data.second.size()); i++) {
set[i] = set[i] | data.second[i];
}
}

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t key_range = 1e2;

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t op_per_thread = 1e5;

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 4);
constexpr size_t op_per_thread = 1e5;

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t op_per_thread = 1e5;

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 4);
constexpr size_t op_per_thread = 1e5;

View File

@ -5,7 +5,7 @@
#include <gtest/gtest.h>
#include "utils/assert.hpp"
#include "utils/timer/timer.hpp"
#include "utils/timer.hpp"
using namespace std::chrono_literals;
using namespace utils;

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t elems_per_thread = 100000;

View File

@ -1,19 +1,19 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t elems_per_thread = 1e5;
// TODO: document the test
int main(int argc, char **argv) {
int main(int, char **argv) {
google::InitGoogleLogging(argv[0]);
memory_check(THREADS_NO, [&] {
ds::static_array<std::thread, THREADS_NO> threads;
std::vector<std::thread> threads;
map_t skiplist;
// put THREADS_NO * elems_per_thread items to the skiplist
for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i) {
threads[thread_i] = std::thread(
threads.emplace_back(
[&skiplist](size_t start, size_t end) {
auto accessor = skiplist.access();
for (size_t elem_i = start; elem_i < end; ++elem_i) {
@ -54,8 +54,8 @@ int main(int argc, char **argv) {
// check size
{
auto accessor = skiplist.access();
permanent_assert(accessor.size() == 0,
"Size should be 0, but size is " << accessor.size());
permanent_assert(accessor.size() == 0, "Size should be 0, but size is "
<< accessor.size());
}
// check count

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t elements = 2e6;

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 1);
constexpr size_t elems_per_thread = 16e5;
@ -9,16 +9,16 @@ constexpr size_t elems_per_thread = 16e5;
// 2. analyse this code
// 3. fix the memory leak
// 4. write proper test
int main(int argc, char **argv) {
int main(int, char **argv) {
google::InitGoogleLogging(argv[0]);
memory_check(THREADS_NO, [&] {
ds::static_array<std::thread, THREADS_NO> threads;
std::vector<std::thread> threads;
map_t skiplist;
// put THREADS_NO * elems_per_thread items to the skiplist
for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i) {
threads[thread_i] = std::thread(
threads.emplace_back(
[&skiplist](size_t start, size_t end) {
auto accessor = skiplist.access();
for (size_t elem_i = start; elem_i < end; ++elem_i) {
@ -59,8 +59,8 @@ int main(int argc, char **argv) {
// check size
{
auto accessor = skiplist.access();
permanent_assert(accessor.size() == 0,
"Size should be 0, but size is " << accessor.size());
permanent_assert(accessor.size() == 0, "Size should be 0, but size is "
<< accessor.size());
}
// check count

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t op_per_thread = 1e5;

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t key_range = 1e5;

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t key_range = 1e4;

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t key_range = 1e4;

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "common.hpp"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t key_range = 1e5;