diff --git a/CMakeLists.txt b/CMakeLists.txt index 588fb6817..697a056cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -418,6 +418,7 @@ set(memgraph_src_files ${src_dir}/utils/string/transform.cpp ${src_dir}/utils/string/join.cpp ${src_dir}/utils/string/file.cpp + ${src_dir}/utils/iterator/iterator_base.cpp ${src_dir}/query_engine/util.cpp ${src_dir}/communication/bolt/v1/bolt.cpp ${src_dir}/communication/bolt/v1/states.cpp diff --git a/include/barrier/barrier.hpp b/include/barrier/barrier.hpp index e201b9d61..7c03e49c9 100644 --- a/include/barrier/barrier.hpp +++ b/include/barrier/barrier.hpp @@ -25,6 +25,7 @@ class EdgeIterator; // TYPED ITERATORS class VertexAccessIterator; +class EdgeAccessIterator; class OutEdgesIterator; class InEdgesIterator; @@ -63,8 +64,8 @@ using label_ref_t = ReferenceWrapper<const Label>; // Original class should have Sized barrier class if it can't be Unsized. // Sized barrier classes should: // --Have same name as original class. -// --Inherit Sized class from common.hpp as private. Blueprint: -// class class_name: Sized<size_of_t,aligment_of_t> +// --Inherit Sized class from common.hpp as public. Blueprint: +// class class_name: public Sized<size_of_t,aligment_of_t> // --Sized template arguments must be hardcoded numbers equal to sizeof(T) and // alignof(T) where T is original class. // --It should have undefined public constructor which is specialized in .cpp @@ -82,7 +83,7 @@ using label_ref_t = ReferenceWrapper<const Label>; // --It should specify public methods which can be called on the original class. // // Blueprint: -// class class_name : private Sized<,> +// class class_name : public Sized<,> // { // public: // template <class T> @@ -247,6 +248,8 @@ public: VertexAccessor vertex_insert(); + EdgeAccessIterator edge_access(); + Option<const EdgeAccessor> edge_find(const Id &id); EdgeAccessor edge_insert(VertexAccessor const &from, @@ -278,7 +281,8 @@ public: void abort(); }; -class VertexIterator : private Sized<8, 8> +class VertexIterator : public Sized<8, 8>, + public IteratorBase<const VertexAccessor> { public: template <class T> @@ -290,11 +294,14 @@ public: VertexIterator &operator=(const VertexIterator &other) = delete; VertexIterator &operator=(VertexIterator &&other) = delete; - Option<const VertexAccessor> next(); + Option<const VertexAccessor> next() final; + + Count count() final; }; // TODO: Find reasons of such great size ant try to decrease it. -class VertexAccessIterator : private Sized<552, 8> +class VertexAccessIterator : public Sized<560, 8>, + public IteratorBase<const VertexAccessor> { public: template <class T> @@ -306,10 +313,32 @@ public: VertexAccessIterator &operator=(const VertexAccessIterator &other) = delete; VertexAccessIterator &operator=(VertexAccessIterator &&other) = delete; - Option<const VertexAccessor> next(); + Option<const VertexAccessor> next() final; + + Count count() final; }; -class OutEdgesIterator : private Sized<40, 8> +// TODO: Find reasons of such great size ant try to decrease it. +class EdgeAccessIterator : public Sized<560, 8>, + public IteratorBase<const EdgeAccessor> +{ +public: + template <class T> + EdgeAccessIterator(T &&d); + + EdgeAccessIterator(const EdgeAccessIterator &other) = delete; + EdgeAccessIterator(EdgeAccessIterator &&other); + ~EdgeAccessIterator(); + EdgeAccessIterator &operator=(const EdgeAccessIterator &other) = delete; + EdgeAccessIterator &operator=(EdgeAccessIterator &&other) = delete; + + Option<const EdgeAccessor> next() final; + + Count count() final; +}; + +class OutEdgesIterator : public Sized<48, 8>, + public IteratorBase<const EdgeAccessor> { public: template <class T> @@ -321,10 +350,13 @@ public: OutEdgesIterator &operator=(const OutEdgesIterator &other) = delete; OutEdgesIterator &operator=(OutEdgesIterator &&other) = delete; - Option<const EdgeAccessor> next(); + Option<const EdgeAccessor> next() final; + + Count count() final; }; -class InEdgesIterator : private Sized<56, 8> +class InEdgesIterator : public Sized<64, 8>, + public IteratorBase<const EdgeAccessor> { public: template <class T> @@ -336,10 +368,12 @@ public: InEdgesIterator &operator=(const InEdgesIterator &other) = delete; InEdgesIterator &operator=(InEdgesIterator &&other) = delete; - Option<const EdgeAccessor> next(); + Option<const EdgeAccessor> next() final; + + Count count() final; }; -class EdgeIterator : private Sized<8, 8> +class EdgeIterator : public Sized<8, 8>, public IteratorBase<const EdgeAccessor> { public: template <class T> @@ -351,7 +385,9 @@ public: EdgeIterator &operator=(const EdgeIterator &other) = delete; EdgeIterator &operator=(EdgeIterator &&other) = delete; - Option<const EdgeAccessor> next(); + Option<const EdgeAccessor> next() final; + + Count count() final; }; class VertexPropertyKey : private Sized<8, 8> @@ -442,10 +478,10 @@ public: void write_success_empty(); void write_ignored(); void write_fields(const std::vector<std::string> &fields); - void write_field(const std::string& field); + void write_field(const std::string &field); void write_list_header(size_t size); void write_record(); - void write_meta(const std::string& type); + void write_meta(const std::string &type); void send(); void chunk(); }; diff --git a/include/barrier/common.hpp b/include/barrier/common.hpp index 75b2bdbe6..1873988f7 100644 --- a/include/barrier/common.hpp +++ b/include/barrier/common.hpp @@ -121,6 +121,18 @@ protected: "Border class aligment mismatch"); } +public: + typename std::aligned_storage<size_B, alignment_B>::type &_data_ref() + { + return data; + } + + typename std::aligned_storage<size_B, alignment_B>::type const & + _data_ref_const() const + { + return data; + } + private: // Here is the aligned storage which imitates size and aligment of object of // original class from memgraph. diff --git a/include/barrier/trans.hpp b/include/barrier/trans.hpp index af7c8ad76..1e474903f 100644 --- a/include/barrier/trans.hpp +++ b/include/barrier/trans.hpp @@ -5,13 +5,15 @@ // This is the place for imports from memgraph .hpp #include "communication/bolt/v1/serialization/bolt_serializer.hpp" #include "communication/bolt/v1/serialization/record_stream.hpp" -#include "io/network/socket.hpp" #include "database/db.hpp" #include "database/db_accessor.hpp" +#include "io/network/socket.hpp" #include "storage/edge_type/edge_type.hpp" #include "storage/edge_x_vertex.hpp" #include "storage/label/label.hpp" +// This is the place for imports from memgraph .cpp + // **************************** HELPER DEFINES *******************************// // Creates 8 functions for transformation of refereces between types x and y. // Where x is a border type. @@ -26,6 +28,21 @@ y *trans(x *l) { return ptr_as<y>(l); } \ y const *trans(x const *l) { return ptr_as<y const>(l); } +// Creates 4 functions for transformation of refereces between types x and y. +// Where x is a sized border type. +// DANGEROUS +#define TRANSFORM_REF_SIZED(x, y) \ + y &trans(x &l) { return ref_as<y>(l._data_ref()); } \ + y const &trans(x const &l) \ + { \ + return ref_as<y const>(l._data_ref_const()); \ + } \ + y *trans(x *l) { return ptr_as<y>(&(l->_data_ref())); } \ + y const *trans(x const *l) \ + { \ + return ptr_as<y const>(&(l->_data_ref_const())); \ + } + // Creates 8 functions for transformation of refereces between types x and y. // Where both x and y are templates over T. Where x is a border type. // DANGEROUS @@ -126,6 +143,9 @@ using vertex_access_iterator_t = decltype(((::DbAccessor *)(std::nullptr_t()))->vertex_access()); +using edge_access_iterator_t = + decltype(((::DbAccessor *)(std::nullptr_t()))->edge_access()); + using out_edge_iterator_t = decltype(((::VertexAccessor *)(std::nullptr_t()))->out()); @@ -155,13 +175,16 @@ TRANSFORM_REF(VertexPropertyKey, ::VertexPropertyFamily::PropertyType::PropertyFamilyKey); TRANSFORM_REF(EdgePropertyKey, ::EdgePropertyFamily::PropertyType::PropertyFamilyKey); -TRANSFORM_REF(VertexIterator, - std::unique_ptr<IteratorBase<const ::VertexAccessor>>); -TRANSFORM_REF(EdgeIterator, - std::unique_ptr<IteratorBase<const ::EdgeAccessor>>); -TRANSFORM_REF(VertexAccessIterator, vertex_access_iterator_t); -TRANSFORM_REF(OutEdgesIterator, out_edge_iterator_t); -TRANSFORM_REF(InEdgesIterator, in_edge_iterator_t); + +// ITERATORS +TRANSFORM_REF_SIZED(VertexIterator, + std::unique_ptr<IteratorBase<const ::VertexAccessor>>); +TRANSFORM_REF_SIZED(EdgeIterator, + std::unique_ptr<IteratorBase<const ::EdgeAccessor>>); +TRANSFORM_REF_SIZED(VertexAccessIterator, vertex_access_iterator_t); +TRANSFORM_REF_SIZED(EdgeAccessIterator, edge_access_iterator_t); +TRANSFORM_REF_SIZED(OutEdgesIterator, out_edge_iterator_t); +TRANSFORM_REF_SIZED(InEdgesIterator, in_edge_iterator_t); template <class T> TRANSFORM_REF_TEMPLATED(VertexIndex<T>, VertexIndexBase<T>); @@ -189,19 +212,22 @@ TRANSFORM_VALUE(EdgePropertyKey, TRANSFORM_VALUE(VertexPropertyKey, ::VertexPropertyFamily::PropertyType::PropertyFamilyKey); TRANSFORM_VALUE_ONE(VertexAccessIterator, vertex_access_iterator_t); -MOVE_CONSTRUCTOR_FORCED(VertexAccessIterator, vertex_access_iterator_t); +// MOVE_CONSTRUCTOR_FORCED(VertexAccessIterator, vertex_access_iterator_t); +TRANSFORM_VALUE_ONE(EdgeAccessIterator, edge_access_iterator_t); +// MOVE_CONSTRUCTOR_FORCED(EdgeAccessIterator, edge_access_iterator_t); TRANSFORM_VALUE_ONE(OutEdgesIterator, out_edge_iterator_t); -MOVE_CONSTRUCTOR_FORCED(OutEdgesIterator, out_edge_iterator_t); +// MOVE_CONSTRUCTOR_FORCED(OutEdgesIterator, out_edge_iterator_t); TRANSFORM_VALUE_ONE(InEdgesIterator, in_edge_iterator_t); -MOVE_CONSTRUCTOR_FORCED(InEdgesIterator, in_edge_iterator_t); +// MOVE_CONSTRUCTOR_FORCED(InEdgesIterator, in_edge_iterator_t); TRANSFORM_VALUE_ONE(VertexIterator, std::unique_ptr<IteratorBase<const ::VertexAccessor>>); -MOVE_CONSTRUCTOR_FORCED(VertexIterator, - std::unique_ptr<IteratorBase<const ::VertexAccessor>>); +// MOVE_CONSTRUCTOR_FORCED(VertexIterator, +// std::unique_ptr<IteratorBase<const +// ::VertexAccessor>>); TRANSFORM_VALUE_ONE(EdgeIterator, std::unique_ptr<IteratorBase<const ::EdgeAccessor>>); -MOVE_CONSTRUCTOR_FORCED(EdgeIterator, - std::unique_ptr<IteratorBase<const ::EdgeAccessor>>); +// MOVE_CONSTRUCTOR_FORCED(EdgeIterator, +// std::unique_ptr<IteratorBase<const ::EdgeAccessor>>); template <class T> TRANSFORM_VALUE_ONE_RAW( diff --git a/include/data_structures/concurrent/common.hpp b/include/data_structures/concurrent/common.hpp index 4ec9e7c16..35b1e3408 100644 --- a/include/data_structures/concurrent/common.hpp +++ b/include/data_structures/concurrent/common.hpp @@ -62,6 +62,8 @@ public: ~AccessorBase() {} + size_t size() { return accessor.size(); }; + list_it begin() { return accessor.begin(); } list_it_con begin() const { return accessor.cbegin(); } diff --git a/include/data_structures/concurrent/concurrent_list.hpp b/include/data_structures/concurrent/concurrent_list.hpp index 87d414f49..8f16a504b 100644 --- a/include/data_structures/concurrent/concurrent_list.hpp +++ b/include/data_structures/concurrent/concurrent_list.hpp @@ -281,6 +281,8 @@ public: ConstIterator cend() { return ConstIterator(); } + std::size_t size() { return count.load(std::memory_order_consume); } + private: std::atomic<std::size_t> count{0}; std::atomic<Node *> head{nullptr}; diff --git a/include/database/db_accessor.hpp b/include/database/db_accessor.hpp index 8614a341a..8df93dfb8 100644 --- a/include/database/db_accessor.hpp +++ b/include/database/db_accessor.hpp @@ -69,6 +69,14 @@ public: VertexAccessor vertex_insert(); // ******************* EDGE METHODS + auto edge_access() + { + return iter::make_map( + iter::make_iter(this->db_transaction.db.graph.edges.access()), + [&](auto e) -> auto { + return EdgeAccessor(&(e->second), db_transaction); + }); + } Option<const EdgeAccessor> edge_find(const Id &id); diff --git a/include/query_engine/hardcode/queries.hpp b/include/query_engine/hardcode/queries.hpp index f50d7c0c4..191cca8de 100644 --- a/include/query_engine/hardcode/queries.hpp +++ b/include/query_engine/hardcode/queries.hpp @@ -4,6 +4,7 @@ #include <map> #include "barrier/barrier.hpp" +#include "utils/iterator/iterator_base.cpp" using namespace std; @@ -20,8 +21,7 @@ auto load_queries(Db &db) auto vertex_accessor = t.vertex_insert(); vertex_accessor.set(prop_key, args[0]); - t.commit(); - return true; + return t.commit(); }; queries[11597417457737499503u] = create_node; @@ -34,8 +34,7 @@ auto load_queries(Db &db) vertex_accessor.set(prop_key, args[0]); vertex_accessor.add_label(label); // cout_properties(vertex_accessor.properties()); - t.commit(); - return true; + return t.commit(); }; auto create_account = [&db](const properties_t &args) { @@ -53,8 +52,7 @@ auto load_queries(Db &db) vertex_accessor.set(prop_created, args[3]); vertex_accessor.add_label(label); // cout_properties(vertex_accessor.properties()); - t.commit(); - return true; + return t.commit(); }; auto find_node_by_internal_id = [&db](const properties_t &args) { @@ -71,8 +69,7 @@ auto load_queries(Db &db) for (auto label_ref : vertex_accessor.labels()) { // cout << label_ref.get() << endl; } - t.commit(); - return true; + return t.commit(); }; auto create_edge = [&db](const properties_t &args) { @@ -89,13 +86,13 @@ auto load_queries(Db &db) edge_accessor.edge_type(edge_type); - t.commit(); + bool ret = t.commit(); // cout << edge_accessor.edge_type() << endl; // cout_properties(edge_accessor.properties()); - return true; + return ret; }; auto find_edge_by_internal_id = [&db](const properties_t &args) { @@ -119,9 +116,7 @@ auto load_queries(Db &db) cout << "TO:" << endl; // cout_properties(to->data.props); - t.commit(); - - return true; + return t.commit(); }; auto update_node = [&db](const properties_t &args) { @@ -135,9 +130,7 @@ auto load_queries(Db &db) v.set(prop_name, args[1]); // cout_properties(v.properties()); - t.commit(); - - return true; + return t.commit(); }; // MATCH (n1), (n2) WHERE ID(n1)=0 AND ID(n2)=1 CREATE (n1)<-[r:IS {age: 25, @@ -158,21 +151,17 @@ auto load_queries(Db &db) auto &IS = t.type_find_or_create("IS"); r.edge_type(IS); - t.commit(); - return true; + return t.commit(); }; // MATCH (n) RETURN n auto match_all_nodes = [&db](const properties_t &args) { DbAccessor t(db); - iter::for_all(t.vertex_access(), [&](auto vertex) { - if (vertex.fill()) { - cout << vertex.id() << endl; - } - }); + t.vertex_access().fill().for_all( + [&](auto vertex) { cout << vertex.id() << endl; }); - return t.commit(), true; + return t.commit(); }; // MATCH (n:LABEL) RETURN n @@ -183,12 +172,123 @@ auto load_queries(Db &db) auto prop_key = t.vertex_property_key("name", Flags::String); cout << "VERTICES" << endl; - iter::for_all(label.index().for_range(t), - [&](auto a) { cout << a.at(prop_key) << endl; }); + label.index().for_range(t).for_all( + [&](auto a) { cout << a.at(prop_key) << endl; }); - return t.commit(), true; + return t.commit(); }; + // MATCH (n) DELETE n + auto match_all_delete = [&db](const properties_t &args) { + DbAccessor t(db); + + t.vertex_access().fill().for_all([&](auto a) { a.remove(); }); + + return t.commit(); + }; + + // MATCH (n:LABEL) DELETE n + auto match_label_delete = [&db](const properties_t &args) { + DbAccessor t(db); + + auto &label = t.label_find_or_create("LABEL"); + + label.index().for_range(t).for_all([&](auto a) { a.remove(); }); + + return t.commit(); + }; + + // MATCH (n) WHERE ID(n) = id DELETE n + auto match_id_delete = [&db](const properties_t &args) { + DbAccessor t(db); + + auto ov = t.vertex_find(args[0]->as<Int64>().value); + if (!option_fill(ov)) return t.commit(), false; + + auto v = ov.take(); + v.remove(); + + return t.commit(); + }; + + // MATCH ()-[r]-() WHERE ID(r) = id DELETE r + auto match_edge_id_delete = [&db](const properties_t &args) { + DbAccessor t(db); + + auto ov = t.edge_find(args[0]->as<Int64>().value); + if (!option_fill(ov)) return t.commit(), false; + + auto v = ov.take(); + v.remove(); + + return t.commit(); + }; + + // MATCH ()-[r]-() DELETE r + auto match_edge_all_delete = [&db](const properties_t &args) { + DbAccessor t(db); + + t.edge_access().fill().for_all([&](auto a) { a.remove(); }); + + return t.commit(); + }; + + // MATCH ()-[r:TYPE]-() DELETE r + auto match_edge_type_delete = [&db](const properties_t &args) { + DbAccessor t(db); + + auto &type = t.type_find_or_create("TYPE"); + + type.index().for_range(t).for_all([&](auto a) { a.remove(); }); + + return t.commit(); + }; + + // MATCH (n)-[:TYPE]->(m) WHERE ID(n) = id RETURN m + auto match_id_type_return = [&db](const properties_t &args) { + DbAccessor t(db); + + auto &type = t.type_find_or_create("TYPE"); + + auto ov = t.vertex_find(args[0]->as<Int64>().value); + if (!option_fill(ov)) return t.commit(), false; + auto v = ov.take(); + + auto results = v.out().fill().type(type).to(); + + // Example of Print resoult. + // results.for_all([&](auto va) { + // va is VertexAccessor + // PRINT + // }); + + return t.commit(); + }; + + // MATCH (n)-[:TYPE]->(m) WHERE n.name = "kruno" RETURN m + auto match_name_type_return = [&db](const properties_t &args) { + DbAccessor t(db); + + auto &type = t.type_find_or_create("TYPE"); + + auto it_type = type.index().for_range(t); + auto it_vertex = t.vertex_access(); + + // if(it_type.count().max>it_vertex.count().max){ + // + // } + + return t.commit(); + }; + + // Blueprint: + // auto = [&db](const properties_t &args) { + // DbAccessor t(db); + // + // + // return t.commit(); + // }; + queries[15284086425088081497u] = match_all_nodes; queries[4857652843629217005u] = match_by_label; queries[15648836733456301916u] = create_edge_v2; @@ -199,6 +299,13 @@ auto load_queries(Db &db) queries[11198568396549106428u] = find_node_by_internal_id; queries[8320600413058284114u] = find_edge_by_internal_id; queries[6813335159006269041u] = update_node; + queries[10506105811763742758u] = match_all_delete; + queries[13742779491897528506u] = match_label_delete; + queries[11349462498691305864u] = match_id_delete; + queries[6963549500479100885u] = match_edge_id_delete; + queries[14897166600223619735u] = match_edge_all_delete; + queries[16888549834923624215u] = match_edge_type_delete; + queries[11675960684124428508u] = match_id_type_return; return queries; } diff --git a/include/storage/model/edge_list.hpp b/include/storage/model/edge_list.hpp index ac53ab4db..cf139a4e5 100644 --- a/include/storage/model/edge_list.hpp +++ b/include/storage/model/edge_list.hpp @@ -27,6 +27,8 @@ public: void clear() { edges.clear(); } + std::size_t size() { return edges.size(); } + private: std::vector<EdgeRecord *> edges; }; diff --git a/include/storage/model/edge_map.hpp b/include/storage/model/edge_map.hpp index 5460e3e18..d1d9b0035 100644 --- a/include/storage/model/edge_map.hpp +++ b/include/storage/model/edge_map.hpp @@ -28,6 +28,8 @@ public: void clear() { edges.clear(); } + std::size_t size() { return edges.size(); } + private: RhHashMultiMap<VertexRecord *, EdgeRecord> edges; }; diff --git a/include/utils/iterator/count.hpp b/include/utils/iterator/count.hpp new file mode 100644 index 000000000..20016970f --- /dev/null +++ b/include/utils/iterator/count.hpp @@ -0,0 +1,21 @@ +#pragma once + +// Represents number of to be returned elements from iterator. Where acutal +// number is probably somwhere in [min,max]. +class Count +{ + +public: + Count(size_t exact) : min(exact), max(exact) {} + + Count(size_t min, size_t max) : min(min), max(max) {} + + Count &min_zero() + { + min = 0; + return *this; + } + + size_t min; + size_t max; +}; diff --git a/include/utils/iterator/filter.hpp b/include/utils/iterator/filter.hpp new file mode 100644 index 000000000..f0c430309 --- /dev/null +++ b/include/utils/iterator/filter.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "utils/iterator/iterator_base.hpp" +#include "utils/option.hpp" + +namespace iter +{ + +// Class which filters values T returned by I iterator if OP returns true for +// them. +// T - type of return value +// I - iterator type +// OP - type of filter function. OP: T& -> bool +template <class T, class I, class OP> +class Filter : public IteratorBase<T> +{ + +public: + Filter() = delete; + + // Filter operation is designed to be used in chained calls which operate on + // a + // iterator. Filter will in that usecase receive other iterator by value and + // std::move is a optimization for it. + Filter(I &&iter, OP &&op) : iter(std::move(iter)), op(std::move(op)) {} + + // Return values for which filter return true. + Option<T> next() final + { + auto item = Option<T>(); + do { + item = iter.next(); + if (!item.is_present()) { + return Option<T>(); + } + } while (!op(item.get())); + + return std::move(item); + } + + Count count() final { return iter.count().min_zero(); } + +private: + I iter; + OP op; +}; + +template <class I, class OP> +auto make_filter(I &&iter, OP &&op) +{ + // Compiler cant deduce type T. decltype is here to help with it. + return Filter<decltype(iter.next().take()), I, OP>(std::move(iter), + std::move(op)); +} +} diff --git a/include/utils/iterator/for_all.hpp b/include/utils/iterator/for_all.hpp index 043f2c882..d68344aff 100644 --- a/include/utils/iterator/for_all.hpp +++ b/include/utils/iterator/for_all.hpp @@ -25,4 +25,17 @@ void for_all(std::unique_ptr<I> &&iter, C &&consumer) e = iter->next(); } } + +template <class I, class C> +void find(I iter, C &&consumer) +{ + auto e = iter.next(); + while (e.is_present()) { + + if (consumer(e.take())) { + return; + } + e = iter.next(); + } +} } diff --git a/include/utils/iterator/iterator.hpp b/include/utils/iterator/iterator.hpp index 93e48a67d..fb9d41655 100644 --- a/include/utils/iterator/iterator.hpp +++ b/include/utils/iterator/iterator.hpp @@ -1,6 +1,8 @@ #pragma once #include "utils/iterator/accessor.hpp" +#include "utils/iterator/count.hpp" +#include "utils/iterator/filter.hpp" #include "utils/iterator/for_all.hpp" #include "utils/iterator/iterator_accessor.hpp" #include "utils/iterator/iterator_base.hpp" diff --git a/include/utils/iterator/iterator_accessor.hpp b/include/utils/iterator/iterator_accessor.hpp index 54ef77eda..2acd960d3 100644 --- a/include/utils/iterator/iterator_accessor.hpp +++ b/include/utils/iterator/iterator_accessor.hpp @@ -17,12 +17,13 @@ public: IteratorAccessor() = delete; IteratorAccessor(A &&acc) - : begin(std::move(acc.begin())), acc(std::forward<A>(acc)) + : begin(std::move(acc.begin())), acc(std::forward<A>(acc)), returned(0) { } IteratorAccessor(IteratorAccessor &&other) - : begin(std::move(other.begin)), acc(std::forward<A>(other.acc)) + : begin(std::move(other.begin)), acc(std::forward<A>(other.acc)), + returned(other.returned) { } @@ -37,15 +38,27 @@ public: if (begin != acc.end()) { auto ret = Option<T>(&(*(begin.operator->()))); begin++; + returned++; return ret; } else { return Option<T>(); } } + Count count() final + { + auto size = acc.size(); + if (size > returned) { + return Count(0); + } else { + return Count(size - returned); + } + } + private: I begin; A acc; + size_t returned; }; // TODO: Join to make functions into one diff --git a/include/utils/iterator/iterator_base.hpp b/include/utils/iterator/iterator_base.hpp index 68403c548..d6feb5813 100644 --- a/include/utils/iterator/iterator_base.hpp +++ b/include/utils/iterator/iterator_base.hpp @@ -1,7 +1,10 @@ #pragma once +#include "utils/iterator/count.hpp" #include "utils/option.hpp" +class EdgeType; + // Base iterator for next() kind iterator. // T - type of return value template <class T> @@ -11,4 +14,26 @@ public: virtual ~IteratorBase(){}; virtual Option<T> next() = 0; + + virtual Count count() { return Count(0, ~((size_t)0)); } + + template <class OP> + auto map(OP &&op); + + template <class OP> + auto filter(OP &&op); + + // Maps with call to method to() and filters with call to fill. + auto to(); + + // Filters with call to method fill() + auto fill(); + + // Filters with type + template <class TYPE> + auto type(TYPE const &type); + + // For all items calls OP. + template <class OP> + void for_all(OP &&op); }; diff --git a/include/utils/iterator/lambda_iterator.hpp b/include/utils/iterator/lambda_iterator.hpp index 67dbccfb6..cd130af31 100644 --- a/include/utils/iterator/lambda_iterator.hpp +++ b/include/utils/iterator/lambda_iterator.hpp @@ -11,26 +11,36 @@ template <class T, class F> class LambdaIterator : public IteratorBase<T> { public: - LambdaIterator(F &&f) : func(std::move(f)) {} + LambdaIterator(F &&f, size_t count) : func(std::move(f)), _count(count) {} - LambdaIterator(LambdaIterator &&other) : func(std::move(other.func)) {} + LambdaIterator(LambdaIterator &&other) + : func(std::move(other.func)), _count(other._count) + { + } ~LambdaIterator() final {} - Option<T> next() final { return func(); } + Option<T> next() final + { + _count = _count > 0 ? _count - 1 : 0; + return func(); + } + + Count count() final { return Count(_count); } private: F func; + size_t _count; }; // Wraps lambda which returns options as an iterator. template <class F> -auto make_iterator(F &&f) +auto make_iterator(F &&f, size_t count) { // Because function isn't receving or in any way using type T from // FunctionIterator compiler can't deduce it thats way there is decltype in // construction of FunctionIterator. Resoulting type of iter.next().take() // is T. - return LambdaIterator<decltype(f().take()), F>(std::move(f)); + return LambdaIterator<decltype(f().take()), F>(std::move(f), count); } } diff --git a/include/utils/iterator/map.hpp b/include/utils/iterator/map.hpp index ddbc45700..53cf52f46 100644 --- a/include/utils/iterator/map.hpp +++ b/include/utils/iterator/map.hpp @@ -37,6 +37,8 @@ public: } } + Count count() final { return iter.count(); } + private: I iter; OP op; diff --git a/include/utils/iterator/query.hpp b/include/utils/iterator/query.hpp new file mode 100644 index 000000000..b3fa64365 --- /dev/null +++ b/include/utils/iterator/query.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "storage/vertex_accessor.hpp" +#include "utils/iterator/iterator.hpp" +#include "utils/option.hpp" + +namespace query_help +{ + +template <class A> +bool fill(A &a) +{ + return a.fill(); +} +}; + +// Base iterator for next() kind iterator. +// Vertex::Accessor - type of return value +template <> +class IteratorBase<Vertex::Accessor> +{ +public: + virtual Option<Vertex::Accessor> next() = 0; + + auto fill() + { + return iter::make_filter(std::move(*this), query_help::fill); + } +}; diff --git a/poc/profile.hpp b/poc/profile.hpp index 9e4548f21..0dea2abca 100644 --- a/poc/profile.hpp +++ b/poc/profile.hpp @@ -115,19 +115,6 @@ void for_all_fill(I iter, C &&consumer) } } -template <class I, class C> -void find(I iter, C &&consumer) -{ - auto e = iter.next(); - while (e.is_present()) { - - if (consumer(e.take())) { - return; - } - e = iter.next(); - } -} - template <class I, class C> void find_fill(I iter, C &&consumer) { diff --git a/src/barrier/barrier.cpp b/src/barrier/barrier.cpp index 7031230bd..717e1fedf 100644 --- a/src/barrier/barrier.cpp +++ b/src/barrier/barrier.cpp @@ -148,6 +148,8 @@ Option<const VertexAccessor> DbAccessor::vertex_find(const Id &id) VertexAccessor DbAccessor::vertex_insert() { return CALL(vertex_insert()); } +EdgeAccessIterator DbAccessor::edge_access() { return CALL(edge_access()); } + Option<const EdgeAccessor> DbAccessor::edge_find(const Id &id) { return HALF_CALL(edge_find(id)).map<const EdgeAccessor>(); @@ -435,6 +437,8 @@ Option<const VertexAccessor> VertexIterator::next() return HALF_CALL(get()->next()).map<const VertexAccessor>(); } +Count VertexIterator::count() { return HALF_CALL(get()->count()); } + // ************************* EdgeIterator DESTRUCTOR(EdgeIterator, unique_ptr); @@ -443,6 +447,8 @@ Option<const EdgeAccessor> EdgeIterator::next() return HALF_CALL(get()->next()).map<const EdgeAccessor>(); } +Count EdgeIterator::count() { return HALF_CALL(get()->count()); } + // ************************* OutEdgesIterator DESTRUCTOR(OutEdgesIterator, out_edge_iterator_t); @@ -451,6 +457,8 @@ Option<const EdgeAccessor> OutEdgesIterator::next() return HALF_CALL(next()).map<const EdgeAccessor>(); } +Count OutEdgesIterator::count() { return HALF_CALL(count()); } + // ************************* InEdgesIterator DESTRUCTOR(InEdgesIterator, in_edge_iterator_t); @@ -459,6 +467,8 @@ Option<const EdgeAccessor> InEdgesIterator::next() return HALF_CALL(next()).map<const EdgeAccessor>(); } +Count InEdgesIterator::count() { return HALF_CALL(count()); } + // ************************* VertexAccessIterator DESTRUCTOR(VertexAccessIterator, vertex_access_iterator_t); @@ -467,6 +477,18 @@ Option<const VertexAccessor> VertexAccessIterator::next() return HALF_CALL(next()).map<const VertexAccessor>(); } +Count VertexAccessIterator::count() { return HALF_CALL(count()); } + +// ************************* EdgeAccessIterator +DESTRUCTOR(EdgeAccessIterator, edge_access_iterator_t); + +Option<const EdgeAccessor> EdgeAccessIterator::next() +{ + return HALF_CALL(next()).map<const EdgeAccessor>(); +} + +Count EdgeAccessIterator::count() { return HALF_CALL(count()); } + // ************************* VertexPropertyKey DESTRUCTOR(VertexPropertyKey, PropertyFamilyKey); @@ -596,7 +618,7 @@ void RecordStream<Stream>::write_fields(const std::vector<std::string> &fields) } template <class Stream> -void RecordStream<Stream>::write_field(const std::string& field) +void RecordStream<Stream>::write_field(const std::string &field) { HALF_CALL(write_field(field)); } @@ -614,7 +636,7 @@ void RecordStream<Stream>::write_record() } template <class Stream> -void RecordStream<Stream>::write_meta(const std::string& type) +void RecordStream<Stream>::write_meta(const std::string &type) { HALF_CALL(write_meta(type)); } @@ -632,7 +654,6 @@ void RecordStream<Stream>::chunk() } template class RecordStream<io::Socket>; - } // **************************** ERROR EXAMPLES ****************************** // diff --git a/src/storage/indexes/impl/nonunique_unordered_index.cpp b/src/storage/indexes/impl/nonunique_unordered_index.cpp index d96f148ad..006ae702a 100644 --- a/src/storage/indexes/impl/nonunique_unordered_index.cpp +++ b/src/storage/indexes/impl/nonunique_unordered_index.cpp @@ -46,22 +46,26 @@ auto NonUniqueUnorderedIndex<T, K>::for_range_exact(DbAccessor &t_v, Border<K> from_v, Border<K> to_v) { - return iter::make_iterator([ - it = list.cbegin(), end = list.cend(), from = from_v, to = to_v, t = t_v - ]() mutable->auto { - while (it != end) { - const IndexRecord<T, K> &r = *it; - if (from < r.key && to > r.key && - r.is_valid(t.db_transaction.trans)) { - const typename T::accessor_t acc = r.access(t.db_transaction); + return iter::make_iterator( + [ + it = list.cbegin(), end = list.cend(), from = from_v, to = to_v, + t = t_v + ]() mutable->auto { + while (it != end) { + const IndexRecord<T, K> &r = *it; + if (from < r.key && to > r.key && + r.is_valid(t.db_transaction.trans)) { + const typename T::accessor_t acc = + r.access(t.db_transaction); + it++; + return make_option(std::move(acc)); + } it++; - return make_option(std::move(acc)); } - it++; - } - return Option<const typename T::accessor_t>(); - }); + return Option<const typename T::accessor_t>(); + }, + list.size()); } template <class T, class K> diff --git a/src/storage/indexes/impl/unique_ordered_index.cpp b/src/storage/indexes/impl/unique_ordered_index.cpp index a0de33592..dc2e6ec83 100644 --- a/src/storage/indexes/impl/unique_ordered_index.cpp +++ b/src/storage/indexes/impl/unique_ordered_index.cpp @@ -64,23 +64,28 @@ auto UniqueOrderedIndex<T, K>::for_range_exact(DbAccessor &t_v, } else { assert(this->order() != None); } + // TODO: determine size on fact of border size. + auto size = acc.size(); - return iter::make_iterator([ - it = std::move(begin), b_end = std::move(end), t = t_v, - hold_acc = std::move(acc) - ]() mutable->auto { - while (b_end >= it->key) { - const IndexRecord<T, K> &r = *it; - if (r.is_valid(t.db_transaction.trans)) { - const typename T::accessor_t acc = r.access(t.db_transaction); + return iter::make_iterator( + [ + it = std::move(begin), b_end = std::move(end), t = t_v, + hold_acc = std::move(acc) + ]() mutable->auto { + while (b_end >= it->key) { + const IndexRecord<T, K> &r = *it; + if (r.is_valid(t.db_transaction.trans)) { + const typename T::accessor_t acc = + r.access(t.db_transaction); + it++; + return make_option(std::move(acc)); + } it++; - return make_option(std::move(acc)); } - it++; - } - return Option<const typename T::accessor_t>(); - }); + return Option<const typename T::accessor_t>(); + }, + size); } template <class T, class K> diff --git a/src/utils/iterator/iterator_base.cpp b/src/utils/iterator/iterator_base.cpp new file mode 100644 index 000000000..63615c825 --- /dev/null +++ b/src/utils/iterator/iterator_base.cpp @@ -0,0 +1,43 @@ +#include "utils/iterator/iterator.hpp" + +template <class T> +template <class OP> +auto IteratorBase<T>::map(OP &&op) +{ + return iter::make_map<decltype(std::move(*this)), OP>(std::move(*this), + std::move(op)); +} + +template <class T> +template <class OP> +auto IteratorBase<T>::filter(OP &&op) +{ + return iter::make_filter<decltype(std::move(*this)), OP>(std::move(*this), + std::move(op)); +} + +template <class T> +auto IteratorBase<T>::to() +{ + return map([](auto er) { return er.to(); }).fill(); +} + +template <class T> +auto IteratorBase<T>::fill() +{ + return filter([](auto &ra) { return ra.fill(); }); +} + +template <class T> +template <class TYPE> +auto IteratorBase<T>::type(TYPE const &type) +{ + return filter([&](auto &ra) { return ra.edge_type() == type; }); +} + +template <class T> +template <class OP> +void IteratorBase<T>::for_all(OP &&op) +{ + iter::for_all(std::move(*this), std::move(op)); +}