Skip to content

Commit

Permalink
Merge pull request #4182 from thehans/master
Browse files Browse the repository at this point in the history
Stack usage optimization for tostream_visitor
  • Loading branch information
thehans committed Mar 19, 2022
2 parents a6392b3 + 5a574ad commit 398d59f
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 94 deletions.
143 changes: 53 additions & 90 deletions src/core/Value.cc
Expand Up @@ -291,75 +291,12 @@ const str_utf8_wrapper& Value::toStrUtf8Wrapper() const {
return boost::get<str_utf8_wrapper>(this->value);
}

class tostring_visitor : public boost::static_visitor<std::string>
{
public:
template <typename T> std::string operator()(const T& op1) const {
assert(false && "unhandled tostring_visitor type");
return boost::lexical_cast<std::string>(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;
Expand Down Expand Up @@ -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 << ']';
Expand All @@ -416,26 +353,62 @@ class tostream_visitor : public boost::static_visitor<>
}
};

std::string Value::toString() const
class tostring_visitor : public boost::static_visitor<std::string>
{
return boost::apply_visitor(tostring_visitor(), this->value);
}
public:
template <typename T> std::string operator()(const T& op1) const {
assert(false && "unhandled tostring_visitor type");
return boost::lexical_cast<std::string>(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
Expand All @@ -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()) {
Expand Down
4 changes: 0 additions & 4 deletions src/core/Value.h
Expand Up @@ -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;
Expand Down

0 comments on commit 398d59f

Please sign in to comment.