From ce6085fa0635c71b14b92c376f4565f4cbc5a216 Mon Sep 17 00:00:00 2001 From: Marin Tomic Date: Tue, 9 Oct 2018 16:43:55 +0200 Subject: [PATCH] Fix pointer tracking in AST serialization Reviewers: teon.banek, llugovic Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1640 --- src/lisp/lcp.lisp | 8 +- src/query/frontend/ast/ast.cpp | 2 +- src/query/frontend/ast/ast.lcp | 177 +++++++++---------- src/query/frontend/ast/ast_serialization.lcp | 20 ++- src/query/plan/operator.lcp | 48 +++-- 5 files changed, 136 insertions(+), 119 deletions(-) diff --git a/src/lisp/lcp.lisp b/src/lisp/lcp.lisp index 0d52b1878..9bdc2e1c0 100644 --- a/src/lisp/lcp.lisp +++ b/src/lisp/lcp.lisp @@ -272,6 +272,8 @@ produces: ;; Extra arguments to the generated save function. List of (name cpp-type). (save-args nil :read-only t) (load-args nil :read-only t) + ;; Function to be called after saving the instance. Lambda taking builder name as only argument. + (post-save nil :read-only t) (construct nil :read-only t) ;; Explicit instantiation of template to generate schema with enum. (type-args nil :read-only t) @@ -1019,7 +1021,11 @@ Proto schema." (cpp-variable-name (first name-and-type))) (capnp-extra-args (find-cpp-class parent) :save)))))) ;; Save members - (write-string (capnp-save-members cpp-class builder :instance-access "self.") cpp-out)))) + (write-string (capnp-save-members cpp-class builder :instance-access "self.") cpp-out) + ;; Call post-save function if necessary + (let ((capnp-opts (cpp-class-capnp-opts cpp-class))) + (when (capnp-opts-post-save capnp-opts) + (write-string (cpp-code (funcall (capnp-opts-post-save capnp-opts) builder)) cpp-out)))))) (with-output-to-string (cpp-out) (let ((subclasses (capnp-union-subclasses cpp-class)) (builder (if (capnp-union-parents-rec cpp-class) diff --git a/src/query/frontend/ast/ast.cpp b/src/query/frontend/ast/ast.cpp index c39e0aae0..7f95cc352 100644 --- a/src/query/frontend/ast/ast.cpp +++ b/src/query/frontend/ast/ast.cpp @@ -5,7 +5,7 @@ namespace query { AstStorage::AstStorage() { - std::unique_ptr root(new Query(next_uid_++)); + std::unique_ptr root(new Query(++max_existing_uid_)); root_idx_ = 0; storage_.emplace_back(std::move(root)); } diff --git a/src/query/frontend/ast/ast.lcp b/src/query/frontend/ast/ast.lcp index 54c110599..58fe30570 100644 --- a/src/query/frontend/ast/ast.lcp +++ b/src/query/frontend/ast/ast.lcp @@ -56,16 +56,14 @@ cpp<# (defun load-ast-pointer (type) (lambda (reader member capnp-name) - (let ((cpp-type (lcp::cpp-type-name type))) - #>cpp - if (${reader}.has${capnp-name}()) { - std::unique_ptr<${cpp-type}> tmp; - Load(&tmp, ${reader}.get${capnp-name}(), storage, loaded_uids); - ${member} = storage->Take(std::move(tmp)); - } else { - ${member} = nullptr; - } - cpp<#))) + #>cpp + if (${reader}.has${capnp-name}()) { + ${member} = static_cast<${type}>( + Load(storage, ${reader}.get${capnp-name}(), loaded_uids)); + } else { + ${member} = nullptr; + } + cpp<#)) (defun save-ast-vector (type) (lcp:capnp-save-vector "capnp::Tree" type @@ -78,11 +76,9 @@ cpp<# (format nil "[storage, loaded_uids](const auto &reader) { - std::unique_ptr<~A> tmp; - Load(&tmp, reader, storage, loaded_uids); - return storage->Take(std::move(tmp)); + return static_cast<~A>(Load(storage, reader, loaded_uids)); }" - (remove #\* type)))) + type))) (defun save-property-map (builder member capnp-name) #>cpp @@ -102,13 +98,11 @@ cpp<# (defun load-property-map (reader member capnp-name) #>cpp for (const auto &entry : ${reader}.getEntries()) { - std::unique_ptr value; - Load(&value, entry.getValue(), storage, loaded_uids); std::string prop_name = entry.getKey().getFirst(); storage::Property prop_id; storage::Load(&prop_id, entry.getKey().getSecond()); ${member}.emplace(std::make_pair(prop_name, prop_id), - storage->Take(std::move(value))); + static_cast(Load(storage, entry.getValue(), loaded_uids))); } cpp<#) @@ -144,26 +138,20 @@ class AstStorage { template T *Create(Args &&... args) { - // Never call create for a Query. Call query() instead. - static_assert(!std::is_same::value, "Call query() instead"); - T *ptr = new T(next_uid_++, std::forward(args)...); + T *ptr = new T(++max_existing_uid_, std::forward(args)...); std::unique_ptr tmp(ptr); + if (std::is_same::value) { + root_idx_ = storage_.size(); + } storage_.emplace_back(std::move(tmp)); return ptr; } - template - T *Take(std::unique_ptr &&node) { - T *ret = node.get(); - storage_.emplace_back(std::move(node)); - return ret; - } - Query *query() const; // Public only for serialization access std::vector> storage_; - int next_uid_ = 0; + int max_existing_uid_ = -1; size_t root_idx_; }; cpp<# @@ -192,7 +180,18 @@ cpp<# (:serialize :capnp :base t :save-args '((saved-uids "std::vector *")) :load-args '((storage "AstStorage *") - (loaded-uids "std::vector *")))) + (loaded-uids "std::vector *")) + :post-save (lambda (builder) + (declare (ignore builder)) + ;; This is a bit hacky because it relies on the fact that parent class + ;; serialization is inlined so we can short-circuit and avoid serializing + ;; the derived class. + #>cpp + if (utils::Contains(*saved_uids, self.uid_)) { + return; + } + saved_uids->push_back(self.uid_); + cpp<#))) (lcp:define-class expression (tree) () @@ -217,7 +216,7 @@ cpp<# ((expression "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression"))) + :capnp-load (load-ast-pointer "Expression *"))) (:public #>cpp Where() = default; @@ -249,11 +248,11 @@ cpp<# ((expression1 "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (expression2 "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression"))) + :capnp-load (load-ast-pointer "Expression *"))) (:abstractp t) (:public #>cpp @@ -277,7 +276,7 @@ cpp<# ((expression "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression"))) + :capnp-load (load-ast-pointer "Expression *"))) (:abstractp t) (:public #>cpp @@ -426,15 +425,15 @@ cpp<# ((list "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (lower-bound "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (upper-bound "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression"))) + :capnp-load (load-ast-pointer "Expression *"))) (:public #>cpp ListSlicingOperator() = default; @@ -479,16 +478,16 @@ cpp<# ((condition "Expression *" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression") + :capnp-load (load-ast-pointer "Expression *") :documentation "None of the expressions should be nullptr. If there is no else_expression, you should make it null PrimitiveLiteral.") (then-expression "Expression *" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (else-expression "Expression *" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression"))) + :capnp-load (load-ast-pointer "Expression *"))) (:public #>cpp IfOperator() = default; @@ -689,7 +688,7 @@ cpp<# ((expression "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (property-name "std::string" :scope :public) (property "storage::Property" :scope :public)) (:public @@ -734,7 +733,7 @@ cpp<# ((expression "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (labels "std::vector" :scope :public :capnp-save (lcp:capnp-save-vector "storage::capnp::Common" @@ -829,27 +828,27 @@ cpp<# ((accumulator "Identifier *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier") + :capnp-load (load-ast-pointer "Identifier *") :documentation "Identifier for the accumulating variable") (initializer "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression") + :capnp-load (load-ast-pointer "Expression *") :documentation "Expression which produces the initial accumulator value.") (identifier "Identifier *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier") + :capnp-load (load-ast-pointer "Identifier *") :documentation "Identifier for the list element.") (list "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression") + :capnp-load (load-ast-pointer "Expression *") :documentation "Expression which produces a list to be reduced.") (expression "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression") + :capnp-load (load-ast-pointer "Expression *") :documentation "Expression which does the reduction, i.e. produces the new accumulator value.")) (:public #>cpp @@ -893,17 +892,17 @@ cpp<# ((identifier "Identifier *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier") + :capnp-load (load-ast-pointer "Identifier *") :documentation "Identifier for the list element.") (list "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression") + :capnp-load (load-ast-pointer "Expression *") :documentation "Expression which produces a list which will be extracted.") (expression "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression") + :capnp-load (load-ast-pointer "Expression *") :documentation "Expression which produces the new value for list element.")) (:public #>cpp @@ -943,15 +942,15 @@ cpp<# ((identifier "Identifier *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier")) + :capnp-load (load-ast-pointer "Identifier *")) (list-expression "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (where "Where *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Where"))) + :capnp-load (load-ast-pointer "Where *"))) (:public #>cpp All() = default; @@ -993,15 +992,15 @@ cpp<# ((identifier "Identifier *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier")) + :capnp-load (load-ast-pointer "Identifier *")) (list-expression "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (where "Where *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Where"))) + :capnp-load (load-ast-pointer "Where *"))) (:public #>cpp Single() = default; @@ -1067,7 +1066,7 @@ cpp<# (expression "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (token-position :int32_t :initval -1 :scope :public :documentation "This field contains token position of first token in named expression used to create name_. If NamedExpression object is not created from query or it is aliased leave this value at -1.")) (:public @@ -1110,7 +1109,7 @@ cpp<# ((identifier "Identifier *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier"))) + :capnp-load (load-ast-pointer "Identifier *"))) (:abstractp t) (:public #>cpp @@ -1195,12 +1194,12 @@ cpp<# (lower-bound "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression") + :capnp-load (load-ast-pointer "Expression *") :documentation "Evaluates to lower bound in variable length expands.") (upper-bound "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression") + :capnp-load (load-ast-pointer "Expression *") :documentation "Evaluated to upper bound in variable length expands.") (filter-lambda "Lambda" :scope :public :documentation "Filter lambda for variable length expands. Can have an empty expression, but identifiers must be valid, because an optimization pass may inline other expressions into this lambda.") @@ -1209,7 +1208,7 @@ cpp<# (total-weight "Identifier *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier") + :capnp-load (load-ast-pointer "Identifier *") :documentation "Variable where the total weight for weighted shortest path will be stored.")) (:public (lcp:define-enum type @@ -1222,17 +1221,17 @@ cpp<# ((inner-edge "Identifier *" :initval "nullptr" :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier") + :capnp-load (load-ast-pointer "Identifier *") :documentation "Argument identifier for the edge currently being traversed.") (inner-node "Identifier *" :initval "nullptr" :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier") + :capnp-load (load-ast-pointer "Identifier *") :documentation "Argument identifier for the destination node of the edge.") (expression "Expression *" :initval "nullptr" :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression") + :capnp-load (load-ast-pointer "Expression *") :documentation "Evaluates the result of the lambda.")) (:documentation "Lambda for use in filtering or weight calculation during variable expand.") (:serialize :capnp @@ -1323,7 +1322,7 @@ cpp<# ((identifier "Identifier *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier")) + :capnp-load (load-ast-pointer "Identifier *")) (atoms "std::vector" :scope :public :capnp-type "List(Tree)" @@ -1426,7 +1425,7 @@ cpp<# ((single-query "SingleQuery *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "SingleQuery")) + :capnp-load (load-ast-pointer "SingleQuery *")) (distinct :bool :initval "false" :scope :public) (union-symbols "std::vector" :scope :public :documentation "Holds symbols that are created during symbol generation phase. These symbols are used when UNION/UNION ALL combines single query results.")) @@ -1472,7 +1471,7 @@ cpp<# (single-query "SingleQuery *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "SingleQuery") + :capnp-load (load-ast-pointer "SingleQuery *") :documentation "First and potentially only query.") (cypher-unions "std::vector" :scope :public @@ -1499,7 +1498,7 @@ cpp<# // Creates deep copy of whole ast. Query *Clone(AstStorage &storage) const override { - auto *query = storage.query(); + auto *query = storage.Create(); query->single_query_ = single_query_->Clone(storage); for (auto *cypher_union : cypher_unions_) { query->cypher_unions_.push_back(cypher_union->Clone(storage)); @@ -1567,7 +1566,7 @@ cpp<# (where "Where *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Where")) + :capnp-load (load-ast-pointer "Where *")) (optional :bool :initval "false" :scope :public)) (:public #>cpp @@ -1622,7 +1621,7 @@ cpp<# (expression "Expression *" :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression"))) + :capnp-load (load-ast-pointer "Expression *"))) (:serialize :capnp :save-args '((saved-uids "std::vector *")) :load-args '((storage "AstStorage *") @@ -1658,12 +1657,12 @@ cpp<# (skip "Expression *" :initval "nullptr" :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression") + :capnp-load (load-ast-pointer "Expression *") :documentation "Optional expression on how many results to skip.") (limit "Expression *" :initval "nullptr" :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression") + :capnp-load (load-ast-pointer "Expression *") :documentation "Optional expression on how many results to produce.")) (:documentation "Contents common to @c Return and @c With clauses.") (:serialize :capnp @@ -1730,7 +1729,7 @@ cpp<# (where "Where *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Where"))) + :capnp-load (load-ast-pointer "Where *"))) (:public #>cpp With() = default; @@ -1825,11 +1824,11 @@ cpp<# ((property-lookup "PropertyLookup *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "PropertyLookup")) + :capnp-load (load-ast-pointer "PropertyLookup *")) (expression "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression"))) + :capnp-load (load-ast-pointer "Expression *"))) (:public #>cpp SetProperty() = default; @@ -1865,11 +1864,11 @@ cpp<# ((identifier "Identifier *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier")) + :capnp-load (load-ast-pointer "Identifier *")) (expression "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (update :bool :initval "false" :scope :public)) (:public #>cpp @@ -1908,7 +1907,7 @@ cpp<# ((identifier "Identifier *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier")) + :capnp-load (load-ast-pointer "Identifier *")) (labels "std::vector" :scope :public :capnp-save (lcp:capnp-save-vector "storage::capnp::Common" @@ -1949,7 +1948,7 @@ cpp<# ((property-lookup "PropertyLookup *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "PropertyLookup"))) + :capnp-load (load-ast-pointer "PropertyLookup *"))) (:public #>cpp RemoveProperty() = default; @@ -1982,7 +1981,7 @@ cpp<# ((identifier "Identifier *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Identifier")) + :capnp-load (load-ast-pointer "Identifier *")) (labels "std::vector" :scope :public :capnp-save (lcp:capnp-save-vector "storage::capnp::Common" @@ -2023,7 +2022,7 @@ cpp<# ((pattern "Pattern *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Pattern")) + :capnp-load (load-ast-pointer "Pattern *")) (on-match "std::vector" :scope :public :capnp-type "List(Tree)" @@ -2094,7 +2093,7 @@ cpp<# ((named-expression "NamedExpression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "NamedExpression"))) + :capnp-load (load-ast-pointer "NamedExpression *"))) (:public #>cpp Unwind() = default; @@ -2161,7 +2160,7 @@ cpp<# (password "Expression *" :initval "nullptr" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (privileges "std::vector" :scope :public :capnp-save (lambda (builder member capnp-name) #>cpp @@ -2293,23 +2292,23 @@ cpp<# (stream-uri "Expression *" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (stream-topic "Expression *" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (transform-uri "Expression *" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (batch-interval-in-ms "Expression *" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression")) + :capnp-load (load-ast-pointer "Expression *")) (batch-size "Expression *" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression"))) + :capnp-load (load-ast-pointer "Expression *"))) (:public #>cpp CreateStream() = default; @@ -2399,7 +2398,7 @@ cpp<# (limit-batches "Expression *" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression"))) + :capnp-load (load-ast-pointer "Expression *"))) (:public #>cpp StartStopStream() = default; @@ -2460,7 +2459,7 @@ cpp<# (limit-batches "Expression *" :scope :public :capnp-type "Tree" :capnp-init nil :capnp-save #'save-ast-pointer - :capnp-load (load-ast-pointer "Expression"))) + :capnp-load (load-ast-pointer "Expression *"))) (:public #>cpp TestStream() = default; diff --git a/src/query/frontend/ast/ast_serialization.lcp b/src/query/frontend/ast/ast_serialization.lcp index 20484a5b2..979bccbb9 100644 --- a/src/query/frontend/ast/ast_serialization.lcp +++ b/src/query/frontend/ast/ast_serialization.lcp @@ -20,12 +20,26 @@ cpp<# #>cpp Tree *Load(AstStorage *ast, const capnp::Tree::Reader &tree, std::vector *loaded_uids) { - ast->storage_.clear(); + // Check if element already deserialized and if yes, return existing + // element from storage. + auto uid = tree.getUid(); + if (utils::Contains(*loaded_uids, uid)) { + auto found = std::find_if(ast->storage_.begin(), ast->storage_.end(), + [&](const auto &n) { return n->uid_ == uid; }); + CHECK(found != ast->storage_.end()); + return found->get(); + } + std::unique_ptr root; ::query::Load(&root, tree, ast, loaded_uids); - ast->root_idx_ = ast->storage_.size(); + + if (dynamic_cast(root.get())) { + ast->root_idx_ = ast->storage_.size(); + } ast->storage_.emplace_back(std::move(root)); - return ast->storage_[ast->root_idx_].get(); + loaded_uids->emplace_back(uid); + ast->max_existing_uid_ = std::max(ast->max_existing_uid_, uid); + return ast->storage_.back().get(); } cpp<#) diff --git a/src/query/plan/operator.lcp b/src/query/plan/operator.lcp index df8c0cb7f..8832de3bb 100644 --- a/src/query/plan/operator.lcp +++ b/src/query/plan/operator.lcp @@ -245,16 +245,15 @@ can serve as inputs to others and thus a sequence of operations is formed.") (defun load-ast-pointer (ast-type) (lambda (reader member capnp-name) - (let ((cpp-type (remove #\* ast-type))) - #>cpp - if (${reader}.has${capnp-name}()) { - std::unique_ptr<${cpp-type}> tmp; - Load(&tmp, ${reader}.get${capnp-name}(), &helper->ast_storage, &helper->loaded_ast_uids); - ${member} = helper->ast_storage.Take(std::move(tmp)); - } else { - ${member} = nullptr; - } - cpp<#))) + #>cpp + if (${reader}.has${capnp-name}()) { + ${member} = static_cast<${ast-type}>(Load(&helper->ast_storage, + ${reader}.get${capnp-name}(), + &helper->loaded_ast_uids)); + } else { + ${member} = nullptr; + } + cpp<#)) (defun save-ast-vector (ast-type) (lcp:capnp-save-vector "::query::capnp::Tree" ast-type @@ -267,11 +266,10 @@ can serve as inputs to others and thus a sequence of operations is formed.") (format nil "[helper](const auto &reader) { - std::unique_ptr<~A> tmp; - Load(&tmp, reader, &helper->ast_storage, &helper->loaded_ast_uids); - return helper->ast_storage.Take(std::move(tmp)); + return static_cast<~A>(Load(&helper->ast_storage, reader, + &helper->loaded_ast_uids)); }" - (remove #\* ast-type)))) + ast-type))) (defun save-operator-pointer (builder member-name capnp-name) (declare (ignore capnp-name)) @@ -563,14 +561,15 @@ given label. (defun load-optional-bound (reader member capnp-name) (let ((load-bound - "[helper](const auto &reader) { - auto type = reader.getType() == ::utils::capnp::Bound<::query::capnp::Tree>::Type::INCLUSIVE - ? utils::BoundType::INCLUSIVE : utils::BoundType::EXCLUSIVE; - std::unique_ptr tmp; - Load(&tmp, reader.getValue(), &helper->ast_storage, &helper->loaded_ast_uids); - auto *value = static_cast(helper->ast_storage.Take(std::move(tmp))); - return utils::Bound(value, type); - }")) + "[helper](const auto &reader) { + auto type = reader.getType() == + ::utils::capnp::Bound<::query::capnp::Tree>::Type::INCLUSIVE + ? utils::BoundType::INCLUSIVE + : utils::BoundType::EXCLUSIVE; + auto *value = static_cast( + Load(&helper->ast_storage, reader.getValue(), &helper->loaded_ast_uids)); + return utils::Bound(value, type); + }")) (funcall (lcp:capnp-load-optional "::utils::capnp::Bound<::query::capnp::Tree>" "utils::Bound" load-bound) @@ -834,9 +833,8 @@ pulled.") :capnp-load (lambda (reader member capnp-name) #>cpp if (${reader}.hasExpression()) { - std::unique_ptr tmp; - Load(&tmp, ${reader}.getExpression(), ast_storage, loaded_ast_uids); - ${member} = ast_storage->Take(std::move(tmp)); + ${member} = static_cast( + Load(ast_storage, ${reader}.getExpression(), loaded_ast_uids)); } else { ${member} = nullptr; }