From 0f04e42dd5ee53af466e25a82667fe4c3b039775 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 27 Feb 2017 01:22:24 +0100 Subject: [PATCH] :zap: micro-optimizations for dump() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All ‘<<‘ calls have been replaced by write()/put() calls. The indentation strings needs not to be resized. Cachegrind measures 1% performance improvement. --- src/json.hpp | 92 +++++++++++++++++++++++++++++++++-------------- src/json.hpp.re2c | 92 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 132 insertions(+), 52 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 3a638d76..1094aade 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -8420,47 +8420,69 @@ class basic_json { if (m_value.object->empty()) { - o << "{}"; + o.write("{}", 2); return; } if (pretty_print) { - o << "{\n"; + o.write("{\n", 2); // variable to hold indentation for recursive calls const auto new_indent = current_indent + indent_step; string_t indent_string = string_t(new_indent, ' '); + // first n-1 elements auto i = m_value.object->cbegin(); for (size_t cnt = 0; cnt < m_value.object->size() - 1; ++cnt, ++i) { - o << indent_string << '\"' << escape_string(i->first) << "\": "; + o.write(indent_string.c_str(), new_indent); + o.put('\"'); + const auto s = escape_string(i->first); + o.write(s.c_str(), static_cast(s.size())); + o.write("\": ", 3); i->second.dump(o, true, indent_step, new_indent); - o << ",\n"; + o.write(",\n", 2); } - o << indent_string << '\"' << escape_string(i->first) << "\": "; + // last element + assert(i != m_value.object->cend()); + o.write(indent_string.c_str(), new_indent); + o.put('\"'); + const auto s = escape_string(i->first); + o.write(s.c_str(), static_cast(s.size())); + o.write("\": ", 3); i->second.dump(o, true, indent_step, new_indent); - indent_string.resize(current_indent); - o << '\n' << indent_string << '}'; + o.put('\n'); + o.write(indent_string.c_str(), current_indent); + o.put('}'); } else { - o << '{'; + o.put('{'); + // first n-1 elements auto i = m_value.object->cbegin(); for (size_t cnt = 0; cnt < m_value.object->size() - 1; ++cnt, ++i) { - o << '\"' << escape_string(i->first) << "\":"; + o.put('\"'); + const auto s = escape_string(i->first); + o.write(s.c_str(), static_cast(s.size())); + o.write("\":", 2); i->second.dump(o, false, indent_step, current_indent); - o << ','; + o.put(','); } - o << '\"' << escape_string(i->first) << "\":"; + // last element + assert(i != m_value.object->cend()); + o.put('\"'); + const auto s = escape_string(i->first); + o.write(s.c_str(), static_cast(s.size())); + o.write("\":", 2); i->second.dump(o, false, indent_step, current_indent); - o << '}'; + + o.put('}'); } return; @@ -8470,43 +8492,51 @@ class basic_json { if (m_value.array->empty()) { - o << "[]"; + o.write("[]", 2); return; } if (pretty_print) { - o << "[\n"; + o.write("[\n", 2); // variable to hold indentation for recursive calls const auto new_indent = current_indent + indent_step; string_t indent_string = string_t(new_indent, ' '); + // first n-1 elements for (auto i = m_value.array->cbegin(); i != m_value.array->cend() - 1; ++i) { - o << indent_string; + o.write(indent_string.c_str(), new_indent); i->dump(o, true, indent_step, new_indent); - o << ",\n"; + o.write(",\n", 2); } - o << indent_string; + // last element assert(not m_value.array->empty()); + o.write(indent_string.c_str(), new_indent); m_value.array->back().dump(o, true, indent_step, new_indent); - indent_string.resize(current_indent); - o << '\n' << indent_string << ']'; + o.put('\n'); + o.write(indent_string.c_str(), current_indent); + o.put(']'); } else { - o << '['; + o.put('['); + + // first n-1 elements for (auto i = m_value.array->cbegin(); i != m_value.array->cend() - 1; ++i) { i->dump(o, false, indent_step, current_indent); - o << ','; + o.put(','); } + + // last element assert(not m_value.array->empty()); m_value.array->back().dump(o, false, indent_step, current_indent); - o << ']'; + + o.put(']'); } return; @@ -8514,13 +8544,23 @@ class basic_json case value_t::string: { - o << '\"' << escape_string(*m_value.string) << '\"'; + o.put('\"'); + const auto s = escape_string(*m_value.string); + o.write(s.c_str(), static_cast(s.size())); + o.put('\"'); return; } case value_t::boolean: { - o << (m_value.boolean ? "true" : "false"); + if (m_value.boolean) + { + o.write("true", 4); + } + else + { + o.write("false", 5); + } return; } @@ -8544,13 +8584,13 @@ class basic_json case value_t::discarded: { - o << ""; + o.write("", 11); return; } case value_t::null: { - o << "null"; + o.write("null", 4); return; } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 796f8c56..a686a1a7 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -8420,47 +8420,69 @@ class basic_json { if (m_value.object->empty()) { - o << "{}"; + o.write("{}", 2); return; } if (pretty_print) { - o << "{\n"; + o.write("{\n", 2); // variable to hold indentation for recursive calls const auto new_indent = current_indent + indent_step; string_t indent_string = string_t(new_indent, ' '); + // first n-1 elements auto i = m_value.object->cbegin(); for (size_t cnt = 0; cnt < m_value.object->size() - 1; ++cnt, ++i) { - o << indent_string << '\"' << escape_string(i->first) << "\": "; + o.write(indent_string.c_str(), new_indent); + o.put('\"'); + const auto s = escape_string(i->first); + o.write(s.c_str(), static_cast(s.size())); + o.write("\": ", 3); i->second.dump(o, true, indent_step, new_indent); - o << ",\n"; + o.write(",\n", 2); } - o << indent_string << '\"' << escape_string(i->first) << "\": "; + // last element + assert(i != m_value.object->cend()); + o.write(indent_string.c_str(), new_indent); + o.put('\"'); + const auto s = escape_string(i->first); + o.write(s.c_str(), static_cast(s.size())); + o.write("\": ", 3); i->second.dump(o, true, indent_step, new_indent); - indent_string.resize(current_indent); - o << '\n' << indent_string << '}'; + o.put('\n'); + o.write(indent_string.c_str(), current_indent); + o.put('}'); } else { - o << '{'; + o.put('{'); + // first n-1 elements auto i = m_value.object->cbegin(); for (size_t cnt = 0; cnt < m_value.object->size() - 1; ++cnt, ++i) { - o << '\"' << escape_string(i->first) << "\":"; + o.put('\"'); + const auto s = escape_string(i->first); + o.write(s.c_str(), static_cast(s.size())); + o.write("\":", 2); i->second.dump(o, false, indent_step, current_indent); - o << ','; + o.put(','); } - o << '\"' << escape_string(i->first) << "\":"; + // last element + assert(i != m_value.object->cend()); + o.put('\"'); + const auto s = escape_string(i->first); + o.write(s.c_str(), static_cast(s.size())); + o.write("\":", 2); i->second.dump(o, false, indent_step, current_indent); - o << '}'; + + o.put('}'); } return; @@ -8470,43 +8492,51 @@ class basic_json { if (m_value.array->empty()) { - o << "[]"; + o.write("[]", 2); return; } if (pretty_print) { - o << "[\n"; + o.write("[\n", 2); // variable to hold indentation for recursive calls const auto new_indent = current_indent + indent_step; string_t indent_string = string_t(new_indent, ' '); + // first n-1 elements for (auto i = m_value.array->cbegin(); i != m_value.array->cend() - 1; ++i) { - o << indent_string; + o.write(indent_string.c_str(), new_indent); i->dump(o, true, indent_step, new_indent); - o << ",\n"; + o.write(",\n", 2); } - o << indent_string; + // last element assert(not m_value.array->empty()); + o.write(indent_string.c_str(), new_indent); m_value.array->back().dump(o, true, indent_step, new_indent); - indent_string.resize(current_indent); - o << '\n' << indent_string << ']'; + o.put('\n'); + o.write(indent_string.c_str(), current_indent); + o.put(']'); } else { - o << '['; + o.put('['); + + // first n-1 elements for (auto i = m_value.array->cbegin(); i != m_value.array->cend() - 1; ++i) { i->dump(o, false, indent_step, current_indent); - o << ','; + o.put(','); } + + // last element assert(not m_value.array->empty()); m_value.array->back().dump(o, false, indent_step, current_indent); - o << ']'; + + o.put(']'); } return; @@ -8514,13 +8544,23 @@ class basic_json case value_t::string: { - o << '\"' << escape_string(*m_value.string) << '\"'; + o.put('\"'); + const auto s = escape_string(*m_value.string); + o.write(s.c_str(), static_cast(s.size())); + o.put('\"'); return; } case value_t::boolean: { - o << (m_value.boolean ? "true" : "false"); + if (m_value.boolean) + { + o.write("true", 4); + } + else + { + o.write("false", 5); + } return; } @@ -8544,13 +8584,13 @@ class basic_json case value_t::discarded: { - o << ""; + o.write("", 11); return; } case value_t::null: { - o << "null"; + o.write("null", 4); return; } }