Database interface refactor.

DbAccessor:
 -Guarantees that access to Vertex and Edge is possible only through
 Vertex::Accessor and Edge::Accessor.
 -Guarantees that changing Vertex and Edge is possible only using
 Vertex::Accessor returned by vertex_insert() method and
 Edge::Accessor returned by edge_insert() method.
 -Offers CRUD for Vertex and Edge except iterating over all edges.

Squashed commit messages:

First step in database accessor refactoring done.
It's compiling.
All tests with exception of integration_querys pass

Tests now initialize logging facilities.

Refactored accessors.
RecordAccessor now has 3 states.
From,To,Out,In in there respecive Accessors return unfilled RecordAccessor.
Added iterator classes into utils/itearator/.
This commit is contained in:
Kruno Tomola Fabro
2016-08-15 00:09:58 +01:00
parent 2113546b9c
commit df0bf6fa5f
53 changed files with 999 additions and 413 deletions

View File

@@ -1,13 +1,13 @@
#pragma once
#include "communication/bolt/v1/transport/bolt_encoder.hpp"
#include "communication/bolt/v1/packing/codes.hpp"
#include "communication/bolt/v1/transport/bolt_encoder.hpp"
#include "storage/vertex_accessor.hpp"
#include "storage/edge_accessor.hpp"
#include "storage/vertex_accessor.hpp"
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/all.hpp"
#include "storage/model/properties/properties.hpp"
namespace bolt
{
@@ -22,7 +22,7 @@ class BoltSerializer
// friend void accept(const Property &property, Handler &h);
public:
BoltSerializer(Stream& stream) : encoder(stream) {}
BoltSerializer(Stream &stream) : encoder(stream) {}
/* Serializes the vertex accessor into the packstream format
*
@@ -33,7 +33,7 @@ public:
* }
*
*/
void write(const Vertex::Accessor& vertex)
void write(const Vertex::Accessor &vertex)
{
// write signatures for the node struct and node data type
encoder.write_struct_header(3);
@@ -47,7 +47,7 @@ public:
encoder.write_list_header(labels.size());
for(auto& label : labels)
for (auto &label : labels)
encoder.write_string(label.get());
// write the property map
@@ -55,7 +55,7 @@ public:
encoder.write_map_header(props.size());
for(auto& prop : props) {
for (auto &prop : props) {
write(prop.first);
write(*prop.second);
}
@@ -72,7 +72,7 @@ public:
* }
*
*/
void write(const Edge::Accessor& edge)
void write(const Edge::Accessor &edge)
{
// write signatures for the edge struct and edge data type
encoder.write_struct_header(5);
@@ -82,8 +82,8 @@ public:
encoder.write_integer(edge.id());
// TODO refactor when from() and to() start returning Accessors
encoder.write_integer(edge.from()->id);
encoder.write_integer(edge.to()->id);
encoder.write_integer(edge.from().id());
encoder.write_integer(edge.to().id());
// write the type of the edge
encoder.write_string(edge.edge_type());
@@ -93,65 +93,37 @@ public:
encoder.write_map_header(props.size());
for(auto& prop : props) {
for (auto &prop : props) {
write(prop.first);
write(*prop.second);
}
}
void write(const Property& prop)
{
accept(prop, *this);
}
void write(const Property &prop) { accept(prop, *this); }
void write_null()
{
encoder.write_null();
}
void write_null() { encoder.write_null(); }
void write(const Bool& prop)
{
encoder.write_bool(prop.value());
}
void write(const Bool &prop) { encoder.write_bool(prop.value()); }
void write(const Float& prop)
{
encoder.write_double(prop.value);
}
void write(const Float &prop) { encoder.write_double(prop.value); }
void write(const Double& prop)
{
encoder.write_double(prop.value);
}
void write(const Double &prop) { encoder.write_double(prop.value); }
void write(const Int32& prop)
{
encoder.write_integer(prop.value);
}
void write(const Int32 &prop) { encoder.write_integer(prop.value); }
void write(const Int64& prop)
{
encoder.write_integer(prop.value);
}
void write(const Int64 &prop) { encoder.write_integer(prop.value); }
void write(const std::string& value)
{
encoder.write_string(value);
}
void write(const std::string &value) { encoder.write_string(value); }
void write(const String& prop)
{
encoder.write_string(prop.value);
}
void write(const String &prop) { encoder.write_string(prop.value); }
template <class T>
void handle(const T& prop)
void handle(const T &prop)
{
write(prop);
}
protected:
Stream& encoder;
Stream &encoder;
};
}

View File

@@ -1,25 +1,22 @@
#pragma once
#include "storage/graph.hpp"
// #include "transactions/commit_log.hpp"
#include "transactions/engine.hpp"
#include "transactions/commit_log.hpp"
class Db
{
public:
using sptr = std::shared_ptr<Db>;
Db() = default;
Db(const std::string& name) : name_(name) {}
Db(const Db& db) = delete;
Db();
Db(const std::string &name);
Db(const Db &db) = delete;
Graph graph;
tx::Engine tx_engine;
std::string& name()
{
return name_;
}
std::string &name();
private:
std::string name_;

View File

@@ -0,0 +1,91 @@
#pragma once
#include "database/db.hpp"
#include "database/db_accessor.hpp"
#include "storage/record_accessor.hpp"
#include "storage/vertex.hpp"
#include "storage/vertex_accessor.hpp"
#include "storage/vertices.hpp"
#include "transactions/transaction.hpp"
#include "utils/iterator/iterator.hpp"
#include "utils/option.hpp"
/*
* DbAccessor
* -Guarantees that access to Vertex and Edge is possible only through
* Vertex::Accessor and Edge::Accessor.
* -Guarantees that changing Vertex and Edge is possible only using
* Vertex::Accessor returned by vertex_insert() method and
* Edge::Accessor returned by edge_insert() method.
* -Offers CRUD for Vertex and Edge except iterating over all edges.
*
* Vertex::Accessor
* By default Vertex::accessor is empty. Caller has to call fill() method
* to fetch valid data and check it's return value. fill() method returns
* true if there is valid data for current transaction false otherwise.
* Only exception to this rule is vertex_insert() method in DbAccessor
* which returns by default filled Vertex::Accessor.
*
* Edge::Accessor
* By default Edge::accessor is empty. Caller has to call fill() method
* to
* fetch valid data and check it's return value. fill() method returns
* true
* if there is valid data for current transaction false otherwise.
* Only exception to this rule is edge_insert() method in DbAccessor
* which
* returns by default filled Edge::Accessor.
*/
class DbAccessor
{
public:
DbAccessor(Db &db);
//*******************VERTEX METHODS
auto vertex_access();
Option<const Vertex::Accessor> vertex_find(const Id &id);
// Creates new Vertex and returns filled Vertex::Accessor.
Vertex::Accessor vertex_insert();
//*******************EDGE METHODS
Option<const Edge::Accessor> edge_find(const Id &id);
// Creates new Edge and returns filled Edge::Accessor.
Edge::Accessor edge_insert(Vertex::Accessor const &from,
Vertex::Accessor const &to);
//*******************LABEL METHODS
const Label &label_find_or_create(const std::string &name);
bool label_contains(const std::string &name);
VertexIndexRecordCollection &label_find_index(const Label &label);
//********************TYPE METHODS
const EdgeType &type_find_or_create(const std::string &name);
bool type_contains(const std::string &name);
//********************TRANSACTION METHODS
void commit();
void abort();
private:
DbTransaction db;
};
//**********************CONVENIENT FUNCTIONS
template <class R>
bool option_fill(Option<R> &o)
{
return o.is_present() && o.get().fill();
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "storage/indexes/index_record.hpp"
#include "storage/label/label.hpp"
#include "transactions/transaction.hpp"
class Db;
class DbAccessor;
// Inner structures local to transaction can hold ref to this structure and use
// its methods.
class DbTransaction
{
friend DbAccessor;
public:
DbTransaction(Db &db, tx::Transaction &trans) : db(db), trans(trans) {}
void update_label_index(const Label &label,
VertexIndexRecord &&index_record);
tx::Transaction &trans;
Db &db;
};

View File

@@ -1,6 +1,8 @@
#pragma once
#include "database/db.hpp"
#include "database/db_accessor.cpp"
#include "database/db_accessor.hpp"
#include "query_engine/query_stripper.hpp"
#include "query_engine/util.hpp"
#include "storage/model/properties/property.hpp"
@@ -12,8 +14,8 @@ auto load_queries(Db &db)
// CREATE (n {prop: 0}) RETURN n)
auto create_node = [&db](const properties_t &args) {
auto &t = db.tx_engine.begin();
auto vertex_accessor = db.graph.vertices.insert(t);
DbAccessor t(db);
auto vertex_accessor = t.vertex_insert();
vertex_accessor.property("prop", args[0]);
t.commit();
return true;
@@ -21,10 +23,10 @@ auto load_queries(Db &db)
queries[11597417457737499503u] = create_node;
auto create_labeled_and_named_node = [&db](const properties_t &args) {
auto &t = db.tx_engine.begin();
auto vertex_accessor = db.graph.vertices.insert(t);
DbAccessor t(db);
auto vertex_accessor = t.vertex_insert();
vertex_accessor.property("name", args[0]);
auto &label = db.graph.label_store.find_or_create("LABEL");
auto &label = t.label_find_or_create("LABEL");
vertex_accessor.add_label(label);
cout_properties(vertex_accessor.properties());
t.commit();
@@ -32,13 +34,13 @@ auto load_queries(Db &db)
};
auto create_account = [&db](const properties_t &args) {
auto &t = db.tx_engine.begin();
auto vertex_accessor = db.graph.vertices.insert(t);
DbAccessor t(db);
auto vertex_accessor = t.vertex_insert();
vertex_accessor.property("id", args[0]);
vertex_accessor.property("name", args[1]);
vertex_accessor.property("country", args[2]);
vertex_accessor.property("created_at", args[3]);
auto &label = db.graph.label_store.find_or_create("ACCOUNT");
auto &label = t.label_find_or_create("ACCOUNT");
vertex_accessor.add_label(label);
cout_properties(vertex_accessor.properties());
t.commit();
@@ -46,14 +48,15 @@ auto load_queries(Db &db)
};
auto find_node_by_internal_id = [&db](const properties_t &args) {
auto &t = db.tx_engine.begin();
DbAccessor t(db);
auto id = static_cast<Int32 &>(*args[0]);
auto vertex_accessor = db.graph.vertices.find(t, Id(id.value));
if (!vertex_accessor) {
auto maybe_va = t.vertex_find(Id(id.value));
if (!option_fill(maybe_va)) {
cout << "vertex doesn't exist" << endl;
t.commit();
return false;
}
auto vertex_accessor = maybe_va.get();
cout_properties(vertex_accessor.properties());
cout << "LABELS:" << endl;
for (auto label_ref : vertex_accessor.labels()) {
@@ -64,20 +67,17 @@ auto load_queries(Db &db)
};
auto create_edge = [&db](const properties_t &args) {
auto &t = db.tx_engine.begin();
DbAccessor t(db);
auto v1 = db.graph.vertices.find(t, args[0]->as<Int32>().value);
if (!v1) return t.commit(), false;
auto v1 = t.vertex_find(args[0]->as<Int32>().value);
if (!option_fill(v1)) return t.commit(), false;
auto v2 = db.graph.vertices.find(t, args[1]->as<Int32>().value);
if (!v2) return t.commit(), false;
auto v2 = t.vertex_find(args[1]->as<Int32>().value);
if (!option_fill(v2)) return t.commit(), false;
auto edge_accessor = db.graph.edges.insert(t, v1.vlist, v2.vlist);
auto edge_accessor = t.edge_insert(v1.get(), v2.get());
v1.vlist->update(t)->data.out.add(edge_accessor.vlist);
v2.vlist->update(t)->data.in.add(edge_accessor.vlist);
auto &edge_type = db.graph.edge_type_store.find_or_create("IS");
auto &edge_type = t.type_find_or_create("IS");
edge_accessor.edge_type(edge_type);
t.commit();
@@ -90,20 +90,25 @@ auto load_queries(Db &db)
};
auto find_edge_by_internal_id = [&db](const properties_t &args) {
auto &t = db.tx_engine.begin();
auto edge_accessor = db.graph.edges.find(t, args[0]->as<Int32>().value);
if (!edge_accessor) return t.commit(), false;
DbAccessor t(db);
auto maybe_ea = t.edge_find(args[0]->as<Int32>().value);
if (!option_fill(maybe_ea)) return t.commit(), false;
auto edge_accessor = maybe_ea.get();
// print edge type and properties
cout << "EDGE_TYPE: " << edge_accessor.edge_type() << endl;
auto from = edge_accessor.from();
if (!from.fill()) return t.commit(), false;
cout << "FROM:" << endl;
cout_properties(from->find(t)->data.props);
cout_properties(from->data.props);
auto to = edge_accessor.to();
if (!to.fill()) return t.commit(), false;
cout << "TO:" << endl;
cout_properties(to->find(t)->data.props);
cout_properties(to->data.props);
t.commit();
@@ -111,10 +116,11 @@ auto load_queries(Db &db)
};
auto update_node = [&db](const properties_t &args) {
auto &t = db.tx_engine.begin();
DbAccessor t(db);
auto v = db.graph.vertices.find(t, args[0]->as<Int32>().value);
if (!v) return t.commit(), false;
auto maybe_v = t.vertex_find(args[0]->as<Int32>().value);
if (!option_fill(maybe_v)) return t.commit(), false;
auto v = maybe_v.get();
v.property("name", args[1]);
cout_properties(v.properties());
@@ -127,18 +133,17 @@ auto load_queries(Db &db)
// MATCH (n1), (n2) WHERE ID(n1)=0 AND ID(n2)=1 CREATE (n1)<-[r:IS {age: 25,
// weight: 70}]-(n2) RETURN r
auto create_edge_v2 = [&db](const properties_t &args) {
auto &t = db.tx_engine.begin();
auto n1 = db.graph.vertices.find(t, args[0]->as<Int64>().value);
if (!n1) return t.commit(), false;
auto n2 = db.graph.vertices.find(t, args[1]->as<Int64>().value);
if (!n2) return t.commit(), false;
auto r = db.graph.edges.insert(t, n2.vlist, n1.vlist);
DbAccessor t(db);
auto n1 = t.vertex_find(args[0]->as<Int64>().value);
if (!option_fill(n1)) return t.commit(), false;
auto n2 = t.vertex_find(args[1]->as<Int64>().value);
if (!option_fill(n2)) return t.commit(), false;
auto r = t.edge_insert(n2.get(), n1.get());
r.property("age", args[2]);
r.property("weight", args[3]);
auto &IS = db.graph.edge_type_store.find_or_create("IS");
auto &IS = t.type_find_or_create("IS");
r.edge_type(IS);
n2.vlist->update(t)->data.out.add(r.vlist);
n1.vlist->update(t)->data.in.add(r.vlist);
t.commit();
return true;
};
@@ -146,14 +151,13 @@ auto load_queries(Db &db)
// MATCH (n) RETURN n
auto match_all_nodes = [&db](const properties_t &args) {
auto &t = db.tx_engine.begin();
DbAccessor t(db);
auto vertices_accessor = db.graph.vertices.access();
for (auto &it : vertices_accessor) {
auto vertex = it.second.find(t);
if (vertex == nullptr) continue;
cout_properties(vertex->data.props);
}
iter::for_all(t.vertex_access(), [&](auto vertex) {
if (vertex.fill()) {
cout_properties(vertex->data.props);
}
});
// TODO
// db.graph.vertices.filter().all(t, handler);
@@ -166,12 +170,11 @@ auto load_queries(Db &db)
// MATCH (n:LABEL) RETURN n
auto find_by_label = [&db](const properties_t &args) {
auto &t = db.tx_engine.begin();
DbAccessor t(db);
auto &label = db.graph.label_store.find_or_create("LABEL");
auto &label = t.label_find_or_create("LABEL");
auto &index_record_collection =
db.graph.vertices.find_label_index(label);
auto &index_record_collection = t.label_find_index(label);
auto accessor = index_record_collection.access();
cout << "VERTICES" << endl;
for (auto &v : accessor) {

View File

@@ -3,31 +3,23 @@
#include "storage/edge.hpp"
#include "storage/edge_record.hpp"
#include "storage/record_accessor.hpp"
#include "storage/vertex_accessor.hpp"
#include "utils/assert.hpp"
#include "utils/reference_wrapper.hpp"
class Edges;
// TODO: Edge, Db, Edge::Accessor
class Edge::Accessor
: public RecordAccessor<Edge, Edges, Edge::Accessor, EdgeRecord>
class Edge::Accessor : public RecordAccessor<Edge, Edge::Accessor, EdgeRecord>
{
public:
using RecordAccessor::RecordAccessor;
void edge_type(edge_type_ref_t edge_type)
{
this->record->data.edge_type = &edge_type.get();
}
void edge_type(edge_type_ref_t edge_type);
edge_type_ref_t edge_type() const
{
runtime_assert(this->record->data.edge_type != nullptr,
"EdgeType is null");
return edge_type_ref_t(*this->record->data.edge_type);
}
edge_type_ref_t edge_type() const;
auto from() const { return this->vlist->from(); }
Vertex::Accessor from() const;
auto to() const { return this->vlist->to(); }
Vertex::Accessor to() const;
};

View File

@@ -27,7 +27,7 @@ public:
auto to() const { return this->to_v; }
private:
protected:
VertexRecord *from_v;
VertexRecord *to_v;
};

View File

@@ -4,12 +4,15 @@
#include "mvcc/version_list.hpp"
#include "storage/common.hpp"
#include "storage/edge_accessor.hpp"
#include "utils/option.hpp"
class Edges
{
public:
Edge::Accessor find(tx::Transaction &t, const Id &id);
Edge::Accessor insert(tx::Transaction &t, VertexRecord *from,
Option<const Edge::Accessor> find(DbTransaction &t, const Id &id);
// Creates new Edge and returns filled Edge::Accessor.
Edge::Accessor insert(DbTransaction &t, VertexRecord *from,
VertexRecord *to);
private:

View File

@@ -23,7 +23,7 @@ public:
edges.remove(edge); // Currently the return is ignored
}
bool contains(VertexRecord *vr) { return edges.contains(vr); }
bool contains(VertexRecord *vr) const { return edges.contains(vr); }
void clear() { edges.clear(); }

View File

@@ -1,45 +1,60 @@
#pragma once
#include "database/db_transaction.hpp"
#include "mvcc/version_list.hpp"
#include "storage/model/properties/properties.hpp"
#include "storage/model/properties/property.hpp"
#include "transactions/transaction.hpp"
template <class T, class Store, class Derived,
class vlist_t = mvcc::VersionList<T>>
template <class T, class Derived, class vlist_t = mvcc::VersionList<T>>
class RecordAccessor
{
public:
RecordAccessor() = default;
friend DbAccessor;
RecordAccessor(T *record, vlist_t *vlist, Store *store)
: record(record), vlist(vlist), store(store)
public:
RecordAccessor(vlist_t *vlist, DbTransaction &db) : vlist(vlist), db(db)
{
assert(vlist != nullptr);
}
RecordAccessor(T *t, vlist_t *vlist, DbTransaction &db)
: record(t), vlist(vlist), db(db)
{
assert(record != nullptr);
assert(vlist != nullptr);
assert(store != nullptr);
}
RecordAccessor(RecordAccessor const &other) = default;
RecordAccessor(RecordAccessor &&other) = default;
bool empty() const { return record == nullptr; }
// Fills accessor and returns true if there is valid data for current
// transaction false otherwise.
bool fill() const
{
const_cast<RecordAccessor *>(this)->record = vlist->find(db.trans);
return record != nullptr;
}
const Id &id() const
{
assert(!empty());
return vlist->id;
}
Derived update(tx::Transaction &t) const
Derived update() const
{
assert(!empty());
return Derived(vlist->update(t), vlist, store);
return Derived(vlist->update(db.trans), vlist, db);
}
bool remove(tx::Transaction &t) const
bool remove() const
{
assert(!empty());
return vlist->remove(record, t);
return vlist->remove(record, db.trans);
}
const Property &property(const std::string &key) const
@@ -62,8 +77,23 @@ public:
explicit operator bool() const { return record != nullptr; }
// protected:
T *const record{nullptr};
vlist_t *const vlist{nullptr};
Store *const store{nullptr};
T const *operator->() const { return record; }
T *operator->() { return record; }
// Assumes same transaction
friend bool operator==(const RecordAccessor &a, const RecordAccessor &b)
{
return a.vlist == b.vlist;
}
// Assumes same transaction
friend bool operator!=(const RecordAccessor &a, const RecordAccessor &b)
{
return !(a == b);
}
protected:
T *record{nullptr};
vlist_t *const vlist;
DbTransaction &db;
};

View File

@@ -1,8 +1,8 @@
#pragma once
#include "mvcc/record.hpp"
#include "storage/model/vertex_model.hpp"
#include "storage/model/properties/traversers/jsonwriter.hpp"
#include "storage/model/vertex_model.hpp"
class Vertex : public mvcc::Record<Vertex>
{
@@ -10,19 +10,19 @@ public:
class Accessor;
Vertex() = default;
Vertex(const VertexModel& data) : data(data) {}
Vertex(VertexModel&& data) : data(std::move(data)) {}
Vertex(const VertexModel &data) : data(data) {}
Vertex(VertexModel &&data) : data(std::move(data)) {}
Vertex(const Vertex&) = delete;
Vertex(Vertex&&) = delete;
Vertex(const Vertex &) = delete;
Vertex(Vertex &&) = delete;
Vertex& operator=(const Vertex&) = delete;
Vertex& operator=(Vertex&&) = delete;
Vertex &operator=(const Vertex &) = delete;
Vertex &operator=(Vertex &&) = delete;
VertexModel data;
};
inline std::ostream& operator<<(std::ostream& stream, const Vertex& record)
inline std::ostream &operator<<(std::ostream &stream, const Vertex &record)
{
StringBuffer buffer;
JsonWriter<StringBuffer> writer(buffer);
@@ -33,6 +33,5 @@ inline std::ostream& operator<<(std::ostream& stream, const Vertex& record)
return stream << "Vertex"
<< "(cre = " << record.tx.cre()
<< ", exp = " << record.tx.exp()
<< "): " << buffer.str();
<< ", exp = " << record.tx.exp() << "): " << buffer.str();
}

View File

@@ -5,8 +5,7 @@
class Vertices;
class Vertex::Accessor
: public RecordAccessor<Vertex, Vertices, Vertex::Accessor>
class Vertex::Accessor : public RecordAccessor<Vertex, Vertex::Accessor>
{
public:
using RecordAccessor::RecordAccessor;
@@ -21,5 +20,12 @@ public:
bool has_label(const Label &label) const;
const std::set<label_ref_t>& labels() const;
const std::set<label_ref_t> &labels() const;
auto out() const;
auto in() const;
// True if there exists edge other->this
bool in_contains(Vertex::Accessor const &other) const;
};

View File

@@ -1,10 +1,12 @@
#pragma once
#include "data_structures/concurrent/concurrent_map.hpp"
#include "database/db_transaction.hpp"
#include "storage/common.hpp"
#include "storage/indexes/index.hpp"
#include "storage/indexes/index_record_collection.hpp"
#include "storage/vertex_accessor.hpp"
#include "utils/option.hpp"
class Vertices
{
@@ -13,17 +15,16 @@ public:
vertices_t::Accessor access();
const Vertex::Accessor find(tx::Transaction &t, const Id &id);
Option<const Vertex::Accessor> find(DbTransaction &t, const Id &id);
const Vertex::Accessor first(tx::Transaction &t);
Vertex::Accessor insert(tx::Transaction &t);
// Creates new Vertex and returns filled Vertex::Accessor.
Vertex::Accessor insert(DbTransaction &t);
void update_label_index(const Label &label,
VertexIndexRecord &&index_record);
VertexIndexRecordCollection& find_label_index(const Label& label);
VertexIndexRecordCollection &find_label_index(const Label &label);
private:
vertices_t vertices;
Index<label_ref_t, VertexIndexRecordCollection> label_index;

View File

@@ -0,0 +1,28 @@
#pragma once
#include "utils/iterator/wrap.hpp"
#include "utils/option.hpp"
namespace iter
{
template <class T, class I>
class OneTimeAccessor
{
public:
OneTimeAccessor() : it(Option<Wrap<T, I>>()) {}
OneTimeAccessor(I &&it) : it(Wrap<T, I>(std::move(it))) {}
Wrap<T, I> begin() { return it.take(); }
Wrap<T, I> end() { return Wrap<T, I>(); }
private:
Option<Wrap<T, I>> it;
};
template <class I>
auto make_one_time_accessor(I &&iter)
{
return OneTimeAccessor<decltype(iter.next().take()), I>(std::move(iter));
}
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "utils/option.hpp"
namespace iter
{
template <class I, class C>
void for_all(I &&iter, C &&consumer)
{
auto e = iter.next();
while (e.is_present()) {
consumer(e.take());
e = iter.next();
}
}
}

View File

@@ -0,0 +1,48 @@
#pragma once
#include "utils/option.hpp"
namespace iter
{
template <class T, class I, class A>
class Iter
{
public:
Iter() = delete;
Iter(A &&acc) : begin(std::move(acc.begin())), acc(std::forward<A>(acc)) {}
// Iter(const Iter &other) = delete;
// Iter(Iter &&other) :
// begin(std::move(other.begin)),end(std::move(other.end)) {};
auto next()
{
if (begin != acc.end()) {
auto ret = Option<T>(&(*(begin.operator->())));
begin++;
return ret;
} else {
return Option<T>();
}
}
private:
I begin;
A acc;
};
// TODO: Join to make functions into one
template <class A>
auto make_iter(A &&acc)
{
return Iter<decltype(&(*(acc.begin().operator->()))), decltype(acc.begin()),
A>(std::move(acc));
}
template <class A>
auto make_iter_ref(A &acc)
{
return Iter<decltype(&(*(acc.begin().operator->()))), decltype(acc.begin()),
A &>(acc);
}
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include "utils/iterator/accessor.hpp"
#include "utils/iterator/for_all.hpp"
#include "utils/iterator/iter.hpp"
#include "utils/iterator/map.hpp"
#include "utils/iterator/wrap.hpp"

View File

@@ -0,0 +1,39 @@
#pragma once
#include "utils/option.hpp"
namespace iter
{
template <class U, class I, class MapOperator>
class Map
{
public:
Map() = delete;
template <class IT, class OP>
Map(IT &&iter, OP &&op) : iter(std::move(iter)), op(std::move(op))
{
}
auto next()
{
auto item = iter.next();
if (item.is_present()) {
return Option<U>(op(item.take()));
} else {
return Option<U>();
}
}
private:
I iter;
MapOperator op;
};
template <class I, class OP>
auto make_map(I &&iter, OP &&op)
{
return Map<decltype(op(iter.next().take())), I, OP>(std::move(iter),
std::move(op));
}
}

View File

@@ -0,0 +1,60 @@
#pragma once
#include "utils/option.hpp"
namespace iter
{
template <class T, class I>
class Wrap
{
public:
Wrap() : iter(Option<I>()), value(Option<T>()){};
Wrap(I &&iter) : value(iter.next()), iter(Option<I>(std::move(iter))) {}
T &operator*()
{
assert(value.is_present());
return value.get();
}
T *operator->()
{
assert(value.is_present());
return &value.get();
}
operator T &()
{
assert(value.is_present());
return value.get();
}
Wrap &operator++()
{
assert(iter.is_present());
value = iter.get().next();
return (*this);
}
Wrap &operator++(int) { return operator++(); }
friend bool operator==(const Wrap &a, const Wrap &b)
{
return a.value.is_present() == b.value.is_present();
}
friend bool operator!=(const Wrap &a, const Wrap &b) { return !(a == b); }
private:
Option<I> iter;
Option<T> value;
};
template <class I>
auto make_wrap(I &&iter)
{
return Wrap<decltype(iter.next().take()), I>(std::move(iter));
}
}

95
include/utils/option.hpp Normal file
View File

@@ -0,0 +1,95 @@
#pragma once
#include <ext/aligned_buffer.h>
#include <utility>
template <class T>
class Option
{
public:
Option() {}
Option(T const &item)
{
new (data._M_addr()) T(item);
initialized = true;
}
Option(T &&item)
{
new (data._M_addr()) T(std::move(item));
initialized = true;
}
Option(Option &other) = default;
Option(Option &&other) noexcept
{
if (other.initialized) {
data = std::move(other.data);
other.initialized = false;
initialized = true;
}
}
~Option()
{
if (initialized) get().~T();
}
Option<T> &operator=(Option<T> &&other)
{
if (initialized) {
get().~T();
initialized = false;
}
if (other.initialized) {
data = std::move(other.data);
other.initialized = false;
initialized = true;
}
return *this;
}
bool is_present() const { return initialized; }
T &get() noexcept
{
assert(initialized);
return *data._M_ptr();
}
const T &get() const noexcept { assert(initialized); }
T take()
{
assert(initialized);
initialized = false;
return std::move(*data._M_ptr());
}
explicit operator bool() const { return initialized; }
private:
__gnu_cxx::__aligned_buffer<T> data;
bool initialized = false;
};
template <class T>
auto make_option()
{
return Option<T>();
}
template <class T>
auto make_option(T &&data)
{
return Option<T>(std::move(data));
}
template <class T>
auto make_option_const(const T &&data)
{
return Option<const T>(std::move(data));
}

View File

@@ -1,7 +1,7 @@
#pragma once
#include <utility>
#include <ext/aligned_buffer.h>
#include <utility>
template <class T>
class Placeholder
@@ -9,40 +9,41 @@ class Placeholder
public:
Placeholder() = default;
Placeholder(Placeholder&) = delete;
Placeholder(Placeholder&&) = delete;
Placeholder(Placeholder &) = delete;
Placeholder(Placeholder &&) = delete;
~Placeholder()
{
if(initialized)
get().~T();
if (initialized) get().~T();
};
T& get() noexcept
bool is_initialized() { return initialized; }
T &get() noexcept
{
assert(initialized);
return *data._M_ptr();
}
const T& get() const noexcept
const T &get() const noexcept
{
assert(initialized);
return *data._M_ptr();
}
void set(const T& item)
void set(const T &item)
{
new (data._M_addr()) T(item);
initialized = true;
}
void set(T&& item)
void set(T &&item)
{
new (data._M_addr()) T(std::move(item));
initialized = true;
}
private:
__gnu_cxx::__aligned_buffer<T> data;
__gnu_cxx::__aligned_buffer<T> data;
bool initialized = false;
};