Optimisation

Signed-off-by: JCW <a1q123456@users.noreply.github.com>
This commit is contained in:
JCW
2025-09-02 00:28:28 +01:00
parent f7c043bd04
commit 284b825a5f
3 changed files with 48 additions and 52 deletions

View File

@@ -80,46 +80,44 @@ namespace beast {
class SimpleJsonWriter class SimpleJsonWriter
{ {
public: public:
explicit SimpleJsonWriter(std::ostringstream& stream) : stream_(stream) explicit SimpleJsonWriter(std::string& stream) : stream_(stream)
{ {
stream_.imbue(std::locale::classic());
} }
void void
startObject() const startObject() const
{ {
stream_.put('{'); stream_.append("{", 1);
} }
void void
endObject() const endObject() const
{ {
stream_.seekp(-1, std::ios_base::end); stream_.pop_back();
stream_.write("},", 2); stream_.append("},", 2);
} }
void void
writeKey(std::string_view key) const writeKey(std::string_view key) const
{ {
writeString(key); writeString(key);
stream_.seekp(-1, std::ios_base::end); *stream_.rbegin() = ':';
stream_.put(':');
} }
void void
startArray() const startArray() const
{ {
stream_.put('['); stream_.append("[", 1);
} }
void void
endArray() const endArray() const
{ {
stream_.seekp(-1, std::ios_base::end); stream_.pop_back();
stream_.write("],", 2); stream_.append("],", 2);
} }
void void
writeString(std::string_view str) const writeString(std::string_view str) const
{ {
stream_.put('"'); stream_.push_back('"');
escape(str, stream_); escape(str, stream_);
stream_.write("\",", 2); stream_.append("\",", 2);
} }
std::string_view std::string_view
writeInt(std::int64_t val) const writeInt(std::int64_t val) const
@@ -140,44 +138,43 @@ public:
writeBool(bool val) const writeBool(bool val) const
{ {
auto str = val ? "true," : "false,"; auto str = val ? "true," : "false,";
stream_.write(str, std::strlen(str)); stream_.append(str, std::strlen(str));
return str; return str;
} }
void void
writeNull() const writeNull() const
{ {
stream_.write("null", std::strlen("null")); stream_.append("null", std::strlen("null"));
stream_.put(','); stream_.push_back(',');
} }
void void
writeRaw(std::string_view str) const writeRaw(std::string_view str) const
{ {
stream_.write(str.data(), str.length()); stream_.append(str);
} }
[[nodiscard]] std::string [[nodiscard]] std::string
str() const finish()
{ {
auto result = stream_.str(); stream_.pop_back();
result.pop_back(); return stream_;
return result;
} }
private: private:
template <typename T> template <typename T>
static std::string_view static std::string_view
pushNumber(T val, std::ostringstream& stream) pushNumber(T val, std::string& stream)
{ {
static char buffer[128]; static char buffer[128];
auto result = std::to_chars(std::begin(buffer), std::end(buffer), val); auto result = std::to_chars(std::begin(buffer), std::end(buffer), val);
*result.ptr = ','; *result.ptr = ',';
auto len = result.ptr - std::begin(buffer); auto len = result.ptr - std::begin(buffer);
stream.write(buffer, len + 1); stream.append(buffer, len + 1);
return {buffer, static_cast<size_t>(len)}; return {buffer, static_cast<size_t>(len)};
} }
static void static void
escape(std::string_view str, std::ostringstream& os) escape(std::string_view str, std::string& os)
{ {
static constexpr char HEX[] = "0123456789ABCDEF"; static constexpr char HEX[] = "0123456789ABCDEF";
@@ -198,16 +195,16 @@ private:
// Flush the preceding safe run in one go. // Flush the preceding safe run in one go.
if (chunk != p) if (chunk != p)
os.write(chunk, p - chunk); os.append(chunk, p - chunk);
switch (c) { switch (c) {
case '"': os.write("\\\"", 2); break; case '"': os.append("\\\"", 2); break;
case '\\': os.write("\\\\", 2); break; case '\\': os.append("\\\\", 2); break;
case '\b': os.write("\\b", 2); break; case '\b': os.append("\\b", 2); break;
case '\f': os.write("\\f", 2); break; case '\f': os.append("\\f", 2); break;
case '\n': os.write("\\n", 2); break; case '\n': os.append("\\n", 2); break;
case '\r': os.write("\\r", 2); break; case '\r': os.append("\\r", 2); break;
case '\t': os.write("\\t", 2); break; case '\t': os.append("\\t", 2); break;
default: { default: {
// Other C0 controls -> \u00XX (JSON compliant) // Other C0 controls -> \u00XX (JSON compliant)
char buf[6]{ char buf[6]{
@@ -215,7 +212,7 @@ private:
HEX[(c >> 4) & 0xF], HEX[(c >> 4) & 0xF],
HEX[c & 0xF] HEX[c & 0xF]
}; };
os.write(buf, 6); os.append(buf, 6);
break; break;
} }
} }
@@ -226,10 +223,10 @@ private:
// Flush trailing safe run // Flush trailing safe run
if (chunk != p) if (chunk != p)
os.write(chunk, p - chunk); os.append(chunk, p - chunk);
} }
std::ostringstream& stream_; std::string& stream_;
}; };
/** A namespace for easy access to logging severity values. */ /** A namespace for easy access to logging severity values. */
@@ -284,7 +281,7 @@ public:
class JsonLogContext class JsonLogContext
{ {
std::ostringstream buffer_; std::string buffer_;
SimpleJsonWriter messageParamsWriter_; SimpleJsonWriter messageParamsWriter_;
public: public:
@@ -567,14 +564,14 @@ public:
Journal(Journal const& other, TAttributesFactory&& attributesFactory) Journal(Journal const& other, TAttributesFactory&& attributesFactory)
: m_name(other.m_name), m_sink(other.m_sink) : m_name(other.m_name), m_sink(other.m_sink)
{ {
std::ostringstream stream{other.m_attributesJson, std::ios_base::app}; std::string stream{other.m_attributesJson};
SimpleJsonWriter writer{stream}; SimpleJsonWriter writer{stream};
if (other.m_attributesJson.empty()) if (other.m_attributesJson.empty())
{ {
writer.startObject(); writer.startObject();
} }
attributesFactory(writer); attributesFactory(writer);
m_attributesJson = stream.str(); m_attributesJson = std::move(stream);
} }
/** Create a journal that writes to the specified sink. */ /** Create a journal that writes to the specified sink. */
@@ -591,11 +588,11 @@ public:
TAttributesFactory&& attributesFactory) TAttributesFactory&& attributesFactory)
: m_name(name), m_sink(&sink) : m_name(name), m_sink(&sink)
{ {
std::ostringstream stream; std::string stream;
SimpleJsonWriter writer{stream}; SimpleJsonWriter writer{stream};
writer.startObject(); writer.startObject();
attributesFactory(writer); attributesFactory(writer);
m_attributesJson = stream.str(); m_attributesJson = std::move(stream);
} }
Journal& Journal&
@@ -712,15 +709,14 @@ public:
std::lock_guard lock(globalLogAttributesMutex_); std::lock_guard lock(globalLogAttributesMutex_);
auto isEmpty = globalLogAttributesJson_.empty(); auto isEmpty = globalLogAttributesJson_.empty();
std::ostringstream stream{ std::string stream{std::move(globalLogAttributesJson_)};
std::move(globalLogAttributesJson_), std::ios_base::app};
SimpleJsonWriter writer{stream}; SimpleJsonWriter writer{stream};
if (isEmpty) if (isEmpty)
{ {
writer.startObject(); writer.startObject();
} }
factory(writer); factory(writer);
globalLogAttributesJson_ = stream.str(); globalLogAttributesJson_ = std::move(stream);
} }
}; };

View File

@@ -138,7 +138,7 @@ Journal::JsonLogContext::reset(
}; };
thread_local ThreadIdStringInitializer const threadId; thread_local ThreadIdStringInitializer const threadId;
buffer_.str(""); buffer_.clear();
writer().startObject(); writer().startObject();
@@ -206,7 +206,7 @@ Journal::formatLog(std::string&& message)
writer.endObject(); writer.endObject();
return writer.str(); return writer.finish();
} }
void void

View File

@@ -212,35 +212,35 @@ TEST_CASE("Global attributes inheritable")
TEST_CASE("Test JsonWriter") TEST_CASE("Test JsonWriter")
{ {
{ {
std::ostringstream stream; std::string stream;
beast::SimpleJsonWriter writer{stream}; beast::SimpleJsonWriter writer{stream};
writer.writeString("\n"); writer.writeString("\n");
CHECK(writer.str() == "\"\\n\""); CHECK(writer.finish() == "\"\\n\"");
} }
{ {
std::ostringstream stream; std::string stream;
beast::SimpleJsonWriter writer{stream}; beast::SimpleJsonWriter writer{stream};
writer.writeString("\t"); writer.writeString("\t");
CHECK(writer.str() == "\"\\t\""); CHECK(writer.finish() == "\"\\t\"");
} }
{ {
std::ostringstream stream; std::string stream;
beast::SimpleJsonWriter writer{stream}; beast::SimpleJsonWriter writer{stream};
writer.writeString(std::string_view{"\0", 1}); writer.writeString(std::string_view{"\0", 1});
CHECK(writer.str() == "\"\\u0000\""); CHECK(writer.finish() == "\"\\u0000\"");
} }
{ {
std::ostringstream stream; std::string stream;
beast::SimpleJsonWriter writer{stream}; beast::SimpleJsonWriter writer{stream};
writer.writeString("\"\\"); writer.writeString("\"\\");
CHECK(writer.str() == "\"\\\"\\\\\""); CHECK(writer.finish() == "\"\\\"\\\\\"");
} }
} }