Fix warnings all over the codebase.
Reviewers: florijan, buda Reviewed By: buda Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D146
This commit is contained in:
parent
88a96c2ebd
commit
6be2399ad1
@ -37,9 +37,9 @@ class Server
|
||||
|
||||
public:
|
||||
Server(Socket &&socket, Dbms &dbms, QueryEngine<OutputStream> &query_engine)
|
||||
: socket_(std::forward<Socket>(socket)),
|
||||
dbms_(dbms),
|
||||
: dbms_(dbms),
|
||||
query_engine_(query_engine),
|
||||
socket_(std::forward<Socket>(socket)),
|
||||
logger_(logging::log->logger("communication::Server")) {
|
||||
event_.data.fd = socket_;
|
||||
|
||||
|
@ -74,7 +74,7 @@ class ConcurrentList {
|
||||
IteratorBase(const IteratorBase &) = delete;
|
||||
|
||||
IteratorBase(IteratorBase &&other)
|
||||
: list(other.list), curr(other.curr), prev(other.prev) {
|
||||
: list(other.list), prev(other.prev), curr(other.curr) {
|
||||
other.list = nullptr;
|
||||
other.curr = nullptr;
|
||||
other.prev = nullptr;
|
||||
|
@ -771,7 +771,7 @@ class SkipList : private Lockable<lock_t> {
|
||||
}
|
||||
|
||||
Node *preds[H];
|
||||
auto level = find_path(this, H - 1, item, preds);
|
||||
find_path(this, H - 1, item, preds);
|
||||
return std::make_pair(ReverseIterator(this, preds[0], preds), true);
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ class RhBase {
|
||||
}
|
||||
}
|
||||
IteratorBase(const RhBase *map, size_t start)
|
||||
: map(map), index(start), advanced(0) {}
|
||||
: map(map), advanced(0), index(start) {}
|
||||
|
||||
const RhBase *map;
|
||||
|
||||
|
@ -1,16 +1,20 @@
|
||||
#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.
|
||||
// Entrys are saved as pointers alligned to 8B.
|
||||
// Entrys 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 entrys.
|
||||
/**
|
||||
* 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;
|
||||
@ -69,6 +73,8 @@ class RhHashMap : public RhBase<K, D, init_size_pow2> {
|
||||
|
||||
// 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());
|
||||
|
@ -4,39 +4,45 @@
|
||||
#include <functional>
|
||||
#include "data_structures/map/rh_common.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
#include "utils/crtp.hpp"
|
||||
#include "utils/likely.hpp"
|
||||
#include "utils/option.hpp"
|
||||
#include "utils/option_ptr.hpp"
|
||||
|
||||
// HashMultiMap with RobinHood collision resolution policy.
|
||||
// Single threaded.
|
||||
// Entrys are POINTERS alligned to 8B.
|
||||
// Entrys must know thers key.
|
||||
// D must have method K& get_key()
|
||||
// K must be comparable with ==.
|
||||
// HashMap behaves as if it isn't owner of entrys.
|
||||
//
|
||||
// Main idea of this MultiMap is a tweak of logic in RobinHood.
|
||||
// RobinHood offset from prefered slot is equal to the number of slots between
|
||||
// [current slot and prefered slot>.
|
||||
// While in this flavour of "multi RobinHood" offset from prefered slot is equal
|
||||
// to the number of different keyed elements between his current slot and
|
||||
// prefered slot.
|
||||
// In the following examples slots will have keys as caracters. So something
|
||||
// like this: |a| will mean that in this slot there is data with key 'a'.
|
||||
// like this: | | will mean empty slot.
|
||||
// like this: |...| will mean arbitary number of slots.
|
||||
// like this: |b:a| will mean that a want's to be in slot but b is in't.
|
||||
//
|
||||
// Examples:
|
||||
// |...|a:a|...| => off(a) = 0
|
||||
// |...|a:a|a|...|a|...| => off(a) = 0
|
||||
// |...|b:a|a|...| => off(a) = 1
|
||||
// |...|b:a|b|...|b|a|...| => off(a) = 1
|
||||
// |...|c:a|b|a|...| => off(a) = 2
|
||||
// |...|c:a|c|...|c|b|...|b||a|...|a|...| => off(a) = 2
|
||||
// ...
|
||||
/**
|
||||
* HashMultiMap with RobinHood collision resolution policy.
|
||||
* Single threaded.
|
||||
* Entries are POINTERS alligned to 8B.
|
||||
* Entries must know thers key.
|
||||
* D must have method 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!
|
||||
*
|
||||
* Main idea of this MultiMap is a tweak of logic in RobinHood.
|
||||
* RobinHood offset from prefered slot is equal to the number of slots between
|
||||
* [current slot and prefered slot>.
|
||||
* While in this flavour of "multi RobinHood" offset from prefered slot is
|
||||
* equal
|
||||
* to the number of different keyed elements between his current slot and
|
||||
* prefered slot.
|
||||
* In the following examples slots will have keys as caracters. So something
|
||||
* like this: |a| will mean that in this slot there is data with key 'a'.
|
||||
* like this: | | will mean empty slot.
|
||||
* like this: |...| will mean arbitary number of slots.
|
||||
* like this: |b:a| will mean that a want's to be in slot but b is in't.
|
||||
*
|
||||
* Examples:
|
||||
* |...|a:a|...| => off(a) = 0
|
||||
* |...|a:a|a|...|a|...| => off(a) = 0
|
||||
* |...|b:a|a|...| => off(a) = 1
|
||||
* |...|b:a|b|...|b|a|...| => off(a) = 1
|
||||
* |...|c:a|b|a|...| => off(a) = 2
|
||||
* |...|c:a|c|...|c|b|...|b||a|...|a|...| => off(a) = 2
|
||||
* ...
|
||||
*/
|
||||
template <class K, class D, size_t init_size_pow2 = 2>
|
||||
class RhHashMultiMap : public RhBase<K, D, init_size_pow2> {
|
||||
typedef RhBase<K, D, init_size_pow2> base;
|
||||
@ -124,6 +130,8 @@ class RhHashMultiMap : public RhBase<K, D, init_size_pow2> {
|
||||
// Inserts element with the given key.
|
||||
void add(const K &key_in, D *data) {
|
||||
debug_assert(key_in == data->get_key(), "Key doesn't match data key.");
|
||||
permanent_assert(!((uint64_t)(static_cast<void *>(data)) & 7),
|
||||
"Data is not 8-alligned.");
|
||||
|
||||
if (count < capacity) {
|
||||
auto key = std::ref(key_in);
|
||||
|
@ -75,7 +75,6 @@ static void FindFromRBegin(benchmark::State &state) {
|
||||
|
||||
auto accessor = skiplist.access();
|
||||
auto rbegin = accessor.rbegin();
|
||||
auto rend = accessor.rend();
|
||||
|
||||
state.ResumeTiming();
|
||||
|
||||
|
@ -29,10 +29,9 @@ int main(int argc, char **argv) {
|
||||
|
||||
auto tests = dataset["benchmark_queries"].as<std::vector<std::string>>();
|
||||
for (auto &test : tests) {
|
||||
auto *benchmark =
|
||||
benchmark::RegisterBenchmark(test.c_str(), BM_Strip, preprocess, test)
|
||||
->Range(1, 1)
|
||||
->Complexity(benchmark::oN);
|
||||
benchmark::RegisterBenchmark(test.c_str(), BM_Strip, preprocess, test)
|
||||
->Range(1, 1)
|
||||
->Complexity(benchmark::oN);
|
||||
}
|
||||
|
||||
benchmark::Initialize(&argc, argv);
|
||||
|
@ -25,188 +25,158 @@ constexpr int max_no_threads = 8;
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using map_t = ConcurrentMap<int, int>;
|
||||
using set_t = ConcurrentSet<int>;
|
||||
using map_t = ConcurrentMap<int, int>;
|
||||
using set_t = ConcurrentSet<int>;
|
||||
using multiset_t = ConcurrentMultiSet<int>;
|
||||
using multimap_t = ConcurrentMultiMap<int, int>;
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
// Returns uniform random size_t generator from range [0,n>
|
||||
auto rand_gen(size_t n)
|
||||
{
|
||||
std::default_random_engine generator;
|
||||
std::uniform_int_distribution<size_t> distribution(0, n - 1);
|
||||
return std::bind(distribution, generator);
|
||||
auto rand_gen(size_t n) {
|
||||
std::default_random_engine generator;
|
||||
std::uniform_int_distribution<size_t> distribution(0, n - 1);
|
||||
return std::bind(distribution, generator);
|
||||
}
|
||||
|
||||
// Returns random bool generator with distribution of 1 true for n false.
|
||||
auto rand_gen_bool(size_t n = 1)
|
||||
{
|
||||
auto gen = rand_gen(n + 1);
|
||||
return [=]() mutable { return gen() == 0; };
|
||||
auto rand_gen_bool(size_t n = 1) {
|
||||
auto gen = rand_gen(n + 1);
|
||||
return [=]() mutable { return gen() == 0; };
|
||||
}
|
||||
|
||||
// Checks for all owned keys if there data is data.
|
||||
template <typename S>
|
||||
void check_present_same(typename S::Accessor &acc, size_t data,
|
||||
std::vector<size_t> &owned)
|
||||
{
|
||||
for (auto num : owned)
|
||||
{
|
||||
permanent_assert(acc.find(num)->second == data,
|
||||
"My data is present and my");
|
||||
}
|
||||
std::vector<size_t> &owned) {
|
||||
for (auto num : owned) {
|
||||
permanent_assert(acc.find(num)->second == data,
|
||||
"My data is present and my");
|
||||
}
|
||||
}
|
||||
|
||||
// Checks for all owned.second keys if there data is owned.first.
|
||||
template <typename S>
|
||||
void check_present_same(typename S::Accessor &acc,
|
||||
std::pair<size_t, std::vector<size_t>> &owned)
|
||||
{
|
||||
check_present_same<S>(acc, owned.first, owned.second);
|
||||
std::pair<size_t, std::vector<size_t>> &owned) {
|
||||
check_present_same<S>(acc, owned.first, owned.second);
|
||||
}
|
||||
|
||||
// Checks if reported size and traversed size are equal to given size.
|
||||
template <typename S>
|
||||
void check_size_list(S &acc, long long size)
|
||||
{
|
||||
// check size
|
||||
void check_size_list(S &acc, long long size) {
|
||||
// check size
|
||||
|
||||
permanent_assert(acc.size() == size, "Size should be " << size
|
||||
<< ", but size is "
|
||||
<< acc.size());
|
||||
permanent_assert(acc.size() == size,
|
||||
"Size should be " << size << ", but size is " << acc.size());
|
||||
|
||||
// check count
|
||||
// check count
|
||||
|
||||
size_t iterator_counter = 0;
|
||||
size_t iterator_counter = 0;
|
||||
|
||||
for (auto elem : acc)
|
||||
{
|
||||
++iterator_counter;
|
||||
}
|
||||
permanent_assert(iterator_counter == size, "Iterator count should be "
|
||||
<< size << ", but size is "
|
||||
<< iterator_counter);
|
||||
for ([[gnu::unused]] auto elem : acc) {
|
||||
++iterator_counter;
|
||||
}
|
||||
permanent_assert(iterator_counter == size, "Iterator count should be "
|
||||
<< size << ", but size is "
|
||||
<< iterator_counter);
|
||||
}
|
||||
template <typename S>
|
||||
void check_size(typename S::Accessor &acc, long long size)
|
||||
{
|
||||
// check size
|
||||
void check_size(typename S::Accessor &acc, long long size) {
|
||||
// check size
|
||||
|
||||
permanent_assert(acc.size() == size, "Size should be " << size
|
||||
<< ", but size is "
|
||||
<< acc.size());
|
||||
permanent_assert(acc.size() == size,
|
||||
"Size should be " << size << ", but size is " << acc.size());
|
||||
|
||||
// check count
|
||||
// check count
|
||||
|
||||
size_t iterator_counter = 0;
|
||||
size_t iterator_counter = 0;
|
||||
|
||||
for (auto elem : acc)
|
||||
{
|
||||
++iterator_counter;
|
||||
}
|
||||
permanent_assert(iterator_counter == size, "Iterator count should be "
|
||||
<< size << ", but size is "
|
||||
<< iterator_counter);
|
||||
for ([[gnu::unused]] auto elem : acc) {
|
||||
++iterator_counter;
|
||||
}
|
||||
permanent_assert(iterator_counter == size, "Iterator count should be "
|
||||
<< size << ", but size is "
|
||||
<< iterator_counter);
|
||||
}
|
||||
|
||||
// Checks if order in list is maintened. It expects map
|
||||
template <typename S>
|
||||
void check_order(typename S::Accessor &acc)
|
||||
{
|
||||
if (acc.begin() != acc.end())
|
||||
{
|
||||
auto last = acc.begin()->first;
|
||||
for (auto elem : acc)
|
||||
{
|
||||
if (!(last <= elem))
|
||||
std::cout << "Order isn't maintained. Before was: " << last
|
||||
<< " next is " << elem.first << "\n";
|
||||
last = elem.first;
|
||||
}
|
||||
void check_order(typename S::Accessor &acc) {
|
||||
if (acc.begin() != acc.end()) {
|
||||
auto last = acc.begin()->first;
|
||||
for (auto elem : acc) {
|
||||
if (!(last <= elem))
|
||||
std::cout << "Order isn't maintained. Before was: " << last
|
||||
<< " next is " << elem.first << "\n";
|
||||
last = elem.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_zero(size_t key_range, long array[], const char *str)
|
||||
{
|
||||
for (int i = 0; i < key_range; i++)
|
||||
{
|
||||
permanent_assert(array[i] == 0,
|
||||
str << " doesn't hold it's guarantees. It has "
|
||||
<< array[i] << " extra elements.");
|
||||
}
|
||||
void check_zero(size_t key_range, long array[], const char *str) {
|
||||
for (int i = 0; i < key_range; i++) {
|
||||
permanent_assert(array[i] == 0,
|
||||
str << " doesn't hold it's guarantees. It has " << array[i]
|
||||
<< " extra elements.");
|
||||
}
|
||||
}
|
||||
|
||||
void check_set(DynamicBitset<> &db, std::vector<bool> &set)
|
||||
{
|
||||
for (int i = 0; i < set.size(); i++)
|
||||
{
|
||||
permanent_assert(!(set[i] ^ db.at(i)),
|
||||
"Set constraints aren't fullfilled.");
|
||||
}
|
||||
void check_set(DynamicBitset<> &db, std::vector<bool> &set) {
|
||||
for (int i = 0; i < set.size(); i++) {
|
||||
permanent_assert(!(set[i] ^ db.at(i)),
|
||||
"Set constraints aren't fullfilled.");
|
||||
}
|
||||
}
|
||||
|
||||
// Checks multiIterator and iterator guarantees
|
||||
void check_multi_iterator(multimap_t::Accessor &accessor, size_t key_range,
|
||||
long set[])
|
||||
{
|
||||
for (int i = 0; i < key_range; i++)
|
||||
{
|
||||
auto it = accessor.find(i);
|
||||
auto it_m = accessor.find_multi(i);
|
||||
permanent_assert(
|
||||
!(it_m != accessor.end(i) && it == accessor.end()),
|
||||
"MultiIterator ended before Iterator. Set: " << set[i]);
|
||||
permanent_assert(
|
||||
!(it_m == accessor.end(i) && it != accessor.end()),
|
||||
"Iterator ended before MultiIterator. Set: " << set[i]);
|
||||
permanent_assert((it_m == accessor.end(i) && it == accessor.end()) ||
|
||||
it->second == it_m->second,
|
||||
"MultiIterator didn't found the same "
|
||||
"first element. Set: "
|
||||
<< set[i]);
|
||||
if (set[i] > 0)
|
||||
{
|
||||
for (int j = 0; j < set[i]; j++)
|
||||
{
|
||||
permanent_assert(
|
||||
it->second == it_m->second,
|
||||
"MultiIterator and iterator aren't on the same "
|
||||
"element.");
|
||||
permanent_assert(it_m->first == i,
|
||||
"MultiIterator is showing illegal data") it++;
|
||||
it_m++;
|
||||
}
|
||||
}
|
||||
permanent_assert(
|
||||
it_m == accessor.end(i),
|
||||
"There is more data than it should be in MultiIterator. "
|
||||
<< it_m->first << "\n");
|
||||
long set[]) {
|
||||
for (int i = 0; i < key_range; i++) {
|
||||
auto it = accessor.find(i);
|
||||
auto it_m = accessor.find_multi(i);
|
||||
permanent_assert(!(it_m != accessor.end(i) && it == accessor.end()),
|
||||
"MultiIterator ended before Iterator. Set: " << set[i]);
|
||||
permanent_assert(!(it_m == accessor.end(i) && it != accessor.end()),
|
||||
"Iterator ended before MultiIterator. Set: " << set[i]);
|
||||
permanent_assert((it_m == accessor.end(i) && it == accessor.end()) ||
|
||||
it->second == it_m->second,
|
||||
"MultiIterator didn't found the same "
|
||||
"first element. Set: "
|
||||
<< set[i]);
|
||||
if (set[i] > 0) {
|
||||
for (int j = 0; j < set[i]; j++) {
|
||||
permanent_assert(it->second == it_m->second,
|
||||
"MultiIterator and iterator aren't on the same "
|
||||
"element.");
|
||||
permanent_assert(it_m->first == i,
|
||||
"MultiIterator is showing illegal data") it++;
|
||||
it_m++;
|
||||
}
|
||||
}
|
||||
permanent_assert(it_m == accessor.end(i),
|
||||
"There is more data than it should be in MultiIterator. "
|
||||
<< it_m->first << "\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Runs given function in threads_no threads and returns vector of futures for
|
||||
// there
|
||||
// results.
|
||||
template <class R, typename S>
|
||||
std::vector<std::future<std::pair<size_t, R>>>
|
||||
run(size_t threads_no, S &skiplist,
|
||||
std::function<R(typename S::Accessor, size_t)> f)
|
||||
{
|
||||
std::vector<std::future<std::pair<size_t, R>>> futures;
|
||||
std::vector<std::future<std::pair<size_t, R>>> run(
|
||||
size_t threads_no, S &skiplist,
|
||||
std::function<R(typename S::Accessor, size_t)> f) {
|
||||
std::vector<std::future<std::pair<size_t, R>>> futures;
|
||||
|
||||
for (size_t thread_i = 0; thread_i < threads_no; ++thread_i)
|
||||
{
|
||||
std::packaged_task<std::pair<size_t, R>()> task(
|
||||
[&skiplist, f, thread_i]() {
|
||||
return std::pair<size_t, R>(thread_i,
|
||||
f(skiplist.access(), thread_i));
|
||||
}); // wrap the function
|
||||
futures.push_back(task.get_future()); // get a future
|
||||
std::thread(std::move(task)).detach();
|
||||
}
|
||||
return futures;
|
||||
for (size_t thread_i = 0; thread_i < threads_no; ++thread_i) {
|
||||
std::packaged_task<std::pair<size_t, R>()> task([&skiplist, f, thread_i]() {
|
||||
return std::pair<size_t, R>(thread_i, f(skiplist.access(), thread_i));
|
||||
}); // wrap the function
|
||||
futures.push_back(task.get_future()); // get a future
|
||||
std::thread(std::move(task)).detach();
|
||||
}
|
||||
return futures;
|
||||
}
|
||||
|
||||
// Runs given function in threads_no threads and returns vector of futures for
|
||||
@ -214,98 +184,87 @@ run(size_t threads_no, S &skiplist,
|
||||
// results.
|
||||
template <class R>
|
||||
std::vector<std::future<std::pair<size_t, R>>> run(size_t threads_no,
|
||||
std::function<R(size_t)> f)
|
||||
{
|
||||
std::vector<std::future<std::pair<size_t, R>>> futures;
|
||||
std::function<R(size_t)> f) {
|
||||
std::vector<std::future<std::pair<size_t, R>>> futures;
|
||||
|
||||
for (size_t thread_i = 0; thread_i < threads_no; ++thread_i)
|
||||
{
|
||||
std::packaged_task<std::pair<size_t, R>()> task([f, thread_i]() {
|
||||
return std::pair<size_t, R>(thread_i, f(thread_i));
|
||||
}); // wrap the function
|
||||
futures.push_back(task.get_future()); // get a future
|
||||
std::thread(std::move(task)).detach();
|
||||
}
|
||||
return futures;
|
||||
for (size_t thread_i = 0; thread_i < threads_no; ++thread_i) {
|
||||
std::packaged_task<std::pair<size_t, R>()> task([f, thread_i]() {
|
||||
return std::pair<size_t, R>(thread_i, f(thread_i));
|
||||
}); // wrap the function
|
||||
futures.push_back(task.get_future()); // get a future
|
||||
std::thread(std::move(task)).detach();
|
||||
}
|
||||
return futures;
|
||||
}
|
||||
|
||||
// Collects all data from futures.
|
||||
template <class R>
|
||||
auto collect(std::vector<std::future<R>> &collect)
|
||||
{
|
||||
std::vector<R> collection;
|
||||
for (auto &fut : collect)
|
||||
{
|
||||
collection.push_back(fut.get());
|
||||
}
|
||||
return collection;
|
||||
auto collect(std::vector<std::future<R>> &collect) {
|
||||
std::vector<R> collection;
|
||||
for (auto &fut : collect) {
|
||||
collection.push_back(fut.get());
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
std::vector<bool> collect_set(
|
||||
std::vector<std::future<std::pair<size_t, std::vector<bool>>>> &&futures)
|
||||
{
|
||||
std::vector<bool> set;
|
||||
for (auto &data : collect(futures))
|
||||
{
|
||||
set.resize(data.second.size());
|
||||
for (int i = 0; i < data.second.size(); i++)
|
||||
{
|
||||
set[i] = set[i] | data.second[i];
|
||||
}
|
||||
std::vector<std::future<std::pair<size_t, std::vector<bool>>>> &&futures) {
|
||||
std::vector<bool> set;
|
||||
for (auto &data : collect(futures)) {
|
||||
set.resize(data.second.size());
|
||||
for (int i = 0; i < data.second.size(); i++) {
|
||||
set[i] = set[i] | data.second[i];
|
||||
}
|
||||
return set;
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
// Returns object which tracs in owned which (key,data) where added and
|
||||
// downcounts.
|
||||
template <class K, class D, class S>
|
||||
auto insert_try(typename S::Accessor &acc, long long &downcount,
|
||||
std::vector<K> &owned)
|
||||
{
|
||||
return [&](K key, D data) mutable {
|
||||
if (acc.insert(key, data).second)
|
||||
{
|
||||
downcount--;
|
||||
owned.push_back(key);
|
||||
}
|
||||
};
|
||||
std::vector<K> &owned) {
|
||||
return [&](K key, D data) mutable {
|
||||
if (acc.insert(key, data).second) {
|
||||
downcount--;
|
||||
owned.push_back(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Performs memory check to determine if memory usage before calling given
|
||||
// function
|
||||
// is aproximately equal to memory usage after function. Memory usage is thread
|
||||
// senstive so no_threads spawned in function is necessary.
|
||||
void memory_check(size_t no_threads, std::function<void()> f)
|
||||
{
|
||||
logging::info("Number of threads: {}", no_threads);
|
||||
void memory_check(size_t no_threads, std::function<void()> f) {
|
||||
logging::info("Number of threads: {}", no_threads);
|
||||
|
||||
// TODO: replace vm_size with something more appropriate
|
||||
// the past implementation was teribble wrong
|
||||
// to that ASAP
|
||||
// OR
|
||||
// use custom allocation wrapper
|
||||
// OR
|
||||
// user Boost.Test
|
||||
auto start = vm_size();
|
||||
logging::info("Memory check (used memory at the beginning): {}", start);
|
||||
// TODO: replace vm_size with something more appropriate
|
||||
// the past implementation was teribble wrong
|
||||
// to that ASAP
|
||||
// OR
|
||||
// use custom allocation wrapper
|
||||
// OR
|
||||
// user Boost.Test
|
||||
auto start = vm_size();
|
||||
logging::info("Memory check (used memory at the beginning): {}", start);
|
||||
|
||||
f();
|
||||
f();
|
||||
|
||||
auto end = vm_size();
|
||||
logging::info("Memory check (used memory at the end): {}", end);
|
||||
auto end = vm_size();
|
||||
logging::info("Memory check (used memory at the end): {}", end);
|
||||
|
||||
long long delta = end - start;
|
||||
logging::info("Delta: {}", delta);
|
||||
long long delta = end - start;
|
||||
logging::info("Delta: {}", delta);
|
||||
|
||||
// TODO: do memory check somehow
|
||||
// the past implementation was wrong
|
||||
permanent_assert(true, "Memory leak");
|
||||
// TODO: do memory check somehow
|
||||
// the past implementation was wrong
|
||||
permanent_assert(true, "Memory leak");
|
||||
}
|
||||
|
||||
// TODO: move this inside logging/default
|
||||
// Initializes loging faccilityes
|
||||
void init_log()
|
||||
{
|
||||
logging::init_async();
|
||||
logging::log->pipe(std::make_unique<Stdout>());
|
||||
void init_log() {
|
||||
logging::init_async();
|
||||
logging::log->pipe(std::make_unique<Stdout>());
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "io/network/socket.hpp"
|
||||
#include "query/engine.hpp"
|
||||
|
||||
|
||||
static constexpr const int SIZE = 60000;
|
||||
static constexpr const int REPLY = 10;
|
||||
|
||||
@ -28,9 +27,10 @@ class TestOutputStream {};
|
||||
|
||||
class TestSession {
|
||||
public:
|
||||
TestSession(socket_t &&socket, Dbms &dbms,
|
||||
QueryEngine<TestOutputStream> &query_engine)
|
||||
: socket(std::move(socket)), logger_(logging::log->logger("TestSession")) {
|
||||
TestSession(socket_t&& socket, Dbms& dbms,
|
||||
QueryEngine<TestOutputStream>& query_engine)
|
||||
: logger_(logging::log->logger("TestSession")),
|
||||
socket(std::move(socket)) {
|
||||
event.data.ptr = this;
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ class TestSession {
|
||||
|
||||
int id() const { return socket.id(); }
|
||||
|
||||
void execute(const byte *data, size_t len) {
|
||||
void execute(const byte* data, size_t len) {
|
||||
if (size_ == 0) {
|
||||
size_ = data[0];
|
||||
size_ <<= 8;
|
||||
@ -77,7 +77,8 @@ void server_start(void* serverptr, int num) {
|
||||
((test_server_t*)serverptr)->Start(num);
|
||||
}
|
||||
|
||||
void client_run(int num, const char* interface, const char* port, const unsigned char* data, int lo, int hi) {
|
||||
void client_run(int num, const char* interface, const char* port,
|
||||
const unsigned char* data, int lo, int hi) {
|
||||
std::stringstream name;
|
||||
name << "Client " << num;
|
||||
Logger logger = logging::log->logger(name.str());
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
|
||||
constexpr size_t elems_per_thread = 100000;
|
||||
constexpr size_t key_range = elems_per_thread * THREADS_NO * 2;
|
||||
|
||||
// TODO: document the test
|
||||
|
||||
@ -18,16 +17,17 @@ int main() {
|
||||
|
||||
auto futures = run<std::vector<size_t>>(
|
||||
THREADS_NO, skiplist, [](auto acc, auto index) {
|
||||
auto rand = rand_gen(key_range);
|
||||
long long downcount = elems_per_thread;
|
||||
std::vector<size_t> owned;
|
||||
auto inserter =
|
||||
insert_try<size_t, size_t, map_t>(acc, downcount, owned);
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfor-loop-analysis"
|
||||
for (int i = 0; downcount > 0; i++) {
|
||||
inserter(i, index);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
check_present_same<map_t>(acc, index, owned);
|
||||
return owned;
|
||||
});
|
||||
|
@ -1,10 +1,10 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <memory>
|
||||
#include "data_structures/map/rh_hashmap.hpp"
|
||||
|
||||
class Data {
|
||||
private:
|
||||
size_t data = 0;
|
||||
int key;
|
||||
|
||||
public:
|
||||
@ -19,14 +19,16 @@ TEST(RobinHoodHashmap, BasicFunctionality) {
|
||||
RhHashMap<int, Data> map;
|
||||
|
||||
ASSERT_EQ(map.size(), 0);
|
||||
ASSERT_EQ(map.insert(new Data(0)), true);
|
||||
Data d0(0);
|
||||
ASSERT_EQ(map.insert(&d0), true);
|
||||
ASSERT_EQ(map.size(), 1);
|
||||
}
|
||||
|
||||
TEST(RobinHoodHashmap, RemoveFunctionality) {
|
||||
RhHashMap<int, Data> map;
|
||||
|
||||
ASSERT_EQ(map.insert(new Data(0)), true);
|
||||
Data d0(0);
|
||||
ASSERT_EQ(map.insert(&d0), true);
|
||||
ASSERT_EQ(map.remove(0).is_present(), true);
|
||||
ASSERT_EQ(map.size(), 0);
|
||||
ASSERT_EQ(!map.find(0).is_present(), true);
|
||||
@ -36,25 +38,29 @@ TEST(RobinHoodHashmap, InsertGetCheck) {
|
||||
RhHashMap<int, Data> map;
|
||||
|
||||
ASSERT_EQ(!map.find(0).is_present(), true);
|
||||
auto ptr0 = new Data(0);
|
||||
ASSERT_EQ(map.insert(ptr0), true);
|
||||
Data d0(0);
|
||||
ASSERT_EQ(map.insert(&d0), true);
|
||||
ASSERT_EQ(map.find(0).is_present(), true);
|
||||
ASSERT_EQ(map.find(0).get(), ptr0);
|
||||
ASSERT_EQ(map.find(0).get(), &d0);
|
||||
}
|
||||
|
||||
TEST(RobinHoodHashmap, DoubleInsert) {
|
||||
RhHashMap<int, Data> map;
|
||||
|
||||
ASSERT_EQ(map.insert(new Data(0)), true);
|
||||
ASSERT_EQ(!map.insert(new Data(0)), true);
|
||||
Data d0(0);
|
||||
ASSERT_EQ(map.insert(&d0), true);
|
||||
ASSERT_EQ(!map.insert(&d0), true);
|
||||
}
|
||||
|
||||
TEST(RobinHoodHashmap, FindInsertFind) {
|
||||
RhHashMap<int, Data> map;
|
||||
|
||||
std::vector<std::unique_ptr<Data>> di;
|
||||
di.reserve(128);
|
||||
for (int i = 0; i < 128; ++i) di.emplace_back(std::make_unique<Data>(i));
|
||||
for (int i = 0; i < 128; i++) {
|
||||
ASSERT_EQ(!map.find(i).is_present(), true);
|
||||
ASSERT_EQ(map.insert(new Data(i)), true);
|
||||
ASSERT_EQ(map.insert(di[i].get()), true);
|
||||
ASSERT_EQ(map.find(i).is_present(), true);
|
||||
}
|
||||
|
||||
@ -67,9 +73,12 @@ TEST(RobinHoodHashmap, FindInsertFind) {
|
||||
TEST(RobinHoodHashmap, Iterate) {
|
||||
RhHashMap<int, Data> map;
|
||||
|
||||
std::vector<std::unique_ptr<Data>> di;
|
||||
di.reserve(128);
|
||||
for (int i = 0; i < 128; ++i) di.emplace_back(std::make_unique<Data>(i));
|
||||
for (int i = 0; i < 128; i++) {
|
||||
ASSERT_EQ(!map.find(i).is_present(), true);
|
||||
ASSERT_EQ(map.insert(new Data(i)), true);
|
||||
ASSERT_EQ(map.insert(di[i].get()), true);
|
||||
ASSERT_EQ(map.find(i).is_present(), true);
|
||||
}
|
||||
|
||||
@ -88,14 +97,21 @@ TEST(RobinHoodHashmap, Checked) {
|
||||
RhHashMap<int, Data> map;
|
||||
std::map<int, Data *> s_map;
|
||||
|
||||
std::vector<std::unique_ptr<Data>> di;
|
||||
std::vector<int> key;
|
||||
di.reserve(128);
|
||||
key.reserve(128);
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
const int curr_key = std::rand();
|
||||
key.emplace_back(curr_key);
|
||||
di.emplace_back(std::make_unique<Data>(curr_key));
|
||||
}
|
||||
for (int i = 0; i < 128; i++) {
|
||||
int key = std::rand();
|
||||
auto data = new Data(key);
|
||||
if (map.insert(data)) {
|
||||
ASSERT_EQ(s_map.find(key), s_map.end());
|
||||
s_map[key] = data;
|
||||
if (map.insert(di[i].get())) {
|
||||
ASSERT_EQ(s_map.find(key[i]), s_map.end());
|
||||
s_map[key[i]] = di[i].get();
|
||||
} else {
|
||||
ASSERT_NE(s_map.find(key), s_map.end());
|
||||
ASSERT_NE(s_map.find(key[i]), s_map.end());
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,17 +121,24 @@ TEST(RobinHoodHashmap, Checked) {
|
||||
TEST(RobinHoodHashMap, CheckWithRemove) {
|
||||
RhHashMap<int, Data> map;
|
||||
std::map<int, Data *> s_map;
|
||||
std::vector<std::unique_ptr<Data>> di;
|
||||
std::vector<int> key;
|
||||
di.reserve(1280);
|
||||
key.reserve(1280);
|
||||
for (int i = 0; i < 1280; ++i) {
|
||||
const int curr_key = std::rand() % 100;
|
||||
key.emplace_back(curr_key);
|
||||
di.emplace_back(std::make_unique<Data>(curr_key));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1280; i++) {
|
||||
int key = std::rand() % 100;
|
||||
auto data = new Data(key);
|
||||
if (map.insert(data)) {
|
||||
ASSERT_EQ(s_map.find(key), s_map.end());
|
||||
s_map[key] = data;
|
||||
if (map.insert(di[i].get())) {
|
||||
ASSERT_EQ(s_map.find(key[i]), s_map.end());
|
||||
s_map[key[i]] = di[i].get();
|
||||
cross_validate(map, s_map);
|
||||
} else {
|
||||
ASSERT_EQ(map.remove(key).is_present(), true);
|
||||
ASSERT_EQ(s_map.erase(key), 1);
|
||||
ASSERT_EQ(map.remove(key[i]).is_present(), true);
|
||||
ASSERT_EQ(s_map.erase(key[i]), 1);
|
||||
cross_validate(map, s_map);
|
||||
}
|
||||
}
|
||||
@ -123,6 +146,13 @@ TEST(RobinHoodHashMap, CheckWithRemove) {
|
||||
cross_validate(map, s_map);
|
||||
}
|
||||
|
||||
TEST(RobinhoodHashmmap, AlignmentCheck) {
|
||||
RhHashMap<int, Data> map;
|
||||
char *block = static_cast<char *>(std::malloc(20));
|
||||
++block; // not alligned - offset 1
|
||||
EXPECT_DEATH(map.insert((Data *)(block)), "not 8-alligned");
|
||||
}
|
||||
|
||||
void cross_validate(RhHashMap<int, Data> &map, std::map<int, Data *> &s_map) {
|
||||
for (auto e : map) {
|
||||
ASSERT_NE(s_map.find(e->get_key()), s_map.end());
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
class Data {
|
||||
private:
|
||||
size_t data = 0;
|
||||
int key;
|
||||
|
||||
public:
|
||||
@ -23,7 +22,8 @@ TEST(RobinHoodHashmultimap, BasicFunctionality) {
|
||||
RhHashMultiMap<int, Data> map;
|
||||
|
||||
ASSERT_EQ(map.size(), 0);
|
||||
map.add(new Data(0));
|
||||
Data d0(0);
|
||||
map.add(&d0);
|
||||
ASSERT_EQ(map.size(), 1);
|
||||
}
|
||||
|
||||
@ -31,67 +31,72 @@ TEST(RobinHoodHashmultimap, InsertGetCheck) {
|
||||
RhHashMultiMap<int, Data> map;
|
||||
|
||||
ASSERT_EQ(map.find(0), map.end());
|
||||
auto ptr0 = new Data(0);
|
||||
map.add(ptr0);
|
||||
Data d0(0);
|
||||
map.add(&d0);
|
||||
ASSERT_NE(map.find(0), map.end());
|
||||
ASSERT_EQ(*map.find(0), ptr0);
|
||||
ASSERT_EQ(*map.find(0), &d0);
|
||||
}
|
||||
|
||||
TEST(RobinHoodHashmultimap, ExtremeSameKeyValusFull) {
|
||||
RhHashMultiMap<int, Data> map;
|
||||
|
||||
std::vector<std::unique_ptr<Data>> di;
|
||||
di.reserve(128);
|
||||
for (int i = 0; i < 128; i++) {
|
||||
map.add(new Data(7));
|
||||
di.emplace_back(std::make_unique<Data>(7));
|
||||
map.add(di[i].get());
|
||||
}
|
||||
ASSERT_EQ(map.size(), 128);
|
||||
ASSERT_NE(map.find(7), map.end());
|
||||
ASSERT_EQ(map.find(0), map.end());
|
||||
auto ptr0 = new Data(0);
|
||||
map.add(ptr0);
|
||||
Data d0(0);
|
||||
map.add(&d0);
|
||||
ASSERT_NE(map.find(0), map.end());
|
||||
ASSERT_EQ(*map.find(0), ptr0);
|
||||
ASSERT_EQ(*map.find(0), &d0);
|
||||
}
|
||||
|
||||
TEST(RobinHoodHashmultimap, ExtremeSameKeyValusFullWithRemove) {
|
||||
RhHashMultiMap<int, Data> map;
|
||||
|
||||
std::vector<std::unique_ptr<Data>> di;
|
||||
di.reserve(128);
|
||||
for (int i = 0; i < 127; i++) {
|
||||
map.add(new Data(7));
|
||||
di.emplace_back(std::make_unique<Data>(7));
|
||||
map.add(di[i].get());
|
||||
}
|
||||
auto ptr = new Data(7);
|
||||
map.add(ptr);
|
||||
Data d7(7);
|
||||
map.add(&d7);
|
||||
ASSERT_EQ(map.size(), 128);
|
||||
ASSERT_EQ(!map.remove(new Data(0)), true);
|
||||
ASSERT_EQ(map.remove(ptr), true);
|
||||
Data d0(0);
|
||||
ASSERT_EQ(!map.remove(&d0), true);
|
||||
ASSERT_EQ(map.remove(&d7), true);
|
||||
}
|
||||
|
||||
TEST(RobinHoodHasmultihmap, RemoveFunctionality) {
|
||||
RhHashMultiMap<int, Data> map;
|
||||
|
||||
ASSERT_EQ(map.find(0), map.end());
|
||||
auto ptr0 = new Data(0);
|
||||
map.add(ptr0);
|
||||
Data d0(0);
|
||||
map.add(&d0);
|
||||
ASSERT_NE(map.find(0), map.end());
|
||||
ASSERT_EQ(*map.find(0), ptr0);
|
||||
ASSERT_EQ(map.remove(ptr0), true);
|
||||
ASSERT_EQ(*map.find(0), &d0);
|
||||
ASSERT_EQ(map.remove(&d0), true);
|
||||
ASSERT_EQ(map.find(0), map.end());
|
||||
}
|
||||
|
||||
TEST(RobinHoodHashmultimap, DoubleInsert) {
|
||||
RhHashMultiMap<int, Data> map;
|
||||
|
||||
auto ptr0 = new Data(0);
|
||||
auto ptr1 = new Data(0);
|
||||
map.add(ptr0);
|
||||
map.add(ptr1);
|
||||
Data d0(0);
|
||||
Data d01(0);
|
||||
map.add(&d0);
|
||||
map.add(&d01);
|
||||
|
||||
for (auto e : map) {
|
||||
if (ptr0 == e) {
|
||||
ptr0 = nullptr;
|
||||
if (&d0 == e) {
|
||||
continue;
|
||||
}
|
||||
if (ptr1 == e) {
|
||||
ptr1 = nullptr;
|
||||
if (&d01 == e) {
|
||||
continue;
|
||||
}
|
||||
ASSERT_EQ(true, false);
|
||||
@ -101,9 +106,12 @@ TEST(RobinHoodHashmultimap, DoubleInsert) {
|
||||
TEST(RobinHoodHashmultimap, FindAddFind) {
|
||||
RhHashMultiMap<int, Data> map;
|
||||
|
||||
std::vector<std::unique_ptr<Data>> di;
|
||||
di.reserve(128);
|
||||
for (int i = 0; i < 128; i++) {
|
||||
ASSERT_EQ(map.find(i), map.end());
|
||||
map.add(new Data(i));
|
||||
di.emplace_back(std::make_unique<Data>(i));
|
||||
map.add(di[i].get());
|
||||
ASSERT_NE(map.find(i), map.end());
|
||||
}
|
||||
|
||||
@ -116,9 +124,12 @@ TEST(RobinHoodHashmultimap, FindAddFind) {
|
||||
TEST(RobinHoodHashmultimap, Iterate) {
|
||||
RhHashMultiMap<int, Data> map;
|
||||
|
||||
std::vector<std::unique_ptr<Data>> di;
|
||||
di.reserve(128);
|
||||
for (int i = 0; i < 128; i++) {
|
||||
ASSERT_EQ(map.find(i), map.end());
|
||||
map.add(new Data(i));
|
||||
di.emplace_back(std::make_unique<Data>(i));
|
||||
map.add(di[i].get());
|
||||
ASSERT_NE(map.find(i), map.end());
|
||||
}
|
||||
|
||||
@ -137,12 +148,18 @@ TEST(RobinHoodHashmultimap, Checked) {
|
||||
RhHashMultiMap<int, Data> map;
|
||||
std::multimap<int, Data *> s_map;
|
||||
|
||||
for (int i = 0; i < 1638; i++) {
|
||||
int key = (std::rand() % 100) << 3;
|
||||
std::vector<std::unique_ptr<Data>> di;
|
||||
std::vector<int> keys;
|
||||
di.reserve(1638);
|
||||
for (int i = 0; i < 1638; ++i) {
|
||||
const int key = (std::rand() % 100) << 3;
|
||||
keys.push_back(key);
|
||||
di.emplace_back(std::make_unique<Data>(key));
|
||||
}
|
||||
|
||||
auto data = new Data(key);
|
||||
map.add(data);
|
||||
s_map.insert(std::pair<int, Data *>(key, data));
|
||||
for (int i = 0; i < 1638; i++) {
|
||||
map.add(di[i].get());
|
||||
s_map.insert(std::pair<int, Data *>(keys[i], di[i].get()));
|
||||
}
|
||||
cross_validate(map, s_map);
|
||||
}
|
||||
@ -151,12 +168,19 @@ TEST(RobinHoodHashmultimap, CheckedRand) {
|
||||
RhHashMultiMap<int, Data> map;
|
||||
std::multimap<int, Data *> s_map;
|
||||
std::srand(std::time(0));
|
||||
for (int i = 0; i < 164308; i++) {
|
||||
int key = (std::rand() % 10000) << 3;
|
||||
|
||||
auto data = new Data(key);
|
||||
map.add(data);
|
||||
s_map.insert(std::pair<int, Data *>(key, data));
|
||||
std::vector<std::unique_ptr<Data>> di;
|
||||
std::vector<int> keys;
|
||||
di.reserve(164308);
|
||||
for (int i = 0; i < 164308; ++i) {
|
||||
const int key = (std::rand() % 10000) << 3;
|
||||
keys.push_back(key);
|
||||
di.emplace_back(std::make_unique<Data>(key));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 164308; i++) {
|
||||
map.add(di[i].get());
|
||||
s_map.insert(std::pair<int, Data *>(keys[i], di[i].get()));
|
||||
}
|
||||
cross_validate(map, s_map);
|
||||
}
|
||||
@ -166,6 +190,7 @@ TEST(RobinHoodHashmultimap, WithRemoveDataChecked) {
|
||||
std::multimap<int, Data *> s_map;
|
||||
|
||||
std::srand(std::time(0));
|
||||
std::vector<std::unique_ptr<Data>> di;
|
||||
for (int i = 0; i < 162638; i++) {
|
||||
int key = (std::rand() % 10000) << 3;
|
||||
if ((std::rand() % 2) == 0) {
|
||||
@ -177,15 +202,22 @@ TEST(RobinHoodHashmultimap, WithRemoveDataChecked) {
|
||||
ASSERT_EQ(map.remove(it->second), true);
|
||||
}
|
||||
} else {
|
||||
auto data = new Data(key);
|
||||
map.add(data);
|
||||
s_map.insert(std::pair<int, Data *>(key, data));
|
||||
di.emplace_back(std::make_unique<Data>(key));
|
||||
map.add(di.back().get());
|
||||
s_map.insert(std::pair<int, Data *>(key, di.back().get()));
|
||||
}
|
||||
}
|
||||
|
||||
cross_validate(map, s_map);
|
||||
}
|
||||
|
||||
TEST(RobinhoodHashmultimap, AlignmentCheck) {
|
||||
RhHashMultiMap<int, Data> map;
|
||||
char *block = static_cast<char *>(std::malloc(20));
|
||||
++block; // not alligned - offset 1
|
||||
EXPECT_DEATH(map.add((Data *)(block)), "not 8-alligned");
|
||||
}
|
||||
|
||||
void cross_validate(RhHashMultiMap<int, Data> &map,
|
||||
std::multimap<int, Data *> &s_map) {
|
||||
for (auto e : map) {
|
||||
|
@ -3,12 +3,12 @@
|
||||
// Created by Florijan Stamenkovic on 24.01.17..
|
||||
//
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <unordered_set>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
@ -38,14 +38,14 @@ class Edge;
|
||||
class Vertex {
|
||||
friend class Edge;
|
||||
|
||||
public:
|
||||
public:
|
||||
// unique identifier (uniqueness guaranteed by this class)
|
||||
const int id_;
|
||||
|
||||
// vertex set by the user, for testing purposes
|
||||
const int label_;
|
||||
|
||||
Vertex(int label=0) : id_(counter_++), label_(label) {}
|
||||
Vertex(int label = 0) : id_(counter_++), label_(label) {}
|
||||
|
||||
const auto &in() const { return *in_; }
|
||||
const auto &out() const { return *out_; }
|
||||
@ -57,15 +57,16 @@ public:
|
||||
bool operator==(const Vertex &v) const { return this->id_ == v.id_; }
|
||||
bool operator!=(const Vertex &v) const { return !(*this == v); }
|
||||
|
||||
private:
|
||||
private:
|
||||
// shared pointers to outgoing and incoming edges are used so that when
|
||||
// a Vertex is copied it still points to the same connectivity storage
|
||||
std::shared_ptr<std::vector<Edge>> in_ = std::make_shared<std::vector<Edge>>();
|
||||
std::shared_ptr<std::vector<Edge>> out_ = std::make_shared<std::vector<Edge>>();
|
||||
std::shared_ptr<std::vector<Edge>> in_ =
|
||||
std::make_shared<std::vector<Edge>>();
|
||||
std::shared_ptr<std::vector<Edge>> out_ =
|
||||
std::make_shared<std::vector<Edge>>();
|
||||
|
||||
// Vertex counter, used for generating IDs
|
||||
static int counter_;
|
||||
|
||||
};
|
||||
|
||||
int Vertex::counter_ = 0;
|
||||
@ -75,15 +76,15 @@ int Vertex::counter_ = 0;
|
||||
* and an exposed id_ member.
|
||||
*/
|
||||
class Edge {
|
||||
public:
|
||||
public:
|
||||
// unique identifier (uniqueness guaranteed by this class)
|
||||
const int id_;
|
||||
|
||||
// vertex set by the user, for testing purposes
|
||||
const int type_;
|
||||
|
||||
Edge(const Vertex &from, const Vertex &to, int type=0) :
|
||||
id_(counter_++), from_(from), to_(to), type_(type) {
|
||||
Edge(const Vertex &from, const Vertex &to, int type = 0)
|
||||
: id_(counter_++), type_(type), from_(from), to_(to) {
|
||||
from.out_->emplace_back(*this);
|
||||
to.in_->emplace_back(*this);
|
||||
}
|
||||
@ -98,7 +99,7 @@ public:
|
||||
return stream << "[" << e.id_ << "]";
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
const Vertex &from_;
|
||||
const Vertex &to_;
|
||||
|
||||
@ -115,34 +116,34 @@ using Paths = traversal_template::Paths<Vertex, Edge>;
|
||||
/**
|
||||
* Specialization of the traversal_template::Begin function.
|
||||
*/
|
||||
template<typename TCollection>
|
||||
auto Begin(const TCollection &vertices, std::function<bool(const Vertex &)> vertex_filter = {}) {
|
||||
return traversal_template::Begin<TCollection, Vertex, Edge>(vertices, vertex_filter);
|
||||
template <typename TCollection>
|
||||
auto Begin(const TCollection &vertices,
|
||||
std::function<bool(const Vertex &)> vertex_filter = {}) {
|
||||
return traversal_template::Begin<TCollection, Vertex, Edge>(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, Vertex, Edge>(
|
||||
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)...)),
|
||||
Vertex, Edge>(
|
||||
std::forward<TVisitableFirst>(first),
|
||||
Cartesian(std::forward<TVisitableOthers>(others)...)
|
||||
);
|
||||
return traversal_template::CartesianBinaryType<
|
||||
TVisitableFirst,
|
||||
decltype(Cartesian(std::forward<TVisitableOthers>(others)...)), Vertex,
|
||||
Edge>(std::forward<TVisitableFirst>(first),
|
||||
Cartesian(std::forward<TVisitableOthers>(others)...));
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,27 +151,27 @@ auto Cartesian(TVisitableFirst &&first, TVisitableOthers &&... others) {
|
||||
* Hash calculations for text vertex, edge, Path and Paths.
|
||||
* Only for testing purposes.
|
||||
*/
|
||||
namespace std{
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
class hash<traversal_test::Vertex> {
|
||||
public:
|
||||
struct hash<traversal_test::Vertex> {
|
||||
public:
|
||||
size_t operator()(const traversal_test::Vertex &vertex) const {
|
||||
return (size_t) vertex.id_;
|
||||
return (size_t)vertex.id_;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class hash<traversal_test::Edge> {
|
||||
public:
|
||||
struct hash<traversal_test::Edge> {
|
||||
public:
|
||||
size_t operator()(const traversal_test::Edge &edge) const {
|
||||
return (size_t) edge.id_;
|
||||
return (size_t)edge.id_;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class hash<traversal_test::Path> {
|
||||
public:
|
||||
struct hash<traversal_test::Path> {
|
||||
public:
|
||||
std::size_t operator()(const traversal_test::Path &path) const {
|
||||
std::size_t r_val = 0;
|
||||
|
||||
@ -182,8 +183,8 @@ public:
|
||||
};
|
||||
|
||||
template <>
|
||||
class hash<traversal_test::Paths> {
|
||||
public:
|
||||
struct hash<traversal_test::Paths> {
|
||||
public:
|
||||
std::size_t operator()(const traversal_test::Paths &paths) const {
|
||||
std::size_t r_val = 0;
|
||||
|
||||
@ -195,14 +196,13 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hash for a list of edges, used in tests.
|
||||
*/
|
||||
namespace std{
|
||||
namespace std {
|
||||
template <>
|
||||
class hash<std::list<traversal_test::Edge>> {
|
||||
public:
|
||||
struct hash<std::list<traversal_test::Edge>> {
|
||||
public:
|
||||
std::size_t operator()(const std::list<traversal_test::Edge> &edges) const {
|
||||
std::size_t r_val = 0;
|
||||
|
||||
@ -221,7 +221,8 @@ std::unordered_set<TElement> accumulate_visited(const TVisitable &visitable) {
|
||||
// we accept const here so we can receive r-values
|
||||
// we cast the const-ness away because the Visit function is not const
|
||||
std::unordered_set<TElement> results;
|
||||
const_cast<TVisitable&>(visitable).Visit([&results](auto e) { results.insert(e); });
|
||||
const_cast<TVisitable &>(visitable).Visit(
|
||||
[&results](auto e) { results.insert(e); });
|
||||
return results;
|
||||
};
|
||||
|
||||
@ -276,8 +277,7 @@ TEST(Traversal, Begin) {
|
||||
std::vector<Vertex> vertices(3);
|
||||
|
||||
std::unordered_set<Path> expected;
|
||||
for (const auto &vertex : vertices)
|
||||
expected.insert(Path().Start(vertex));
|
||||
for (const auto &vertex : vertices) expected.insert(Path().Start(vertex));
|
||||
EXPECT_EQ(expected.size(), 3);
|
||||
|
||||
auto result = accumulate_visited<Path>(Begin(vertices));
|
||||
@ -291,13 +291,10 @@ TEST(Traversal, BeginExpand) {
|
||||
Edge e2(v2, v3);
|
||||
|
||||
// test traversal from (v0)
|
||||
auto expected = std::unordered_set<Path>{
|
||||
Path().Start(v0).Append(e0, v1),
|
||||
Path().Start(v0).Append(e1, v2)
|
||||
};
|
||||
auto result= accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).
|
||||
Expand(Expansion::Back, Direction::Out));
|
||||
auto expected = std::unordered_set<Path>{Path().Start(v0).Append(e0, v1),
|
||||
Path().Start(v0).Append(e1, v2)};
|
||||
auto result = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).Expand(Expansion::Back, Direction::Out));
|
||||
EXPECT_EQ(expected, result);
|
||||
}
|
||||
|
||||
@ -312,29 +309,23 @@ TEST(Traversal, BeginExpandVariable) {
|
||||
|
||||
// test traversal from (v0)
|
||||
auto expected = std::unordered_set<Path>{
|
||||
Path().Start(v0).Append(e0, v1),
|
||||
Path().Start(v0).Append(e1, v2),
|
||||
Path().Start(v0).Append(e1, v2).Append(e2, v3)
|
||||
};
|
||||
auto result= accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).
|
||||
ExpandVariable(Expansion::Back, Direction::Out));
|
||||
Path().Start(v0).Append(e0, v1), Path().Start(v0).Append(e1, v2),
|
||||
Path().Start(v0).Append(e1, v2).Append(e2, v3)};
|
||||
auto result = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0})
|
||||
.ExpandVariable(Expansion::Back, Direction::Out));
|
||||
EXPECT_EQ(expected, result);
|
||||
|
||||
}
|
||||
|
||||
TEST(Traversal, BeginFilter) {
|
||||
Vertex v0(1), v1(1), v2(2);
|
||||
|
||||
std::unordered_set<Path> expected{
|
||||
Path().Start(v0),
|
||||
Path().Start(v1)
|
||||
};
|
||||
std::unordered_set<Path> expected{Path().Start(v0), Path().Start(v1)};
|
||||
|
||||
auto result = accumulate_visited<Path>(Begin(std::vector<Vertex>{v0, v1, v2},
|
||||
[](const Vertex &v) { return v.label_ == 1; }));
|
||||
auto result = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0, v1, v2},
|
||||
[](const Vertex &v) { return v.label_ == 1; }));
|
||||
EXPECT_EQ(expected, result);
|
||||
|
||||
}
|
||||
|
||||
TEST(Traversal, BeginCurrent) {
|
||||
@ -344,7 +335,7 @@ TEST(Traversal, BeginCurrent) {
|
||||
std::vector<Vertex> begin_input{v0, v1, v2};
|
||||
auto b = Begin(begin_input);
|
||||
|
||||
b.Visit([&b, &expected](Path &path){
|
||||
b.Visit([&b, &expected](Path &path) {
|
||||
EXPECT_EQ(1, expected.erase(b.CurrentVertex()));
|
||||
});
|
||||
|
||||
@ -365,32 +356,36 @@ TEST(Traversal, ExpandExpand) {
|
||||
Edge e6(v7, v1);
|
||||
|
||||
// test traversal from (v0)
|
||||
auto expected = std::unordered_set<Path>{
|
||||
Path().Start(v0).Append(e0, v1).Append(e2, v3),
|
||||
Path().Start(v0).Append(e1, v2).Append(e3, v4),
|
||||
Path().Start(v0).Append(e1, v2).Append(e4, v5)
|
||||
};
|
||||
auto result= accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).
|
||||
Expand(Expansion::Back, Direction::Out).
|
||||
Expand(Expansion::Back, Direction::Out));
|
||||
auto expected =
|
||||
std::unordered_set<Path>{Path().Start(v0).Append(e0, v1).Append(e2, v3),
|
||||
Path().Start(v0).Append(e1, v2).Append(e3, v4),
|
||||
Path().Start(v0).Append(e1, v2).Append(e4, v5)};
|
||||
auto result =
|
||||
accumulate_visited<Path>(Begin(std::vector<Vertex>{v0})
|
||||
.Expand(Expansion::Back, Direction::Out)
|
||||
.Expand(Expansion::Back, Direction::Out));
|
||||
EXPECT_EQ(expected, result);
|
||||
}
|
||||
|
||||
TEST(Traversal, ExpandFilter) {
|
||||
// make a one-level deep tree and 4 children that have {1,2} vertex labels and {3,4} edge types
|
||||
// make a one-level deep tree and 4 children that have {1,2} vertex labels and
|
||||
// {3,4} edge types
|
||||
Vertex root;
|
||||
Vertex v1(1); Edge e1(root, v1, 3);
|
||||
Vertex v2(1); Edge e2(root, v2, 4);
|
||||
Vertex v3(2); Edge e3(root, v3, 3);
|
||||
Vertex v4(2); Edge e4(root, v4, 4);
|
||||
Vertex v1(1);
|
||||
Edge e1(root, v1, 3);
|
||||
Vertex v2(1);
|
||||
Edge e2(root, v2, 4);
|
||||
Vertex v3(2);
|
||||
Edge e3(root, v3, 3);
|
||||
Vertex v4(2);
|
||||
Edge e4(root, v4, 4);
|
||||
|
||||
// filter to accept only label 1 and edge type 3, expect exactly one path
|
||||
auto result = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{root}).
|
||||
Expand(Expansion::Back, Direction::Out,
|
||||
[](const Vertex &v) { return v.label_ == 1; },
|
||||
[](const Edge &e) { return e.type_ == 3; }));
|
||||
Begin(std::vector<Vertex>{root})
|
||||
.Expand(Expansion::Back, Direction::Out,
|
||||
[](const Vertex &v) { return v.label_ == 1; },
|
||||
[](const Edge &e) { return e.type_ == 3; }));
|
||||
|
||||
auto expected = std::unordered_set<Path>{Path().Start(root).Append(e1, v1)};
|
||||
EXPECT_EQ(expected, result);
|
||||
@ -416,7 +411,7 @@ TEST(Traversal, ExpandCurrent) {
|
||||
std::unordered_set<Vertex> expected_expand1_vertices{v3, v4, v5, v6};
|
||||
std::unordered_set<Edge> expected_expand1_edges{e3, e4, e5, e6};
|
||||
|
||||
expand1.Visit([&](Path &path){
|
||||
expand1.Visit([&](Path &path) {
|
||||
// we can't check that erasure on the first level because it only gets
|
||||
// erased the first time a path containing first level stuff gets visited
|
||||
expected_expand0_vertices.erase(expand0.CurrentVertex());
|
||||
@ -434,10 +429,14 @@ TEST(Traversal, ExpandCurrent) {
|
||||
TEST(Traversal, ExpandVariableLimits) {
|
||||
// make a chain
|
||||
Vertex v0;
|
||||
Vertex v1; Edge e1(v0, v1);
|
||||
Vertex v2; Edge e2(v1, v2);
|
||||
Vertex v3; Edge e3(v2, v3);
|
||||
Vertex v4; Edge e4(v3, v4);
|
||||
Vertex v1;
|
||||
Edge e1(v0, v1);
|
||||
Vertex v2;
|
||||
Edge e2(v1, v2);
|
||||
Vertex v3;
|
||||
Edge e3(v2, v3);
|
||||
Vertex v4;
|
||||
Edge e4(v3, v4);
|
||||
|
||||
// all possible results
|
||||
std::vector<Path> all_possible{Path().Start(v0)};
|
||||
@ -448,29 +447,36 @@ TEST(Traversal, ExpandVariableLimits) {
|
||||
|
||||
// default is one or more traversals
|
||||
auto result0 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).ExpandVariable(Expansion::Back, Direction::Out));
|
||||
EXPECT_EQ(result0, std::unordered_set<Path>(all_possible.begin() + 1, all_possible.end()));
|
||||
Begin(std::vector<Vertex>{v0})
|
||||
.ExpandVariable(Expansion::Back, Direction::Out));
|
||||
EXPECT_EQ(result0, std::unordered_set<Path>(all_possible.begin() + 1,
|
||||
all_possible.end()));
|
||||
|
||||
// zero or more traversals
|
||||
auto result1 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).
|
||||
ExpandVariable(Expansion::Back, Direction::Out, {}, {}, 0));
|
||||
EXPECT_EQ(result1, std::unordered_set<Path>(all_possible.begin(), all_possible.end()));
|
||||
Begin(std::vector<Vertex>{v0})
|
||||
.ExpandVariable(Expansion::Back, Direction::Out, {}, {}, 0));
|
||||
EXPECT_EQ(result1,
|
||||
std::unordered_set<Path>(all_possible.begin(), all_possible.end()));
|
||||
|
||||
// an exact number of traversals [2, 4)
|
||||
auto result2 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).
|
||||
ExpandVariable(Expansion::Back, Direction::Out, {}, {}, 2, 4));
|
||||
EXPECT_EQ(result2, std::unordered_set<Path>(all_possible.begin() + 2, all_possible.begin() + 4));
|
||||
Begin(std::vector<Vertex>{v0})
|
||||
.ExpandVariable(Expansion::Back, Direction::Out, {}, {}, 2, 4));
|
||||
EXPECT_EQ(result2, std::unordered_set<Path>(all_possible.begin() + 2,
|
||||
all_possible.begin() + 4));
|
||||
}
|
||||
|
||||
TEST(Traversal, ExpandVariableFilter) {
|
||||
// make a chain with vertex labels and edge types with these values
|
||||
// (0)-[1]->(1)-[2]->(2)-[3]->(3)
|
||||
Vertex v0(0);
|
||||
Vertex v1(1); Edge e1(v0, v1, 1);
|
||||
Vertex v2(2); Edge e2(v1, v2, 2);
|
||||
Vertex v3(3); Edge e3(v2, v3, 3);
|
||||
Vertex v1(1);
|
||||
Edge e1(v0, v1, 1);
|
||||
Vertex v2(2);
|
||||
Edge e2(v1, v2, 2);
|
||||
Vertex v3(3);
|
||||
Edge e3(v2, v3, 3);
|
||||
|
||||
// all possible paths
|
||||
std::vector<Path> all_possible{Path().Start(v0)};
|
||||
@ -480,46 +486,49 @@ TEST(Traversal, ExpandVariableFilter) {
|
||||
|
||||
// filter on edge type < 3
|
||||
auto result0 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).
|
||||
ExpandVariable(Expansion::Back, Direction::Out, {},
|
||||
[](const Edge &e) { return e.type_ < 3; }));
|
||||
EXPECT_EQ(result0, std::unordered_set<Path>(all_possible.begin() + 1, all_possible.begin() + 3));
|
||||
Begin(std::vector<Vertex>{v0})
|
||||
.ExpandVariable(Expansion::Back, Direction::Out, {},
|
||||
[](const Edge &e) { return e.type_ < 3; }));
|
||||
EXPECT_EQ(result0, std::unordered_set<Path>(all_possible.begin() + 1,
|
||||
all_possible.begin() + 3));
|
||||
|
||||
// filter on edge type > 1, expect nothing because the first edge is 1
|
||||
auto result1 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).
|
||||
ExpandVariable(Expansion::Back, Direction::Out, {},
|
||||
[](const Edge &e) { return e.type_ > 1; }));
|
||||
Begin(std::vector<Vertex>{v0})
|
||||
.ExpandVariable(Expansion::Back, Direction::Out, {},
|
||||
[](const Edge &e) { return e.type_ > 1; }));
|
||||
EXPECT_EQ(result1.size(), 0);
|
||||
|
||||
// filter on vertex label > 1, expect last 2 results
|
||||
auto result2 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).
|
||||
ExpandVariable(Expansion::Back, Direction::Out,
|
||||
[](const Vertex &v) { return v.label_ > 1; }, {}));
|
||||
EXPECT_EQ(result2, std::unordered_set<Path>(all_possible.end() - 2, all_possible.end()));
|
||||
Begin(std::vector<Vertex>{v0})
|
||||
.ExpandVariable(Expansion::Back, Direction::Out,
|
||||
[](const Vertex &v) { return v.label_ > 1; }, {}));
|
||||
EXPECT_EQ(result2, std::unordered_set<Path>(all_possible.end() - 2,
|
||||
all_possible.end()));
|
||||
}
|
||||
|
||||
TEST(Traversal, ExpandVariableCurrent) {
|
||||
// a chain
|
||||
Vertex v0;
|
||||
Vertex v1; Edge e1(v0, v1);
|
||||
Vertex v2; Edge e2(v1, v2);
|
||||
Vertex v3; Edge e3(v2, v3);
|
||||
Vertex v1;
|
||||
Edge e1(v0, v1);
|
||||
Vertex v2;
|
||||
Edge e2(v1, v2);
|
||||
Vertex v3;
|
||||
Edge e3(v2, v3);
|
||||
|
||||
// ensure that expanded vertices and all edge sets get visited as current
|
||||
std::unordered_set<Vertex> expected_vertices{v1, v2, v3};
|
||||
std::unordered_set<std::list<Edge>> expected_edge_lists{
|
||||
std::list<Edge>{e1},
|
||||
std::list<Edge>{e1, e2},
|
||||
std::list<Edge>{e1, e2, e3}
|
||||
};
|
||||
std::list<Edge>{e1}, std::list<Edge>{e1, e2},
|
||||
std::list<Edge>{e1, e2, e3}};
|
||||
|
||||
std::vector<Vertex> begin_input{v0};
|
||||
auto begin = Begin(begin_input);
|
||||
auto expand = begin.ExpandVariable(Expansion::Back, Direction::Out);
|
||||
|
||||
expand.Visit([&](Path &path){
|
||||
expand.Visit([&](Path &path) {
|
||||
EXPECT_EQ(1, expected_vertices.erase(expand.CurrentVertex()));
|
||||
EXPECT_EQ(1, expected_edge_lists.erase(expand.CurrentEdges()));
|
||||
});
|
||||
@ -531,13 +540,13 @@ TEST(Traversal, EnumExpansion) {
|
||||
Edge e0(v0, v1);
|
||||
|
||||
// Expansion::Back
|
||||
auto result0= accumulate_visited<Path>(
|
||||
auto result0 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).Expand(Expansion::Back, Direction::Out));
|
||||
auto expected0 = std::unordered_set<Path>{Path().Start(v0).Append(e0, v1)};
|
||||
EXPECT_EQ(result0, expected0);
|
||||
|
||||
// Expansion::Front
|
||||
auto result1= accumulate_visited<Path>(
|
||||
auto result1 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).Expand(Expansion::Front, Direction::Out));
|
||||
auto expected1 = std::unordered_set<Path>{Path().Start(v0).Prepend(e0, v1)};
|
||||
EXPECT_EQ(result1, expected1);
|
||||
@ -549,24 +558,22 @@ TEST(Traversal, EnumDirection) {
|
||||
Edge e0(v0, v1), e1(v1, v2);
|
||||
|
||||
// Direction::Out
|
||||
auto result0= accumulate_visited<Path>(
|
||||
auto result0 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v1}).Expand(Expansion::Back, Direction::Out));
|
||||
auto expected0 = std::unordered_set<Path>{Path().Start(v1).Append(e1, v2)};
|
||||
EXPECT_EQ(result0, expected0);
|
||||
|
||||
// Direction::In
|
||||
auto result1= accumulate_visited<Path>(
|
||||
auto result1 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v1}).Expand(Expansion::Back, Direction::In));
|
||||
auto expected1 = std::unordered_set<Path>{Path().Start(v1).Append(e0, v0)};
|
||||
EXPECT_EQ(result1, expected1);
|
||||
|
||||
// Direction::Both
|
||||
auto result2= accumulate_visited<Path>(
|
||||
auto result2 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v1}).Expand(Expansion::Back, Direction::Both));
|
||||
auto expected2 = std::unordered_set<Path>{
|
||||
Path().Start(v1).Append(e0, v0),
|
||||
Path().Start(v1).Append(e1, v2)
|
||||
};
|
||||
auto expected2 = std::unordered_set<Path>{Path().Start(v1).Append(e0, v0),
|
||||
Path().Start(v1).Append(e1, v2)};
|
||||
EXPECT_EQ(result2, expected2);
|
||||
}
|
||||
|
||||
@ -577,30 +584,28 @@ TEST(Traversal, EnumUniqueness) {
|
||||
|
||||
// Uniqueness::Edge
|
||||
auto result0 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).
|
||||
Expand(Expansion::Back, Direction::Out, {}, {}, Uniqueness::Edge).
|
||||
Expand(Expansion::Back, Direction::Out));
|
||||
auto expected0 = std::unordered_set<Path>{
|
||||
Path().Start(v0).Append(e0, v0).Append(e1, v1)
|
||||
};
|
||||
Begin(std::vector<Vertex>{v0})
|
||||
.Expand(Expansion::Back, Direction::Out, {}, {}, Uniqueness::Edge)
|
||||
.Expand(Expansion::Back, Direction::Out));
|
||||
auto expected0 =
|
||||
std::unordered_set<Path>{Path().Start(v0).Append(e0, v0).Append(e1, v1)};
|
||||
EXPECT_EQ(result0, expected0);
|
||||
|
||||
// Uniqueness::Vertex
|
||||
auto result1 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).
|
||||
Expand(Expansion::Back, Direction::Out, {}, {}, Uniqueness::Vertex).
|
||||
Expand(Expansion::Back, Direction::Out));
|
||||
Begin(std::vector<Vertex>{v0})
|
||||
.Expand(Expansion::Back, Direction::Out, {}, {}, Uniqueness::Vertex)
|
||||
.Expand(Expansion::Back, Direction::Out));
|
||||
EXPECT_EQ(result1.size(), 0);
|
||||
|
||||
// Uniqueness::None
|
||||
auto result2 = accumulate_visited<Path>(
|
||||
Begin(std::vector<Vertex>{v0}).
|
||||
Expand(Expansion::Back, Direction::Out, {}, {}, Uniqueness::None).
|
||||
Expand(Expansion::Back, Direction::Out));
|
||||
auto expected2 = std::unordered_set<Path>{
|
||||
Path().Start(v0).Append(e0, v0).Append(e1, v1),
|
||||
Path().Start(v0).Append(e0, v0).Append(e0, v0)
|
||||
};
|
||||
Begin(std::vector<Vertex>{v0})
|
||||
.Expand(Expansion::Back, Direction::Out, {}, {}, Uniqueness::None)
|
||||
.Expand(Expansion::Back, Direction::Out));
|
||||
auto expected2 =
|
||||
std::unordered_set<Path>{Path().Start(v0).Append(e0, v0).Append(e1, v1),
|
||||
Path().Start(v0).Append(e0, v0).Append(e0, v0)};
|
||||
EXPECT_EQ(result2, expected2);
|
||||
}
|
||||
|
||||
@ -624,11 +629,11 @@ TEST(Traversal, Cartesian) {
|
||||
std::unordered_set<Paths> expected;
|
||||
for (auto &path1 : paths0_set)
|
||||
for (auto &path2 : paths1_set)
|
||||
for (auto &path3: paths0_set) {
|
||||
for (auto &path3 : paths0_set) {
|
||||
Paths paths;
|
||||
paths.emplace_back(std::ref(const_cast<Path&>(path1)));
|
||||
paths.emplace_back(std::ref(const_cast<Path&>(path2)));
|
||||
paths.emplace_back(std::ref(const_cast<Path&>(path3)));
|
||||
paths.emplace_back(std::ref(const_cast<Path &>(path1)));
|
||||
paths.emplace_back(std::ref(const_cast<Path &>(path2)));
|
||||
paths.emplace_back(std::ref(const_cast<Path &>(path3)));
|
||||
expected.insert(paths);
|
||||
}
|
||||
EXPECT_EQ(8, expected.size());
|
||||
@ -651,7 +656,7 @@ TEST(Traversal, UniquenessSubgroups) {
|
||||
// counts the number of visits to the visitable
|
||||
auto visit_counter = [](const auto &visitable) {
|
||||
auto r_val = 0;
|
||||
visitable.Visit([&r_val](const auto &x) {r_val++;});
|
||||
visitable.Visit([&r_val](const auto &x) { r_val++; });
|
||||
return r_val;
|
||||
};
|
||||
|
||||
@ -666,16 +671,20 @@ TEST(Traversal, UniquenessSubgroups) {
|
||||
|
||||
// edge uniqueness sharing
|
||||
{
|
||||
auto paths0 = Begin(begin_v).Expand(Expansion::Back, Direction::Out, {}, {}, Uniqueness::Edge);
|
||||
auto paths1 = Begin(begin_v).Expand(Expansion::Back, Direction::Out, {}, {}, Uniqueness::Edge);
|
||||
auto paths0 = Begin(begin_v).Expand(Expansion::Back, Direction::Out, {}, {},
|
||||
Uniqueness::Edge);
|
||||
auto paths1 = Begin(begin_v).Expand(Expansion::Back, Direction::Out, {}, {},
|
||||
Uniqueness::Edge);
|
||||
paths1.UniquenessGroup().Add(paths0.UniquenessGroup());
|
||||
EXPECT_EQ(2, visit_counter(Cartesian(paths0, paths1)));
|
||||
}
|
||||
|
||||
// vertex uniqueness sharing
|
||||
{
|
||||
auto paths0 = Begin(begin_v).Expand(Expansion::Back, Direction::Out, {}, {}, Uniqueness::Vertex);
|
||||
auto paths1 = Begin(begin_v).Expand(Expansion::Back, Direction::Out, {}, {}, Uniqueness::Vertex);
|
||||
auto paths0 = Begin(begin_v).Expand(Expansion::Back, Direction::Out, {}, {},
|
||||
Uniqueness::Vertex);
|
||||
auto paths1 = Begin(begin_v).Expand(Expansion::Back, Direction::Out, {}, {},
|
||||
Uniqueness::Vertex);
|
||||
paths1.UniquenessGroup().Add(paths0.UniquenessGroup());
|
||||
EXPECT_EQ(0, visit_counter(Cartesian(paths0, paths1)));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user