From 5a574adbc1b179b55a694503f0ee58a69c1cc7b9 Mon Sep 17 00:00:00 2001 From: Hans Loeblich Date: Fri, 18 Mar 2022 19:12:18 -0500 Subject: [PATCH] Stack usage optimization for tostream_visitor (related to #4172) Also remove unused Value toString,toStream functions. --- src/core/Value.cc | 143 +++++++++++++++++----------------------------- src/core/Value.h | 4 -- 2 files changed, 53 insertions(+), 94 deletions(-) diff --git a/src/core/Value.cc b/src/core/Value.cc index 3d9a468ee5..abc10e5903 100644 --- a/src/core/Value.cc +++ b/src/core/Value.cc @@ -291,75 +291,12 @@ const str_utf8_wrapper& Value::toStrUtf8Wrapper() const { return boost::get(this->value); } -class tostring_visitor : public boost::static_visitor -{ -public: - template std::string operator()(const T& op1) const { - assert(false && "unhandled tostring_visitor type"); - return boost::lexical_cast(op1); - } - - std::string operator()(const str_utf8_wrapper& op1) const { - return op1.toString(); - } - - std::string operator()(const double& op1) const { - char buffer[DC_BUFFER_SIZE]; - double_conversion::StringBuilder builder(buffer, DC_BUFFER_SIZE); - double_conversion::DoubleToStringConverter dc(DC_FLAGS, DC_INF, DC_NAN, DC_EXP, - DC_DECIMAL_LOW_EXP, DC_DECIMAL_HIGH_EXP, DC_MAX_LEADING_ZEROES, DC_MAX_TRAILING_ZEROES); - return DoubleConvert(op1, buffer, builder, dc); - } - - std::string operator()(const UndefType&) const { - return "undef"; - } - - std::string operator()(const bool& v) const { - return v ? "true" : "false"; - } - - std::string operator()(const EmbeddedVectorType&) const { - assert(false && "Error: unexpected visit to EmbeddedVectorType!"); - return ""; - } - - std::string operator()(const VectorType& v) const { - // Create a single stream and pass reference to it for list elements for optimization. - std::ostringstream stream; - stream << '['; - if (!v.empty()) { - auto it = v.begin(); - it->toStream(stream); - for (++it; it != v.end(); ++it) { - stream << ", "; - it->toStream(stream); - } - } - stream << ']'; - return stream.str(); - } - - std::string operator()(const ObjectType& v) const { - return STR(v); - } - - std::string operator()(const RangePtr& v) const { - return STR(*v); - } - - std::string operator()(const FunctionPtr& v) const { - return STR(*v); - } -}; - // Optimization to avoid multiple stream instantiations and copies to str for long vectors. // Functions identically to "class tostring_visitor", except outputting to stream and not returning strings class tostream_visitor : public boost::static_visitor<> { public: std::ostringstream& stream; - mutable char buffer[DC_BUFFER_SIZE]; mutable double_conversion::StringBuilder builder; double_conversion::DoubleToStringConverter dc; @@ -394,10 +331,10 @@ class tostream_visitor : public boost::static_visitor<> stream << '['; if (!v.empty()) { auto it = v.begin(); - it->toStream(stream); + boost::apply_visitor(*this, it->getVariant()); for (++it; it != v.end(); ++it) { stream << ", "; - it->toStream(stream); + boost::apply_visitor(*this, it->getVariant()); } } stream << ']'; @@ -416,26 +353,62 @@ class tostream_visitor : public boost::static_visitor<> } }; -std::string Value::toString() const +class tostring_visitor : public boost::static_visitor { - return boost::apply_visitor(tostring_visitor(), this->value); -} +public: + template std::string operator()(const T& op1) const { + assert(false && "unhandled tostring_visitor type"); + return boost::lexical_cast(op1); + } -// helper called by tostring_visitor methods to avoid extra instantiations -std::string Value::toString(const tostring_visitor *visitor) const -{ - return boost::apply_visitor(*visitor, this->value); -} + std::string operator()(const str_utf8_wrapper& op1) const { + return op1.toString(); + } -void Value::toStream(std::ostringstream& stream) const -{ - boost::apply_visitor(tostream_visitor(stream), this->value); -} + std::string operator()(const double& op1) const { + char buffer[DC_BUFFER_SIZE]; + double_conversion::StringBuilder builder(buffer, DC_BUFFER_SIZE); + double_conversion::DoubleToStringConverter dc(DC_FLAGS, DC_INF, DC_NAN, DC_EXP, + DC_DECIMAL_LOW_EXP, DC_DECIMAL_HIGH_EXP, DC_MAX_LEADING_ZEROES, DC_MAX_TRAILING_ZEROES); + return DoubleConvert(op1, buffer, builder, dc); + } + + std::string operator()(const UndefType&) const { + return "undef"; + } + + std::string operator()(const bool& v) const { + return v ? "true" : "false"; + } + + std::string operator()(const EmbeddedVectorType&) const { + assert(false && "Error: unexpected visit to EmbeddedVectorType!"); + return ""; + } + + std::string operator()(const VectorType& v) const { + // Create a single stream and pass reference to it for list elements for optimization. + std::ostringstream stream; + (tostream_visitor(stream))(v); + return stream.str(); + } + + std::string operator()(const ObjectType& v) const { + return STR(v); + } -// helper called by tostream_visitor methods to avoid extra instantiations -void Value::toStream(const tostream_visitor *visitor) const + std::string operator()(const RangePtr& v) const { + return STR(*v); + } + + std::string operator()(const FunctionPtr& v) const { + return STR(*v); + } +}; + +std::string Value::toString() const { - boost::apply_visitor(*visitor, this->value); + return boost::apply_visitor(tostring_visitor(), this->value); } std::string Value::toEchoString() const @@ -447,16 +420,6 @@ std::string Value::toEchoString() const } } -// helper called by tostring_visitor methods to avoid extra instantiations -std::string Value::toEchoString(const tostring_visitor *visitor) const -{ - if (type() == Value::Type::STRING) { - return std::string("\"") + toString(visitor) + '"'; - } else { - return toString(visitor); - } -} - std::string UndefType::toString() const { std::ostringstream stream; if (!reasons->empty()) { diff --git a/src/core/Value.h b/src/core/Value.h index 3a574af9da..e9793b548a 100644 --- a/src/core/Value.h +++ b/src/core/Value.h @@ -578,13 +578,9 @@ class Value bool getDouble(double& v) const; bool getFiniteDouble(double& v) const; std::string toString() const; - std::string toString(const tostring_visitor *visitor) const; std::string toEchoString() const; - std::string toEchoString(const tostring_visitor *visitor) const; const UndefType& toUndef(); std::string toUndefString() const; - void toStream(std::ostringstream& stream) const; - void toStream(const tostream_visitor *visitor) const; std::string chrString() const; bool getVec2(double& x, double& y, bool ignoreInfinite = false) const; bool getVec3(double& x, double& y, double& z) const;