mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-23 21:55:03 +02:00
JsonEncoder: wrap writer for flushing
This commit introduces intruduces a small helper class that wraps any writer and provides a flush operation that performs the corresponding action if the writer is an AsyncJsonWriter and does nothing otherwise.
This commit is contained in:
parent
89418f38ee
commit
30f7d74c7c
@ -24,7 +24,7 @@ JsonEncoder::JsonEncoder(std::basic_ostream<char>& stream, bool prettify)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsonEncoder::JsonEncoder(nlohmann::detail::output_adapter_t<char> w, bool prettify)
|
JsonEncoder::JsonEncoder(nlohmann::detail::output_adapter_t<char> w, bool prettify)
|
||||||
: m_IsAsyncWriter{dynamic_cast<AsyncJsonWriter*>(w.get()) != nullptr}, m_Pretty(prettify), m_Writer(std::move(w))
|
: m_Flusher{w}, m_Pretty(prettify), m_Writer(std::move(w))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ void JsonEncoder::EncodeArray(const Array::Ptr& array, boost::asio::yield_contex
|
|||||||
WriteSeparatorAndIndentStrIfNeeded(!isEmpty);
|
WriteSeparatorAndIndentStrIfNeeded(!isEmpty);
|
||||||
isEmpty = false;
|
isEmpty = false;
|
||||||
Encode(item, yc);
|
Encode(item, yc);
|
||||||
FlushIfSafe(yc);
|
m_Flusher.FlushIfSafe(yc);
|
||||||
}
|
}
|
||||||
EndContainer(']', isEmpty);
|
EndContainer(']', isEmpty);
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ void JsonEncoder::EncodeValueGenerator(const ValueGenerator::Ptr& generator, boo
|
|||||||
WriteSeparatorAndIndentStrIfNeeded(!isEmpty);
|
WriteSeparatorAndIndentStrIfNeeded(!isEmpty);
|
||||||
isEmpty = false;
|
isEmpty = false;
|
||||||
Encode(*result, yc);
|
Encode(*result, yc);
|
||||||
FlushIfSafe(yc);
|
m_Flusher.FlushIfSafe(yc);
|
||||||
}
|
}
|
||||||
EndContainer(']', isEmpty);
|
EndContainer(']', isEmpty);
|
||||||
}
|
}
|
||||||
@ -171,7 +171,7 @@ void JsonEncoder::EncodeObject(const Iterable& container, const ValExtractor& ex
|
|||||||
Write(m_Pretty ? ": " : ":");
|
Write(m_Pretty ? ": " : ":");
|
||||||
|
|
||||||
Encode(extractor(val), yc);
|
Encode(extractor(val), yc);
|
||||||
FlushIfSafe(yc);
|
m_Flusher.FlushIfSafe(yc);
|
||||||
}
|
}
|
||||||
EndContainer('}', isEmpty);
|
EndContainer('}', isEmpty);
|
||||||
}
|
}
|
||||||
@ -223,29 +223,6 @@ void JsonEncoder::EncodeNumber(double value) const
|
|||||||
EncodeNlohmannJson(value);
|
EncodeNlohmannJson(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Flushes the output stream if it is safe to do so.
|
|
||||||
*
|
|
||||||
* Safe flushing means that it only performs the flush operation if the @c JsonEncoder has not acquired
|
|
||||||
* any object lock so far. This is to ensure that the stream can safely perform asynchronous operations
|
|
||||||
* without risking undefined behaviour due to coroutines being suspended while the stream is being flushed.
|
|
||||||
*
|
|
||||||
* When the @c yc parameter is provided, it indicates that it's safe to perform asynchronous operations,
|
|
||||||
* and the function will attempt to flush if the writer is an instance of @c AsyncJsonWriter.
|
|
||||||
*
|
|
||||||
* @param yc The yield context to use for asynchronous operations.
|
|
||||||
*/
|
|
||||||
void JsonEncoder::FlushIfSafe(boost::asio::yield_context* yc) const
|
|
||||||
{
|
|
||||||
if (yc && m_IsAsyncWriter) {
|
|
||||||
// The m_IsAsyncWriter flag is a constant, and it will never change, so we can safely static
|
|
||||||
// cast the m_Writer to AsyncJsonWriter without any additional checks as it is guaranteed
|
|
||||||
// to be an instance of AsyncJsonWriter when m_IsAsyncWriter is true.
|
|
||||||
auto ajw(static_cast<AsyncJsonWriter*>(m_Writer.get()));
|
|
||||||
ajw->Flush(*yc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a string to the underlying output stream.
|
* Writes a string to the underlying output stream.
|
||||||
*
|
*
|
||||||
@ -313,6 +290,36 @@ void JsonEncoder::WriteSeparatorAndIndentStrIfNeeded(bool emitComma) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps any writer of type @c nlohmann::detail::output_adapter_t<char> into a Flusher
|
||||||
|
*
|
||||||
|
* @param w The writer to wrap.
|
||||||
|
*/
|
||||||
|
JsonEncoder::Flusher::Flusher(const nlohmann::detail::output_adapter_t<char>& w)
|
||||||
|
: m_AsyncWriter(dynamic_cast<AsyncJsonWriter*>(w.get()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes the underlying writer if it supports that operation and is safe to do so.
|
||||||
|
*
|
||||||
|
* Safe flushing means that it only performs the flush operation if the @c JsonEncoder has not acquired
|
||||||
|
* any object lock so far. This is to ensure that the stream can safely perform asynchronous operations
|
||||||
|
* without risking undefined behaviour due to coroutines being suspended while the stream is being flushed.
|
||||||
|
*
|
||||||
|
* When the @c yc parameter is provided, it indicates that it's safe to perform asynchronous operations,
|
||||||
|
* and the function will attempt to flush if the writer is an instance of @c AsyncJsonWriter. Otherwise,
|
||||||
|
* this function does nothing.
|
||||||
|
*
|
||||||
|
* @param yc The yield context to use for asynchronous operations.
|
||||||
|
*/
|
||||||
|
void JsonEncoder::Flusher::FlushIfSafe(boost::asio::yield_context* yc) const
|
||||||
|
{
|
||||||
|
if (yc && m_AsyncWriter) {
|
||||||
|
m_AsyncWriter->Flush(*yc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class JsonSax : public nlohmann::json_sax<nlohmann::json>
|
class JsonSax : public nlohmann::json_sax<nlohmann::json>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -83,8 +83,6 @@ private:
|
|||||||
void EncodeNlohmannJson(const nlohmann::json& json) const;
|
void EncodeNlohmannJson(const nlohmann::json& json) const;
|
||||||
void EncodeNumber(double value) const;
|
void EncodeNumber(double value) const;
|
||||||
|
|
||||||
void FlushIfSafe(boost::asio::yield_context* yc) const;
|
|
||||||
|
|
||||||
void Write(const std::string_view& sv) const;
|
void Write(const std::string_view& sv) const;
|
||||||
void BeginContainer(char openChar);
|
void BeginContainer(char openChar);
|
||||||
void EndContainer(char closeChar, bool isContainerEmpty = false);
|
void EndContainer(char closeChar, bool isContainerEmpty = false);
|
||||||
@ -93,7 +91,6 @@ private:
|
|||||||
// The number of spaces to use for indentation in prettified JSON.
|
// The number of spaces to use for indentation in prettified JSON.
|
||||||
static constexpr uint8_t m_IndentSize = 4;
|
static constexpr uint8_t m_IndentSize = 4;
|
||||||
|
|
||||||
const bool m_IsAsyncWriter; // Whether the writer is an instance of AsyncJsonWriter.
|
|
||||||
bool m_Pretty; // Whether to pretty-print the JSON output.
|
bool m_Pretty; // Whether to pretty-print the JSON output.
|
||||||
unsigned m_Indent{0}; // The current indentation level for pretty-printing.
|
unsigned m_Indent{0}; // The current indentation level for pretty-printing.
|
||||||
/**
|
/**
|
||||||
@ -106,6 +103,20 @@ private:
|
|||||||
|
|
||||||
// The output stream adapter for writing JSON data. This can be either a std::ostream or an Asio stream adapter.
|
// The output stream adapter for writing JSON data. This can be either a std::ostream or an Asio stream adapter.
|
||||||
nlohmann::detail::output_adapter_t<char> m_Writer;
|
nlohmann::detail::output_adapter_t<char> m_Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class wraps any @c nlohmann::detail::output_adapter_t<char> and provides a method to flush it as required.
|
||||||
|
* Only @c AsyncJsonWriter supports the flush operation, the class is safe to use with them and the flush method
|
||||||
|
* does nothing for them.
|
||||||
|
*/
|
||||||
|
class Flusher {
|
||||||
|
public:
|
||||||
|
explicit Flusher(const nlohmann::detail::output_adapter_t<char>& w);
|
||||||
|
void FlushIfSafe(boost::asio::yield_context* yc) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AsyncJsonWriter* m_AsyncWriter;
|
||||||
|
} m_Flusher;
|
||||||
};
|
};
|
||||||
|
|
||||||
String JsonEncode(const Value& value, bool prettify = false);
|
String JsonEncode(const Value& value, bool prettify = false);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user