From 0d43512ea96dcca51dda0782e170f9aef9ad13ab Mon Sep 17 00:00:00 2001 From: Riyyi Date: Thu, 24 Aug 2023 23:03:31 +0200 Subject: [PATCH] Everywhere: Do less Collection nodes copying --- src/ast.cpp | 16 +++++++++++++ src/ast.h | 11 ++++++++- src/environment.cpp | 2 +- src/environment.h | 2 +- src/eval-special-form.cpp | 12 +++++----- src/eval.cpp | 18 +++++++------- src/forward.h | 2 ++ src/functions.cpp | 50 +++++++++++++++++++-------------------- src/printer.cpp | 2 +- src/reader.cpp | 2 +- 10 files changed, 71 insertions(+), 46 deletions(-) diff --git a/src/ast.cpp b/src/ast.cpp index 5861337..c1f4307 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -7,6 +7,7 @@ #include // int64_t #include // std::static_pointer_cast #include +#include // std::move #include #include "ast.h" @@ -35,6 +36,11 @@ Collection::Collection(const ValueVector& nodes) { } +Collection::Collection(ValueVector&& nodes) noexcept + : m_nodes(std::move(nodes)) +{ +} + Collection::Collection(ValueVectorIt begin, ValueVectorIt end) : m_nodes(ValueVector(begin, end)) { @@ -64,6 +70,11 @@ List::List(const ValueVector& nodes) { } +List::List(ValueVector&& nodes) noexcept + : Collection(std::move(nodes)) +{ +} + List::List(ValueVectorIt begin, ValueVectorIt end) : Collection(begin, end) { @@ -86,6 +97,11 @@ Vector::Vector(const ValueVector& nodes) { } +Vector::Vector(ValueVector&& nodes) noexcept + : Collection(std::move(nodes)) +{ +} + Vector::Vector(ValueVectorIt begin, ValueVectorIt end) : Collection(begin, end) { diff --git a/src/ast.h b/src/ast.h index 3819554..58e63cc 100644 --- a/src/ast.h +++ b/src/ast.h @@ -101,11 +101,18 @@ public: ValuePtr front() const { return m_nodes.front(); } ValueVector rest() const; - const ValueVector& nodes() const { return m_nodes; } + ValueVectorConstIt begin() const { return m_nodes.cbegin(); } + ValueVectorConstIt end() const { return m_nodes.cend(); } + ValueVectorConstReverseIt beginReverse() const { return m_nodes.crbegin(); } + ValueVectorConstReverseIt endReverse() const { return m_nodes.crend(); } + + const ValueVector& nodesCopy() const { return m_nodes; } + std::span nodesRead() const { return m_nodes; } protected: Collection() = default; Collection(const ValueVector& nodes); + Collection(ValueVector&& nodes) noexcept; Collection(ValueVectorIt begin, ValueVectorIt end); Collection(ValueVectorConstIt begin, ValueVectorConstIt end); Collection(const Collection& that, ValuePtr meta); @@ -129,6 +136,7 @@ class List final : public Collection { public: List() = default; List(const ValueVector& nodes); + List(ValueVector&& nodes) noexcept; List(ValueVectorIt begin, ValueVectorIt end); List(ValueVectorConstIt begin, ValueVectorConstIt end); List(const List& that, ValuePtr meta); @@ -154,6 +162,7 @@ class Vector final : public Collection { public: Vector() = default; Vector(const ValueVector& nodes); + Vector(ValueVector&& nodes) noexcept; Vector(ValueVectorIt begin, ValueVectorIt end); Vector(ValueVectorConstIt begin, ValueVectorConstIt end); Vector(const Vector& that, ValuePtr meta); diff --git a/src/environment.cpp b/src/environment.cpp index 39ba951..ce83ac2 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -29,7 +29,7 @@ EnvironmentPtr Environment::create(EnvironmentPtr outer) return env; } -EnvironmentPtr Environment::create(const ValuePtr lambda, const ValueVector& arguments) +EnvironmentPtr Environment::create(const ValuePtr lambda, ValueVector&& arguments) { auto lambda_casted = std::static_pointer_cast(lambda); auto env = create(lambda_casted->env()); diff --git a/src/environment.h b/src/environment.h index a2e3c2e..f116e12 100644 --- a/src/environment.h +++ b/src/environment.h @@ -21,7 +21,7 @@ public: // Factory functions instead of constructors because it can fail in the bindings/arguments case static EnvironmentPtr create(); static EnvironmentPtr create(EnvironmentPtr outer); - static EnvironmentPtr create(const ValuePtr lambda, const ValueVector& arguments); + static EnvironmentPtr create(const ValuePtr lambda, ValueVector&& arguments); bool exists(const std::string& symbol); ValuePtr set(const std::string& symbol, ValuePtr value); diff --git a/src/eval-special-form.cpp b/src/eval-special-form.cpp index 3b5115f..6c897d9 100644 --- a/src/eval-special-form.cpp +++ b/src/eval-special-form.cpp @@ -73,7 +73,7 @@ ValuePtr Eval::evalFn(const ValueVector& nodes, EnvironmentPtr env) // First element needs to be a List or Vector VALUE_CAST(collection, Collection, nodes.front()); - const auto& collection_nodes = collection->nodes(); + const auto& collection_nodes = collection->nodesRead(); std::vector bindings; bindings.reserve(collection_nodes.size()); @@ -137,7 +137,7 @@ ValuePtr Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env) Error::the().clearErrors(); VALUE_CAST(catch_list, List, nodes.back()); - const auto& catch_nodes = catch_list->nodes(); + const auto& catch_nodes = catch_list->nodesRead(); CHECK_ARG_COUNT_IS("catch*", catch_nodes.size() - 1, 2); VALUE_CAST(catch_symbol, Symbol, catch_nodes.front()); @@ -209,7 +209,7 @@ void Eval::evalLet(const ValueVector& nodes, EnvironmentPtr env) // First argument needs to be a List or Vector VALUE_CAST(bindings, Collection, nodes.front(), void()); - const auto& binding_nodes = bindings->nodes(); + const auto& binding_nodes = bindings->nodesRead(); // List or Vector needs to have an even number of elements CHECK_ARG_COUNT_EVEN("bindings", binding_nodes.size(), void()); @@ -258,7 +258,7 @@ static ValuePtr startsWith(ValuePtr ast, const std::string& symbol) return nullptr; } - const auto& nodes = std::static_pointer_cast(ast)->nodes(); + const auto& nodes = std::static_pointer_cast(ast)->nodesRead(); if (nodes.empty() || !isSymbol(nodes.front(), symbol)) { return nullptr; @@ -294,10 +294,10 @@ static ValuePtr evalQuasiQuoteImpl(ValuePtr ast) ValuePtr result = makePtr(); - const auto& nodes = std::static_pointer_cast(ast)->nodes(); + auto collection = std::static_pointer_cast(ast); // `() or `(1 ~2 3) or `(1 ~@(list 2 2 2) 3) - for (auto it = nodes.crbegin(); it != nodes.crend(); ++it) { + for (auto it = collection->beginReverse(); it != collection->endReverse(); ++it) { const auto& elt = *it; const auto splice_unquote = startsWith(elt, "splice-unquote"); // (list 2 2 2) diff --git a/src/eval.cpp b/src/eval.cpp index e67c22d..b086705 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -148,7 +148,7 @@ ValuePtr Eval::evalAst(ValuePtr ast, EnvironmentPtr env) return result; } else if (is(ast_raw_ptr)) { - const auto& nodes = std::static_pointer_cast(ast)->nodes(); + const auto& nodes = std::static_pointer_cast(ast)->nodesRead(); size_t count = nodes.size(); auto evaluated_nodes = ValueVector(count); @@ -162,11 +162,11 @@ ValuePtr Eval::evalAst(ValuePtr ast, EnvironmentPtr env) evaluated_nodes.at(i) = eval_node; } - if (is(ast_raw_ptr)) { - return makePtr(evaluated_nodes); + if (is(ast_raw_ptr)) { + return makePtr(evaluated_nodes); } - return makePtr(evaluated_nodes); + return makePtr(evaluated_nodes); } else if (is(ast_raw_ptr)) { const auto& elements = std::static_pointer_cast(ast)->elements(); @@ -239,16 +239,16 @@ ValuePtr Eval::apply(std::shared_ptr evaluated_list) return nullptr; } - auto nodes = evaluated_list->nodes(); + auto front = evaluated_list->front(); - if (!is(nodes.front().get())) { - Error::the().add(::format("invalid function: {}", nodes.front())); + if (!is(front.get())) { + Error::the().add(::format("invalid function: {}", front)); return nullptr; } - auto function = std::static_pointer_cast(nodes.front())->function(); + auto function = std::static_pointer_cast(front)->function(); - return function(nodes.begin() + 1, nodes.end()); + return function(evaluated_list->begin() + 1, evaluated_list->end()); } } // namespace blaze diff --git a/src/forward.h b/src/forward.h index 9a01f49..5bebba1 100644 --- a/src/forward.h +++ b/src/forward.h @@ -18,7 +18,9 @@ class Value; typedef std::shared_ptr ValuePtr; typedef std::vector ValueVector; typedef ValueVector::iterator ValueVectorIt; +typedef ValueVector::reverse_iterator ValueVectorReverseIt; typedef ValueVector::const_iterator ValueVectorConstIt; +typedef ValueVector::const_reverse_iterator ValueVectorConstReverseIt; class Environment; typedef std::shared_ptr EnvironmentPtr; diff --git a/src/functions.cpp b/src/functions.cpp index 0cc90d0..68aeed8 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -239,16 +239,16 @@ ADD_FUNCTION( [&equal](ValuePtr lhs, ValuePtr rhs) -> bool { if ((is(lhs.get()) || is(lhs.get())) && (is(rhs.get()) || is(rhs.get()))) { - const auto& lhs_nodes = std::static_pointer_cast(lhs)->nodes(); - const auto& rhs_nodes = std::static_pointer_cast(rhs)->nodes(); + auto lhs_collection = std::static_pointer_cast(lhs); + auto rhs_collection = std::static_pointer_cast(rhs); - if (lhs_nodes.size() != rhs_nodes.size()) { + if (lhs_collection->size() != rhs_collection->size()) { return false; } - auto lhs_it = lhs_nodes.cbegin(); - auto rhs_it = rhs_nodes.cbegin(); - for (; lhs_it != lhs_nodes.end(); ++lhs_it, ++rhs_it) { + auto lhs_it = lhs_collection->begin(); + auto rhs_it = rhs_collection->begin(); + for (; lhs_it != lhs_collection->end(); ++lhs_it, ++rhs_it) { if (!equal(*lhs_it, *rhs_it)) { return false; } @@ -390,7 +390,7 @@ ADD_FUNCTION( // Remove atom and function from the argument list, add atom value begin += 2; - auto arguments = ValueVector(end - begin + 1); + auto arguments = ValueVector(SIZE() + 1); arguments[0] = atom->deref(); std::copy(begin, end, arguments.begin() + 1); @@ -401,7 +401,7 @@ ADD_FUNCTION( } else { auto lambda = std::static_pointer_cast(callable); - value = eval(lambda->body(), Environment::create(lambda, arguments)); + value = eval(lambda->body(), Environment::create(lambda, std::move(arguments))); } return atom->reset(value); @@ -417,7 +417,7 @@ ADD_FUNCTION( begin++; VALUE_CAST(collection, Collection, (*begin)); - const auto& collection_nodes = collection->nodes(); + const auto& collection_nodes = collection->nodesRead(); auto result_nodes = ValueVector(collection_nodes.size() + 1); result_nodes.at(0) = first; @@ -439,7 +439,7 @@ ADD_FUNCTION( auto result_nodes = ValueVector(count); size_t offset = 0; for (auto it = begin; it != end; ++it) { - const auto& collection_nodes = std::static_pointer_cast(*it)->nodes(); + const auto& collection_nodes = std::static_pointer_cast(*it)->nodesRead(); std::copy(collection_nodes.begin(), collection_nodes.end(), result_nodes.begin() + offset); offset += collection_nodes.size(); } @@ -459,7 +459,7 @@ ADD_FUNCTION( VALUE_CAST(collection, Collection, (*begin)); - return makePtr(collection->nodes()); + return makePtr(collection->nodesCopy()); }); // (nth (list 1 2 3) 0) @@ -470,20 +470,15 @@ ADD_FUNCTION( VALUE_CAST(collection, Collection, (*begin)); VALUE_CAST(number_node, Number, (*(begin + 1))); - auto collection_nodes = collection->nodes(); - auto index = (size_t)number_node->number(); + auto collection_nodes = collection->nodesRead(); + auto index = static_cast(number_node->number()); if (number_node->number() < 0 || index >= collection_nodes.size()) { Error::the().add("index is out of range"); return nullptr; } - auto result = collection_nodes.begin(); - for (size_t i = 0; i < index; ++i) { - result++; - } - - return *result; + return collection_nodes[index]; }); // (first (list 1 2 3)) -> 1 @@ -533,7 +528,7 @@ ADD_FUNCTION( arguments.reserve(arguments.size() + collection->size()); // Append list nodes to the argument leftovers - auto nodes = collection->nodes(); + auto nodes = collection->nodesRead(); for (const auto& node : nodes) { arguments.push_back(node); } @@ -545,7 +540,7 @@ ADD_FUNCTION( } else { auto lambda = std::static_pointer_cast(callable); - value = eval(lambda->body(), Environment::create(lambda, arguments)); + value = eval(lambda->body(), Environment::create(lambda, std::move(arguments))); } return value; @@ -559,7 +554,6 @@ ADD_FUNCTION( VALUE_CAST(callable, Callable, (*begin)); VALUE_CAST(collection, Collection, (*(begin + 1))); - const auto& collection_nodes = collection->nodes(); size_t count = collection->size(); auto nodes = ValueVector(count); @@ -567,11 +561,12 @@ ADD_FUNCTION( if (is(callable.get())) { auto function = std::static_pointer_cast(callable)->function(); for (size_t i = 0; i < count; ++i) { - nodes.at(i) = function(collection_nodes.begin() + i, collection_nodes.begin() + i + 1); + nodes.at(i) = function(collection->begin() + i, collection->begin() + i + 1); } } else { auto lambda = std::static_pointer_cast(callable); + auto collection_nodes = collection->nodesRead(); for (size_t i = 0; i < count; ++i) { nodes.at(i) = (eval(lambda->body(), Environment::create(lambda, { collection_nodes[i] }))); } @@ -911,7 +906,7 @@ ADD_FUNCTION( VALUE_CAST(collection, Collection, (*begin)); begin++; - const auto& collection_nodes = collection->nodes(); + const auto& collection_nodes = collection->nodesRead(); size_t collection_count = collection_nodes.size(); size_t argument_count = SIZE(); @@ -944,7 +939,10 @@ ADD_FUNCTION( if (is(front_raw_ptr) && std::static_pointer_cast(front)->state() == Constant::Nil) { return makePtr(); } - if (is(front_raw_ptr)) { + if (is(front_raw_ptr)) { + return front; + } + if (is(front_raw_ptr)) { auto collection = std::static_pointer_cast(front); if (collection->empty()) { @@ -955,7 +953,7 @@ ADD_FUNCTION( return front; } - return makePtr(collection->nodes()); + return makePtr(collection->nodesCopy()); } if (is(front_raw_ptr)) { auto string = std::static_pointer_cast(front); diff --git a/src/printer.cpp b/src/printer.cpp index 5d7c6bf..742afdf 100644 --- a/src/printer.cpp +++ b/src/printer.cpp @@ -76,7 +76,7 @@ void Printer::printImpl(ValuePtr node, bool print_readably) m_print += (is(node_raw_ptr)) ? '(' : '['; m_first_node = false; m_previous_node_is_list = true; - auto nodes = std::static_pointer_cast(node)->nodes(); + auto nodes = std::static_pointer_cast(node)->nodesRead(); for (auto node : nodes) { printImpl(node, print_readably); m_previous_node_is_list = false; diff --git a/src/reader.cpp b/src/reader.cpp index 5eca8b0..37d3751 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -373,7 +373,7 @@ void Reader::dumpImpl(ValuePtr node) Value* node_raw_ptr = node.get(); if (is(node_raw_ptr)) { - auto nodes = std::static_pointer_cast(node)->nodes(); + auto nodes = std::static_pointer_cast(node)->nodesRead(); print("{}", indentation); print(fg(ruc::format::TerminalColor::Blue), "{}Container", (is(node_raw_ptr)) ? "List" : "Vector"); print(" <");