Reformated code acording to format rules in .clang-format.

This commit is contained in:
Kruno Tomola Fabro 2016-07-31 13:56:13 +01:00
parent 246cf1fd78
commit bf174644de
20 changed files with 282 additions and 188 deletions

View File

@ -20,7 +20,7 @@ AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterEnum: true
@ -46,7 +46,7 @@ DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories:
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|isl|json)/)'
@ -87,4 +87,3 @@ Standard: "C++11"
TabWidth: 8
UseTab: Never
...

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ memgraph
*.session.yaml
tags
.gdb_history
Testing/

View File

@ -5,37 +5,46 @@
using std::pair;
template <typename K, typename T> class ConcurrentMap {
template <typename K, typename T>
class ConcurrentMap
{
class Item : public TotalOrdering<Item>,
public TotalOrdering<K, Item>,
public TotalOrdering<Item, K>,
public pair<const K, T> {
public:
public pair<const K, T>
{
public:
using pair<const K, T>::pair;
friend constexpr bool operator<(const Item &lhs, const Item &rhs) {
friend constexpr bool operator<(const Item &lhs, const Item &rhs)
{
std::pair<const K, T> *a;
return lhs.first < rhs.first;
}
friend constexpr bool operator==(const Item &lhs, const Item &rhs) {
friend constexpr bool operator==(const Item &lhs, const Item &rhs)
{
return lhs.first == rhs.first;
}
friend constexpr bool operator<(const K &lhs, const Item &rhs) {
friend constexpr bool operator<(const K &lhs, const Item &rhs)
{
return lhs < rhs.first;
}
friend constexpr bool operator==(const K &lhs, const Item &rhs) {
friend constexpr bool operator==(const K &lhs, const Item &rhs)
{
return lhs == rhs.first;
}
friend constexpr bool operator<(const Item &lhs, const K &rhs) {
friend constexpr bool operator<(const Item &lhs, const K &rhs)
{
return lhs.first < rhs;
}
friend constexpr bool operator==(const Item &lhs, const K &rhs) {
friend constexpr bool operator==(const Item &lhs, const K &rhs)
{
return lhs.first == rhs;
}
};
@ -44,16 +53,17 @@ template <typename K, typename T> class ConcurrentMap {
typedef typename SkipList<Item>::Iterator list_it;
typedef typename SkipList<Item>::ConstIterator list_it_con;
public:
public:
ConcurrentMap() {}
friend class Accessor;
class Accessor {
class Accessor
{
friend class ConcurrentMap;
Accessor(list *skiplist) : accessor(skiplist->access()) {}
public:
public:
Accessor(const Accessor &) = delete;
Accessor(Accessor &&other) : accessor(std::move(other.accessor)) {}
@ -72,15 +82,18 @@ public:
list_it_con cend() const { return accessor.cend(); }
std::pair<list_it, bool> insert(const K &key, const T &data) {
std::pair<list_it, bool> insert(const K &key, const T &data)
{
return accessor.insert(Item(key, data));
}
std::pair<list_it, bool> insert(const K &key, T &&data) {
std::pair<list_it, bool> insert(const K &key, T &&data)
{
return accessor.insert(Item(key, std::forward<T>(data)));
}
std::pair<list_it, bool> insert(K &&key, T &&data) {
std::pair<list_it, bool> insert(K &&key, T &&data)
{
return accessor.insert(Item(std::forward<K>(key), std::forward<T>(data)));
}
@ -94,7 +107,7 @@ public:
size_t size() const { return accessor.size(); }
private:
private:
typename list::Accessor accessor;
};
@ -102,6 +115,6 @@ public:
const Accessor access() const { return Accessor(&skiplist); }
private:
private:
list skiplist;
};

View File

@ -94,8 +94,9 @@
* and deletion of nodes.
*/
template <class T, size_t H = 32, class lock_t = SpinLock>
class SkipList : private Lockable<lock_t> {
public:
class SkipList : private Lockable<lock_t>
{
public:
// computes the height for the new node from the interval [1...H]
// with p(k) = (1/2)^k for all k from the interval
static thread_local FastBinomial<H> rnd;
@ -106,8 +107,10 @@ public:
* FULLY_LINKED is used to mark the node as fully inserted, i.e. linked
* at all layers in the skiplist up to the node height
*/
struct Flags {
enum node_flags : uint8_t {
struct Flags
{
enum node_flags : uint8_t
{
MARKED = 0x01,
FULLY_LINKED = 0x10,
};
@ -120,12 +123,13 @@ public:
void set_fully_linked() { flags.fetch_or(FULLY_LINKED); }
private:
private:
std::atomic<uint8_t> flags{0};
};
class Node : Lockable<lock_t> {
public:
class Node : Lockable<lock_t>
{
public:
friend class SkipList;
const uint8_t height;
@ -135,17 +139,20 @@ public:
const T &value() const { return data.get(); }
static Node *sentinel(uint8_t height) {
static Node *sentinel(uint8_t height)
{
// we have raw memory and we need to construct an object
// of type Node on it
return new (allocate(height)) Node(height);
}
static Node *create(const T &item, uint8_t height) {
static Node *create(const T &item, uint8_t height)
{
return create(item, height);
}
static Node *create(T &&item, uint8_t height) {
static Node *create(T &&item, uint8_t height)
{
auto node = allocate(height);
// we have raw memory and we need to construct an object
@ -153,7 +160,8 @@ public:
return new (node) Node(std::forward<T>(item), height);
}
static void destroy(Node *node) {
static void destroy(Node *node)
{
node->~Node();
std::free(node);
}
@ -162,8 +170,9 @@ public:
void forward(size_t level, Node *next) { tower[level].store(next); }
private:
Node(uint8_t height) : height(height) {
private:
Node(uint8_t height) : height(height)
{
// here we assume, that the memory for N towers (N = height) has
// been allocated right after the Node structure so we need to
// initialize that memory
@ -171,16 +180,19 @@ public:
new (&tower[i]) std::atomic<Node *>{nullptr};
}
Node(T &&data, uint8_t height) : Node(height) {
Node(T &&data, uint8_t height) : Node(height)
{
this->data.set(std::forward<T>(data));
}
~Node() {
~Node()
{
for (auto i = 0; i < height; ++i)
tower[i].~atomic();
}
static Node *allocate(uint8_t height) {
static Node *allocate(uint8_t height)
{
// [ Node ][Node*][Node*][Node*]...[Node*]
// | | | | |
// | 0 1 2 height-1
@ -205,33 +217,39 @@ public:
std::atomic<Node *> tower[0];
};
public:
template <class It> class IteratorBase : public Crtp<It> {
protected:
public:
template <class It>
class IteratorBase : public Crtp<It>
{
protected:
IteratorBase(Node *node) : node(node) {}
Node *node{nullptr};
public:
public:
IteratorBase() = default;
IteratorBase(const IteratorBase &) = default;
T &operator*() {
T &operator*()
{
assert(node != nullptr);
return node->value();
}
T *operator->() {
T *operator->()
{
assert(node != nullptr);
return &node->value();
}
operator T &() {
operator T &()
{
assert(node != nullptr);
return node->value();
}
It &operator++() {
It &operator++()
{
assert(node != nullptr);
node = node->forward(0);
return this->derived();
@ -239,18 +257,20 @@ public:
It &operator++(int) { return operator++(); }
friend bool operator==(const It &a, const It &b) {
friend bool operator==(const It &a, const It &b)
{
return a.node == b.node;
}
friend bool operator!=(const It &a, const It &b) { return !(a == b); }
};
class ConstIterator : public IteratorBase<ConstIterator> {
class ConstIterator : public IteratorBase<ConstIterator>
{
friend class SkipList;
ConstIterator(Node *node) : IteratorBase<ConstIterator>(node) {}
public:
public:
ConstIterator() = default;
ConstIterator(const ConstIterator &) = default;
@ -261,18 +281,20 @@ public:
operator const T &() { return IteratorBase<ConstIterator>::operator T &(); }
};
class Iterator : public IteratorBase<Iterator> {
class Iterator : public IteratorBase<Iterator>
{
friend class SkipList;
Iterator(Node *node) : IteratorBase<Iterator>(node) {}
public:
public:
Iterator() = default;
Iterator(const Iterator &) = default;
};
SkipList() : header(Node::sentinel(H)) {}
~SkipList() {
~SkipList()
{
// Someone could be using this map through an Accessor.
Node *now = header;
header = nullptr;
@ -286,25 +308,28 @@ public:
friend class Accessor;
class Accessor {
class Accessor
{
friend class SkipList;
Accessor(SkipList *skiplist) : skiplist(skiplist) {
Accessor(SkipList *skiplist) : skiplist(skiplist)
{
assert(skiplist != nullptr);
skiplist->gc.add_ref();
}
public:
public:
Accessor(const Accessor &) = delete;
Accessor(Accessor &&other) : skiplist(other.skiplist) {
Accessor(Accessor &&other) : skiplist(other.skiplist)
{
other.skiplist = nullptr;
}
~Accessor() {
if (skiplist == nullptr)
return;
~Accessor()
{
if (skiplist == nullptr) return;
skiplist->gc.release_ref();
}
@ -321,33 +346,43 @@ public:
ConstIterator cend() const { return skiplist->cend(); }
std::pair<Iterator, bool> insert(const T &item) {
std::pair<Iterator, bool> insert(const T &item)
{
return skiplist->insert(item, preds, succs);
}
std::pair<Iterator, bool> insert(T &&item) {
std::pair<Iterator, bool> insert(T &&item)
{
return skiplist->insert(std::forward<T>(item), preds, succs);
}
template <class K> ConstIterator find(const K &item) const {
template <class K>
ConstIterator find(const K &item) const
{
return static_cast<const SkipList &>(*skiplist).find(item);
}
template <class K> Iterator find(const K &item) {
template <class K>
Iterator find(const K &item)
{
return skiplist->find(item);
}
template <class K> bool contains(const K &item) const {
template <class K>
bool contains(const K &item) const
{
return this->find(item) != this->end();
}
template <class K> bool remove(const K &item) {
template <class K>
bool remove(const K &item)
{
return skiplist->remove(item, preds, succs);
}
size_t size() const { return skiplist->size(); }
private:
private:
SkipList *skiplist;
Node *preds[H], *succs[H];
};
@ -356,7 +391,7 @@ public:
const Accessor access() const { return Accessor(this); }
private:
private:
using guard_t = std::unique_lock<lock_t>;
Iterator begin() { return Iterator(header->forward(0)); }
@ -373,23 +408,33 @@ private:
size_t size() const { return count.load(); }
template <class K> bool greater(const K &item, const Node *const node) {
template <class K>
bool greater(const K &item, const Node *const node)
{
return node && item > node->value();
}
template <class K> bool less(const K &item, const Node *const node) {
template <class K>
bool less(const K &item, const Node *const node)
{
return (node == nullptr) || item < node->value();
}
template <class K> ConstIterator find(const K &item) const {
template <class K>
ConstIterator find(const K &item) const
{
return const_cast<SkipList *>(this)->find_node<ConstIterator, K>(item);
}
template <class K> Iterator find(const K &item) {
template <class K>
Iterator find(const K &item)
{
return find_node<Iterator, K>(item);
}
template <class It, class K> It find_node(const K &item) {
template <class It, class K>
It find_node(const K &item)
{
Node *node, *pred = header;
int h = static_cast<int>(pred->height) - 1;
@ -399,8 +444,7 @@ private:
}
// if we overshoot at every layer, item doesn't exist
if (h < 0)
return It();
if (h < 0) return It();
// the item is farther to the right, continue going right as long
// as the key is greater than the current node's key
@ -408,14 +452,14 @@ private:
pred = node, node = node->forward(h);
// check if we have a hit. if not, we need to descend down again
if (!less(item, node) && !node->flags.is_marked())
return It(node);
if (!less(item, node) && !node->flags.is_marked()) return It(node);
}
}
template <class K>
int find_path(Node *from, int start, const K &item, Node *preds[],
Node *succs[]) {
Node *succs[])
{
int level_found = -1;
Node *pred = from;
@ -425,8 +469,7 @@ private:
while (greater(item, node))
pred = node, node = pred->forward(level);
if (level_found == -1 && !less(item, node))
level_found = level;
if (level_found == -1 && !less(item, node)) level_found = level;
preds[level] = pred;
succs[level] = node;
@ -437,7 +480,8 @@ private:
template <bool ADDING>
bool lock_nodes(uint8_t height, guard_t guards[], Node *preds[],
Node *succs[]) {
Node *succs[])
{
Node *prepred, *pred, *succ = nullptr;
bool valid = true;
@ -456,7 +500,8 @@ private:
return valid;
}
std::pair<Iterator, bool> insert(T &&data, Node *preds[], Node *succs[]) {
std::pair<Iterator, bool> insert(T &&data, Node *preds[], Node *succs[])
{
while (true) {
// TODO: before here was data.first
auto level = find_path(header, H - 1, data, preds, succs);
@ -464,8 +509,7 @@ private:
if (level != -1) {
auto found = succs[level];
if (found->flags.is_marked())
continue;
if (found->flags.is_marked()) continue;
while (!found->flags.is_fully_linked())
usleep(250);
@ -479,8 +523,7 @@ private:
// try to acquire the locks for predecessors up to the height of
// the new node. release the locks and try again if someone else
// has the locks
if (!lock_nodes<true>(height, guards, preds, succs))
continue;
if (!lock_nodes<true>(height, guards, preds, succs)) continue;
// you have the locks, create a new node
auto new_node = Node::create(std::forward<T>(data), height);
@ -503,12 +546,15 @@ private:
}
}
bool ok_delete(Node *node, int level) {
bool ok_delete(Node *node, int level)
{
return node->flags.is_fully_linked() && node->height - 1 == level &&
!node->flags.is_marked();
}
template <class K> bool remove(const K &item, Node *preds[], Node *succs[]) {
template <class K>
bool remove(const K &item, Node *preds[], Node *succs[])
{
Node *node = nullptr;
guard_t node_guard;
bool marked = false;
@ -525,8 +571,7 @@ private:
height = node->height;
node_guard = node->acquire_unique();
if (node->flags.is_marked())
return false;
if (node->flags.is_marked()) return false;
node->flags.set_marked();
marked = true;
@ -534,8 +579,7 @@ private:
guard_t guards[H];
if (!lock_nodes<false>(height, guards, preds, succs))
continue;
if (!lock_nodes<false>(height, guards, preds, succs)) continue;
for (int level = height - 1; level >= 0; --level)
preds[level]->forward(level, node->forward(level));

View File

@ -8,8 +8,9 @@
#include "threading/sync/spinlock.hpp"
template <class T, class lock_t = SpinLock>
class SkiplistGC : public LazyGC<SkiplistGC<T, lock_t>, lock_t> {
public:
class SkiplistGC : public LazyGC<SkiplistGC<T, lock_t>, lock_t>
{
public:
// release_ref method should be called by a thread
// when the thread finish it job over object
// which has to be lazy cleaned
@ -17,7 +18,8 @@ public:
// are going to be deleted
// the only problem with this approach is that
// GC may never be called, but for now we can deal with that
void release_ref() {
void release_ref()
{
std::vector<T *> local_freelist;
// take freelist if there is no more threads
@ -47,6 +49,6 @@ public:
void collect(T *node) { freelist.add(node); }
private:
private:
FreeList<T> freelist;
};

View File

@ -8,17 +8,19 @@
#include "utils/crtp.hpp"
template <class Derived, class lock_t = SpinLock>
class LazyGC : public Crtp<Derived>, public Lockable<lock_t> {
public:
class LazyGC : public Crtp<Derived>, public Lockable<lock_t>
{
public:
// add_ref 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 add_ref() {
void add_ref()
{
auto lock = this->acquire_unique();
++count;
}
protected:
protected:
size_t count{0};
};

View File

@ -4,25 +4,26 @@
#include "data_structures/concurrent/concurrent_map.hpp"
#include "edge_accessor.hpp"
class Edges {
public:
Edge::Accessor find(tx::Transaction &t, const Id &id) {
class Edges
{
public:
Edge::Accessor find(tx::Transaction &t, const Id &id)
{
auto edges_accessor = edges.access();
auto edges_iterator = edges_accessor.find(id);
if (edges_iterator == edges_accessor.end())
return Edge::Accessor();
if (edges_iterator == edges_accessor.end()) return Edge::Accessor();
// find edge
auto edge = edges_iterator->second.find(t);
if (edge == nullptr)
return Edge::Accessor();
if (edge == nullptr) return Edge::Accessor();
return Edge::Accessor(edge, &edges_iterator->second, this);
}
Edge::Accessor insert(tx::Transaction &t) {
Edge::Accessor insert(tx::Transaction &t)
{
// get next vertex id
auto next = counter.next(std::memory_order_acquire);
@ -40,7 +41,7 @@ public:
return Edge::Accessor(edge, &inserted_edge_record->second, this);
}
private:
private:
ConcurrentMap<uint64_t, EdgeRecord> edges;
AtomicCounter<uint64_t> counter;
};

View File

@ -7,13 +7,16 @@
#include "storage/indexes/index_record_collection.hpp"
#include "storage/label/label.hpp"
template <class Key, class Item> class Index {
public:
template <class Key, class Item>
class Index
{
public:
using container_t = ConcurrentMap<Key, Item>;
Index() : index(std::make_unique<container_t>()) {}
auto update(const Label &label, VertexIndexRecord &&index_record) {
auto update(const Label &label, VertexIndexRecord &&index_record)
{
auto accessor = index->access();
auto label_ref = label_ref_t(label);
@ -27,7 +30,8 @@ public:
record_collection.add(std::forward<VertexIndexRecord>(index_record));
}
VertexIndexRecordCollection &find(const Label &label) {
VertexIndexRecordCollection &find(const Label &label)
{
// TODO: accessor should be outside?
// bacause otherwise GC could delete record that has just be returned
auto label_ref = label_ref_t(label);
@ -35,6 +39,6 @@ public:
return (*accessor.find(label_ref)).second;
}
private:
private:
std::unique_ptr<container_t> index;
};

View File

@ -1,22 +1,22 @@
#include "storage/vertices.hpp"
const Vertex::Accessor Vertices::find(tx::Transaction &t, const Id &id) {
const Vertex::Accessor Vertices::find(tx::Transaction &t, const Id &id)
{
auto vertices_accessor = vertices.access();
auto vertices_iterator = vertices_accessor.find(id);
if (vertices_iterator == vertices_accessor.end())
return Vertex::Accessor();
if (vertices_iterator == vertices_accessor.end()) return Vertex::Accessor();
// find vertex
auto vertex = vertices_iterator->second.find(t);
if (vertex == nullptr)
return Vertex::Accessor();
if (vertex == nullptr) return Vertex::Accessor();
return Vertex::Accessor(vertex, &vertices_iterator->second, this);
}
Vertex::Accessor Vertices::insert(tx::Transaction &t) {
Vertex::Accessor Vertices::insert(tx::Transaction &t)
{
// get next vertex id
auto next = counter.next();
@ -36,10 +36,12 @@ Vertex::Accessor Vertices::insert(tx::Transaction &t) {
}
void Vertices::update_label_index(const Label &label,
VertexIndexRecord &&index_record) {
VertexIndexRecord &&index_record)
{
label_index.update(label, std::forward<VertexIndexRecord>(index_record));
}
VertexIndexRecordCollection &Vertices::find_label_index(const Label &label) {
VertexIndexRecordCollection &Vertices::find_label_index(const Label &label)
{
return label_index.find(label);
}

View File

@ -1,19 +1,25 @@
#pragma once
template <class Derived, class Other = Derived> struct TotalOrdering {
friend constexpr bool operator!=(const Derived &a, const Other &b) {
template <class Derived, class Other = Derived>
struct TotalOrdering
{
friend constexpr bool operator!=(const Derived &a, const Other &b)
{
return !(a == b);
}
friend constexpr bool operator<=(const Derived &a, const Other &b) {
friend constexpr bool operator<=(const Derived &a, const Other &b)
{
return a < b || a == b;
}
friend constexpr bool operator>(const Derived &a, const Other &b) {
friend constexpr bool operator>(const Derived &a, const Other &b)
{
return !(a <= b);
}
friend constexpr bool operator>=(const Derived &a, const Other &b) {
friend constexpr bool operator>=(const Derived &a, const Other &b)
{
return !(a < b);
}
};

View File

@ -19,26 +19,30 @@ using skiplist_t = ConcurrentMap<int, int>;
using namespace std::chrono_literals;
// Returns uniform random size_t generator from range [0,n>
auto rand_gen(size_t 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);
}
// Returns random bool generator with distribution of 1 true for n false.
auto rand_gen_bool(size_t n = 1) {
auto rand_gen_bool(size_t n = 1)
{
auto gen = rand_gen(n + 1);
return [=]() mutable { return gen() == 0; };
}
// Checks for all owned.second keys if there data is owned.first.
void check_present_same(skiplist_t::Accessor &acc,
std::pair<size_t, std::vector<size_t>> &owned) {
std::pair<size_t, std::vector<size_t>> &owned)
{
check_present_same(acc, owned.first, owned.second);
}
// Checks for all owned keys if there data is data.
void check_present_same(skiplist_t::Accessor &acc, size_t data,
std::vector<size_t> &owned) {
std::vector<size_t> &owned)
{
for (auto num : owned) {
permanent_assert(acc.find(num)->second == data,
"My data is present and my");
@ -46,7 +50,8 @@ void check_present_same(skiplist_t::Accessor &acc, size_t data,
}
// Checks if reported size and traversed size are equal to given size.
void check_size(const skiplist_t::Accessor &acc, long long size) {
void check_size(const skiplist_t::Accessor &acc, long long size)
{
// check size
permanent_assert(acc.size() == size,
@ -70,7 +75,8 @@ void check_size(const skiplist_t::Accessor &acc, long long size) {
template <class R>
std::vector<std::future<std::pair<size_t, R>>>
run(size_t threads_no, skiplist_t &skiplist,
std::function<R(skiplist_t::Accessor, size_t)> f) {
std::function<R(skiplist_t::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) {
@ -84,7 +90,9 @@ run(size_t threads_no, skiplist_t &skiplist,
}
// Collects all data from futures.
template <class R> auto collect(std::vector<std::future<R>> &collect) {
template <class R>
auto collect(std::vector<std::future<R>> &collect)
{
std::vector<R> collection;
for (auto &fut : collect) {
collection.push_back(fut.get());
@ -96,7 +104,8 @@ template <class R> auto collect(std::vector<std::future<R>> &collect) {
// downcounts.
template <class K, class D>
auto insert_try(skiplist_t::Accessor &acc, size_t &downcount,
std::vector<K> &owned) {
std::vector<K> &owned)
{
return [&](K key, D data) mutable {
if (acc.insert(key, data).second) {
downcount--;
@ -106,7 +115,8 @@ auto insert_try(skiplist_t::Accessor &acc, size_t &downcount,
}
// Helper function.
int parseLine(char *line) {
int parseLine(char *line)
{
// This assumes that a digit will be found and the line ends in " Kb".
int i = strlen(line);
const char *p = line;
@ -118,7 +128,8 @@ int parseLine(char *line) {
}
// Returns currentlz used memory in kB.
int currently_used_memory() { // Note: this value is in KB!
int currently_used_memory()
{ // Note: this value is in KB!
FILE *file = fopen("/proc/self/status", "r");
int result = -1;
char line[128];
@ -137,7 +148,8 @@ int currently_used_memory() { // Note: this value is in KB!
// 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) {
void memory_check(size_t no_threads, std::function<void()> f)
{
long long start = currently_used_memory();
f();
long long leaked =

View File

@ -10,51 +10,51 @@ using std::endl;
template <typename list_type>
void test_concurrent_list_access(list_type &list, std::size_t size)
{
// test concurrent access
for (int i = 0; i < 1000000; ++i) {
// test concurrent access
for (int i = 0; i < 1000000; ++i) {
std::thread t1([&list] {
list.push_front(1);
list.pop_front();
});
std::thread t1([&list] {
list.push_front(1);
list.pop_front();
});
std::thread t2([&list] {
list.push_front(2);
list.pop_front();
});
std::thread t2([&list] {
list.push_front(2);
list.pop_front();
});
t1.join();
t2.join();
t1.join();
t2.join();
assert(list.size() == size);
}
assert(list.size() == size);
}
}
int main()
{
LinkedList<int> list;
LinkedList<int> list;
// push & pop operations
list.push_front(10);
list.push_front(20);
auto a = list.front();
assert(a == 20);
list.pop_front();
a = list.front();
assert(a == 10);
list.pop_front();
assert(list.size() == 0);
// push & pop operations
list.push_front(10);
list.push_front(20);
auto a = list.front();
assert(a == 20);
list.pop_front();
a = list.front();
assert(a == 10);
list.pop_front();
assert(list.size() == 0);
// concurrent test
LinkedList<int> concurrent_list;
concurrent_list.push_front(1);
concurrent_list.push_front(1);
std::list<int> no_concurrent_list;
no_concurrent_list.push_front(1);
no_concurrent_list.push_front(1);
test_concurrent_list_access(concurrent_list, 2);
// test_concurrent_list_access(no_concurrent_list, 2);
// concurrent test
LinkedList<int> concurrent_list;
concurrent_list.push_front(1);
concurrent_list.push_front(1);
std::list<int> no_concurrent_list;
no_concurrent_list.push_front(1);
no_concurrent_list.push_front(1);
return 0;
test_concurrent_list_access(concurrent_list, 2);
// test_concurrent_list_access(no_concurrent_list, 2);
return 0;
}

View File

@ -3,7 +3,8 @@
#define THREADS_NO 1
constexpr size_t elems_per_thread = 16e5;
int main() {
int main()
{
memory_check(THREADS_NO, [&] {
ds::static_array<std::thread, THREADS_NO> threads;
skiplist_t skiplist;
@ -33,15 +34,15 @@ int main() {
}
for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i) {
threads[thread_i] = std::thread(
[&skiplist](size_t start, size_t end) {
auto accessor = skiplist.access();
for (size_t elem_i = 0; elem_i < elems_per_thread; ++elem_i) {
permanent_assert(accessor.remove(elem_i) == true, "");
}
},
thread_i * elems_per_thread,
thread_i * elems_per_thread + elems_per_thread);
threads[thread_i] = std::thread(
[&skiplist](size_t start, size_t end) {
auto accessor = skiplist.access();
for (size_t elem_i = 0; elem_i < elems_per_thread; ++elem_i) {
permanent_assert(accessor.remove(elem_i) == true, "");
}
},
thread_i * elems_per_thread,
thread_i * elems_per_thread + elems_per_thread);
}
// wait all threads
for (auto &thread : threads) {

View File

@ -7,7 +7,8 @@ constexpr size_t key_range = elems_per_thread * THREADS_NO * 2;
// This test checks insert_unique method under pressure.
// Test checks for missing data and changed/overwriten data.
int main() {
int main()
{
memory_check(THREADS_NO, [] {
skiplist_t skiplist;

View File

@ -8,7 +8,8 @@ constexpr size_t key_range = elems_per_thread * THREADS_NO * 2;
// Threads will try to insert keys in the same order.
// This will force threads to compete intensly with each other.
// Test checks for missing data and changed/overwriten data.
int main() {
int main()
{
memory_check(THREADS_NO, [] {
skiplist_t skiplist;

View File

@ -5,7 +5,8 @@
constexpr size_t elements = 2e6;
// Test for simple memory leaks
int main() {
int main()
{
memory_check(THREADS_NO, [] {
skiplist_t skiplist;

View File

@ -10,7 +10,8 @@ constexpr size_t no_insert_for_one_delete = 2;
// Threads will try to insert and remove keys aproximetly in the same order.
// This will force threads to compete intensly with each other.
// Calls of remove method are interleaved with insert calls.
int main() {
int main()
{
memory_check(THREADS_NO, [] {
skiplist_t skiplist;

View File

@ -8,7 +8,8 @@ constexpr size_t no_insert_for_one_delete = 1;
// This test checks remove method under pressure.
// Each thread removes it's own data. So removes are disjoint.
// Calls of remove method are interleaved with insert calls.
int main() {
int main()
{
memory_check(THREADS_NO, [] {
skiplist_t skiplist;

View File

@ -10,7 +10,8 @@ constexpr size_t no_insert_for_one_delete = 2;
// This test checks remove method under pressure.
// Each thread removes random data. So removes are joint.
// Calls of remove method are interleaved with insert calls.
int main() {
int main()
{
memory_check(THREADS_NO, [] {
skiplist_t skiplist;

View File

@ -12,7 +12,8 @@ constexpr size_t no_insert_for_one_delete = 1;
// Each thread makes a series of finds interleaved with method which change.
// Exact ratio of finds per change and insert per delete can be regulated with
// no_find_per_change and no_insert_for_one_delete.
int main() {
int main()
{
memory_check(THREADS_NO, [] {
skiplist_t skiplist;