diff --git a/.clangd b/.clangd index c864a33..adf7a53 100644 --- a/.clangd +++ b/.clangd @@ -1,2 +1,2 @@ CompileFlags: - Add: [-std=c++2b, -Wunused-function] + Add: [-std=c++20, -Wunused-function] diff --git a/flake.lock b/flake.lock index bce19fc..9eb57a1 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1717112898, - "narHash": "sha256-7R2ZvOnvd9h8fDd65p0JnB7wXfUvreox3xFdYWd1BnY=", + "lastModified": 1717430266, + "narHash": "sha256-EWy2Qbkl/HUwmO8KDBzgDQf+4rl+fLiPFvp3nUSWcxc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6132b0f6e344ce2fe34fc051b72fb46e34f668e0", + "rev": "d125f0e4d85f1517b639d4a8f848175da46fcd3e", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index c5e9e7a..40ddb97 100644 --- a/flake.nix +++ b/flake.nix @@ -46,7 +46,12 @@ ]; }; - stdenv = pkgs.stdenvAdapters.useMoldLinker pkgs.llvmPackages_18.stdenv; + stdenv = pkgs.llvmPackages_18.stdenv; + + darwinPkgs = nixpkgs.lib.optionals pkgs.stdenv.isDarwin (with pkgs.darwin; [ + apple_sdk.frameworks.CoreFoundation + apple_sdk.frameworks.MediaPlayer + ]); in with pkgs; { packages = rec { @@ -72,7 +77,7 @@ ]); buildInputs = [ - boost185 + coost fmt ]; @@ -105,19 +110,22 @@ ninja pkg-config - boost185 + coost fmt glib libcpr tomlplusplus ] - ++ (lib.optionals pkgs.hostPlatform.isLinux [playerctl]); + ++ (lib.optionals pkgs.hostPlatform.isLinux [playerctl]) + ++ darwinPkgs; - buildInputs = [ - boost185 - libcpr - tomlplusplus - ]; + buildInputs = + [ + coost + libcpr + tomlplusplus + ] + ++ darwinPkgs; name = "C++"; }; diff --git a/include/rfl/bson.hpp b/include/rfl/bson.hpp new file mode 100644 index 0000000..29ca2c5 --- /dev/null +++ b/include/rfl/bson.hpp @@ -0,0 +1,13 @@ +#ifndef RFL_BSON_HPP_ +#define RFL_BSON_HPP_ + +#include "../rfl.hpp" +#include "bson/Parser.hpp" +#include "bson/Reader.hpp" +#include "bson/Writer.hpp" +#include "bson/load.hpp" +#include "bson/read.hpp" +#include "bson/save.hpp" +#include "bson/write.hpp" + +#endif diff --git a/include/rfl/bson/Parser.hpp b/include/rfl/bson/Parser.hpp new file mode 100644 index 0000000..60352b2 --- /dev/null +++ b/include/rfl/bson/Parser.hpp @@ -0,0 +1,50 @@ +#ifndef RFL_BSON_PARSER_HPP_ +#define RFL_BSON_PARSER_HPP_ + +#include + +#include "../parsing/Parser.hpp" +#include "Reader.hpp" +#include "Writer.hpp" + +namespace rfl::parsing { + +/// bson_oid_t needs to be treated as a special case, otherwise it will be read +/// as a struct. +template +requires AreReaderAndWriter +struct Parser { + using InputVarType = typename R::InputVarType; + using OutputVarType = typename W::OutputVarType; + + using ParentType = Parent; + + static Result read(const R& _r, + const InputVarType& _var) noexcept { + return _r.template to_basic_type(_var); + } + + template + static void write(const W& _w, const bson_oid_t& _oid, + const P& _parent) noexcept { + ParentType::add_value(_w, _oid, _parent); + } + + static schema::Type to_schema( + std::map* _definitions) { + static_assert(rfl::always_false_v, + "bson_oid_t cannot be expressed inside a JSON schema."); + return schema::Type{schema::Type::String{}}; + } +}; + +} // namespace rfl::parsing + +namespace rfl::bson { + +template +using Parser = parsing::Parser; + +} // namespace rfl::bson + +#endif diff --git a/include/rfl/bson/Reader.hpp b/include/rfl/bson/Reader.hpp new file mode 100644 index 0000000..dedcff4 --- /dev/null +++ b/include/rfl/bson/Reader.hpp @@ -0,0 +1,217 @@ +#ifndef RFL_BSON_READER_HPP_ +#define RFL_BSON_READER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Box.hpp" +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace bson { + +/// Please refer to https://mongoc.org/libbson/current/api.html +struct Reader { + struct BSONValue { + bson_value_t val_; + }; + + struct BSONInputArray { + BSONValue* val_; + }; + + struct BSONInputObject { + BSONValue* val_; + }; + + struct BSONInputVar { + BSONValue* val_; + }; + + using InputArrayType = BSONInputArray; + using InputObjectType = BSONInputObject; + using InputVarType = BSONInputVar; + + template + static constexpr bool has_custom_constructor = (requires(InputVarType var) { + T::from_bson_obj(var); + }); + + rfl::Result get_field( + const std::string& _name, const InputObjectType& _obj) const noexcept { + bson_t b; + bson_iter_t iter; + const auto doc = _obj.val_->val_.value.v_doc; + if (bson_init_static(&b, doc.data, doc.data_len)) { + if (bson_iter_init(&iter, &b)) { + while (bson_iter_next(&iter)) { + auto key = std::string(bson_iter_key(&iter)); + if (key == _name) { + return to_input_var(&iter); + } + } + } + } + return Error("No field named '" + _name + "' was found."); + } + + bool is_empty(const InputVarType& _var) const noexcept { + return _var.val_->val_.value_type == BSON_TYPE_NULL; + } + + template + rfl::Result to_basic_type(const InputVarType& _var) const noexcept { + const auto btype = _var.val_->val_.value_type; + const auto value = _var.val_->val_.value; + if constexpr (std::is_same, std::string>()) { + switch (btype) { + case BSON_TYPE_UTF8: + return std::string(value.v_utf8.str, value.v_utf8.len); + + case BSON_TYPE_SYMBOL: + return std::string(value.v_symbol.symbol, value.v_symbol.len); + + default: + return rfl::Error( + "Could not cast to string. The type must be UTF8 or symbol."); + } + } else if constexpr (std::is_same, bool>()) { + if (btype != BSON_TYPE_BOOL) { + return rfl::Error("Could not cast to boolean."); + } + return value.v_bool; + } else if constexpr (std::is_floating_point>() || + std::is_integral>()) { + switch (btype) { + case BSON_TYPE_DOUBLE: + return static_cast(value.v_double); + + case BSON_TYPE_INT32: + return static_cast(value.v_int32); + + case BSON_TYPE_INT64: + return static_cast(value.v_int64); + + case BSON_TYPE_DATE_TIME: + return static_cast(value.v_datetime); + + default: + return rfl::Error( + "Could not cast to numeric value. The type must be double, " + "int32, int64 or date_time."); + } + } else if constexpr (std::is_same, bson_oid_t>()) { + if (btype != BSON_TYPE_OID) { + return rfl::Error("Could not cast to OID."); + } + return value.v_oid; + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + } + + rfl::Result to_array( + const InputVarType& _var) const noexcept { + const auto btype = _var.val_->val_.value_type; + if (btype != BSON_TYPE_ARRAY && btype != BSON_TYPE_DOCUMENT) { + return Error("Could not cast to an array."); + } + return InputArrayType{_var.val_}; + } + + template + std::optional read_array(const ArrayReader& _array_reader, + const InputArrayType& _arr) const noexcept { + bson_t b; + bson_iter_t iter; + const auto doc = _arr.val_->val_.value.v_doc; + if (bson_init_static(&b, doc.data, doc.data_len)) { + if (bson_iter_init(&iter, &b)) { + while (bson_iter_next(&iter)) { + const auto err = _array_reader.read(to_input_var(&iter)); + if (err) { + return err; + } + } + } + } + return std::nullopt; + } + + template + std::optional read_object(const ObjectReader& _object_reader, + const InputObjectType& _obj) const noexcept { + bson_t b; + bson_iter_t iter; + const auto doc = _obj.val_->val_.value.v_doc; + if (bson_init_static(&b, doc.data, doc.data_len)) { + if (bson_iter_init(&iter, &b)) { + while (bson_iter_next(&iter)) { + const char* k = bson_iter_key(&iter); + _object_reader.read(std::string_view(k), to_input_var(&iter)); + } + } + } + return std::nullopt; + } + + rfl::Result to_object( + const InputVarType& _var) const noexcept { + const auto btype = _var.val_->val_.value_type; + if (btype != BSON_TYPE_DOCUMENT) { + return Error("Could not cast to a document."); + } + return InputObjectType{_var.val_}; + } + + template + rfl::Result use_custom_constructor( + const InputVarType& _var) const noexcept { + try { + return T::from_bson_obj(_var); + } catch (std::exception& e) { + return rfl::Error(e.what()); + } + } + + private: + struct BSONValues { + std::vector> vec_; + ~BSONValues() { + for (auto& v : vec_) { + bson_value_destroy(&(v->val_)); + } + } + }; + + private: + InputVarType to_input_var(bson_iter_t* _iter) const noexcept { + values_->vec_.emplace_back(rfl::Box::make()); + auto* last_value = values_->vec_.back().get(); + bson_value_copy(bson_iter_value(_iter), &last_value->val_); + return InputVarType{last_value}; + } + + private: + /// Contains the values inside the object. + rfl::Ref values_; +}; + +} // namespace bson +} // namespace rfl + +#endif // JSON_PARSER_HPP_ diff --git a/include/rfl/bson/Writer.hpp b/include/rfl/bson/Writer.hpp new file mode 100644 index 0000000..aac627a --- /dev/null +++ b/include/rfl/bson/Writer.hpp @@ -0,0 +1,227 @@ +#ifndef RFL_BSON_WRITER_HPP_ +#define RFL_BSON_WRITER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Box.hpp" +#include "../Ref.hpp" +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace bson { + +/// Please refer to https://mongoc.org/libbson/current/api.html +class Writer { + struct BSONType { + bson_t val_; + }; + + struct IsArray { + bson_array_builder_t* ptr_; + }; + + struct IsObject { + bson_t* ptr_; + }; + + struct IsRoot {}; + + using ParentType = std::variant; + + public: + struct BSONOutputArray { + BSONOutputArray(bson_array_builder_t* _val, ParentType _parent) + : parent_(_parent), val_(_val) {} + ParentType parent_; + bson_array_builder_t* val_; + }; + + struct BSONOutputObject { + BSONOutputObject(bson_t* _val, ParentType _parent) + : parent_(_parent), val_(_val) {} + ParentType parent_; + bson_t* val_; + }; + + struct BSONOutputVar {}; + + using OutputArrayType = BSONOutputArray; + using OutputObjectType = BSONOutputObject; + using OutputVarType = BSONOutputVar; + + Writer(bson_t* _doc) : doc_(_doc) {} + + ~Writer() = default; + + OutputArrayType array_as_root(const size_t _size) const noexcept { + bson_array_builder_t* val = bson_array_builder_new(); + return OutputArrayType(val, IsRoot{}); + } + + OutputObjectType object_as_root(const size_t _size) const noexcept { + return OutputObjectType(doc_, IsRoot{}); + } + + OutputVarType null_as_root() const noexcept { + // Appears to be unsupported by the BSON C API. + return OutputVarType{}; + } + + template + OutputVarType value_as_root(const T& _var) const noexcept { + static_assert(rfl::always_false_v, + "BSON only allows arrays or objects as its root."); + return OutputVarType{}; + } + + OutputArrayType add_array_to_array(const size_t _size, + OutputArrayType* _parent) const noexcept { + bson_array_builder_t* val; + bson_array_builder_append_array_builder_begin(_parent->val_, &val); + return OutputArrayType(val, IsArray{_parent->val_}); + } + + OutputArrayType add_array_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + bson_array_builder_t* val; + bson_append_array_builder_begin(_parent->val_, _name.data(), + static_cast(_name.size()), &val); + return OutputArrayType(val, IsObject{_parent->val_}); + } + + OutputObjectType add_object_to_array( + const size_t _size, OutputArrayType* _parent) const noexcept { + subdocs_->emplace_back(rfl::Box()); + bson_array_builder_append_document_begin(_parent->val_, + &(subdocs_->back()->val_)); + return OutputObjectType(&subdocs_->back()->val_, IsArray{_parent->val_}); + } + + OutputObjectType add_object_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + subdocs_->emplace_back(rfl::Box()); + bson_append_document_begin(_parent->val_, _name.data(), + static_cast(_name.size()), + &(subdocs_->back()->val_)); + return OutputObjectType(&subdocs_->back()->val_, IsObject{_parent->val_}); + } + + template + OutputVarType add_value_to_array(const T& _var, + OutputArrayType* _parent) const noexcept { + if constexpr (std::is_same, std::string>()) { + bson_array_builder_append_utf8(_parent->val_, _var.c_str(), + static_cast(_var.size())); + } else if constexpr (std::is_same, bool>()) { + bson_array_builder_append_bool(_parent->val_, _var); + } else if constexpr (std::is_floating_point>()) { + bson_array_builder_append_double(_parent->val_, + static_cast(_var)); + } else if constexpr (std::is_integral>()) { + bson_array_builder_append_int64(_parent->val_, + static_cast(_var)); + } else if constexpr (std::is_same, bson_oid_t>()) { + bson_array_builder_append_oid(_parent->val_, &_var); + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + return OutputVarType{}; + } + + template + OutputVarType add_value_to_object(const std::string_view& _name, + const T& _var, + OutputObjectType* _parent) const noexcept { + if constexpr (std::is_same, std::string>()) { + bson_append_utf8(_parent->val_, _name.data(), + static_cast(_name.size()), _var.c_str(), + static_cast(_var.size())); + } else if constexpr (std::is_same, bool>()) { + bson_append_bool(_parent->val_, _name.data(), + static_cast(_name.size()), _var); + } else if constexpr (std::is_floating_point>()) { + bson_append_double(_parent->val_, _name.data(), + static_cast(_name.size()), + static_cast(_var)); + } else if constexpr (std::is_integral>()) { + bson_append_int64(_parent->val_, _name.data(), + static_cast(_name.size()), + static_cast(_var)); + } else if constexpr (std::is_same, bson_oid_t>()) { + bson_append_oid(_parent->val_, _name.data(), + static_cast(_name.size()), &_var); + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + return OutputVarType{}; + } + + OutputVarType add_null_to_array(OutputArrayType* _parent) const noexcept { + bson_array_builder_append_null(_parent->val_); + return OutputVarType{}; + } + + OutputVarType add_null_to_object(const std::string_view& _name, + OutputObjectType* _parent) const noexcept { + bson_append_null(_parent->val_, _name.data(), + static_cast(_name.size())); + return OutputVarType{}; + } + + void end_array(OutputArrayType* _arr) const noexcept { + const auto handle = [&](const auto _parent) { + using Type = std::remove_cvref_t; + if constexpr (std::is_same()) { + bson_array_builder_append_array_builder_end(_parent.ptr_, _arr->val_); + } else if constexpr (std::is_same()) { + bson_append_array_builder_end(_parent.ptr_, _arr->val_); + } else if constexpr (std::is_same()) { + bson_array_builder_build(_arr->val_, doc_); + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + }; + std::visit(handle, _arr->parent_); + } + + void end_object(OutputObjectType* _obj) const noexcept { + const auto handle = [&](const auto _parent) { + using Type = std::remove_cvref_t; + if constexpr (std::is_same()) { + bson_array_builder_append_document_end(_parent.ptr_, _obj->val_); + } else if constexpr (std::is_same()) { + bson_append_document_end(_parent.ptr_, _obj->val_); + } else if constexpr (std::is_same()) { + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + }; + std::visit(handle, _obj->parent_); + } + + private: + /// Pointer to the main document. In BSON, documents are what are usually + /// called objects. + bson_t* const doc_; + + /// Contain all of the subdocuments. + const rfl::Ref>> subdocs_; +}; + +} // namespace bson +} // namespace rfl + +#endif // BSON_PARSER_HPP_ diff --git a/include/rfl/bson/load.hpp b/include/rfl/bson/load.hpp new file mode 100644 index 0000000..05cd9b7 --- /dev/null +++ b/include/rfl/bson/load.hpp @@ -0,0 +1,22 @@ +#ifndef RFL_BSON_LOAD_HPP_ +#define RFL_BSON_LOAD_HPP_ + +#include "../Result.hpp" +#include "../io/load_bytes.hpp" +#include "read.hpp" + +namespace rfl { +namespace bson { + +template +Result load(const std::string& _fname) { + const auto read_bytes = [](const auto& _bytes) { + return read(_bytes); + }; + return rfl::io::load_bytes(_fname).and_then(read_bytes); +} + +} // namespace bson +} // namespace rfl + +#endif diff --git a/include/rfl/bson/read.hpp b/include/rfl/bson/read.hpp new file mode 100644 index 0000000..2ee5bc3 --- /dev/null +++ b/include/rfl/bson/read.hpp @@ -0,0 +1,61 @@ +#ifndef RFL_BSON_READ_HPP_ +#define RFL_BSON_READ_HPP_ + +#include + +#include +#include + +#include "../Processors.hpp" +#include "../internal/wrap_in_rfl_array_t.hpp" +#include "Parser.hpp" +#include "Reader.hpp" + +namespace rfl { +namespace bson { + +using InputObjectType = typename Reader::InputObjectType; +using InputVarType = typename Reader::InputVarType; + +/// Parses an object from a BSON var. +template +Result> read(const InputVarType& _obj) { + const auto r = Reader(); + return Parser>::read(r, _obj); +} + +/// Parses an BSON object using reflection. +template +auto read(const uint8_t* _bytes, const size_t _size) { + Reader::BSONValue value; + value.val_.value.v_doc.data_len = static_cast(_size); + value.val_.value.v_doc.data = const_cast(_bytes); + value.val_.value_type = BSON_TYPE_DOCUMENT; + auto doc = InputVarType{&value}; + return read(doc); +} + +/// Parses an BSON object using reflection. +template +auto read(const char* _bytes, const size_t _size) { + return read(reinterpret_cast(_bytes), _size); +} + +/// Parses an object from BSON using reflection. +template +auto read(const std::vector& _bytes) { + return read(_bytes.data(), _bytes.size()); +} + +/// Parses an object from a stream. +template +auto read(std::istream& _stream) { + std::istreambuf_iterator begin(_stream), end; + auto bytes = std::vector(begin, end); + return read(bytes.data(), bytes.size()); +} + +} // namespace bson +} // namespace rfl + +#endif diff --git a/include/rfl/bson/save.hpp b/include/rfl/bson/save.hpp new file mode 100644 index 0000000..3ebbeda --- /dev/null +++ b/include/rfl/bson/save.hpp @@ -0,0 +1,26 @@ +#ifndef RFL_BSON_SAVE_HPP_ +#define RFL_BSON_SAVE_HPP_ + +#include +#include +#include + +#include "../Result.hpp" +#include "../io/save_bytes.hpp" +#include "write.hpp" + +namespace rfl { +namespace bson { + +template +Result save(const std::string& _fname, const auto& _obj) { + const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { + return write(_obj, _stream); + }; + return rfl::io::save_bytes(_fname, _obj, write_func); +} + +} // namespace bson +} // namespace rfl + +#endif diff --git a/include/rfl/bson/write.hpp b/include/rfl/bson/write.hpp new file mode 100644 index 0000000..a22e750 --- /dev/null +++ b/include/rfl/bson/write.hpp @@ -0,0 +1,61 @@ +#ifndef RFL_BSON_WRITE_HPP_ +#define RFL_BSON_WRITE_HPP_ + +#include + +#include +#include +#include +#include + +#include "../Processors.hpp" +#include "../parsing/Parent.hpp" +#include "Parser.hpp" + +namespace rfl { +namespace bson { + +/// Returns BSON bytes. Careful: It is the responsibility of the caller to call +/// bson_free on the returned pointer. +template +std::pair to_buffer(const auto& _obj) noexcept { + using T = std::remove_cvref_t; + using ParentType = parsing::Parent; + bson_t* doc = nullptr; + uint8_t* buf = nullptr; + size_t buflen = 0; + bson_writer_t* bson_writer = + bson_writer_new(&buf, &buflen, 0, bson_realloc_ctx, NULL); + bson_writer_begin(bson_writer, &doc); + const auto rfl_writer = Writer(doc); + Parser>::write(rfl_writer, _obj, + typename ParentType::Root{}); + bson_writer_end(bson_writer); + const auto len = bson_writer_get_length(bson_writer); + bson_writer_destroy(bson_writer); + return std::make_pair(buf, len); +} + +/// Returns BSON bytes. +template +std::vector write(const auto& _obj) noexcept { + auto [buf, len] = to_buffer(_obj); + const auto result = std::vector(reinterpret_cast(buf), + reinterpret_cast(buf) + len); + bson_free(buf); + return result; +} + +/// Writes a BSON into an ostream. +template +std::ostream& write(const auto& _obj, std::ostream& _stream) noexcept { + auto [buf, len] = to_buffer(_obj); + _stream.write(reinterpret_cast(buf), len); + bson_free(buf); + return _stream; +} + +} // namespace bson +} // namespace rfl + +#endif // BSON_PARSER_HPP_ diff --git a/include/rfl/cbor.hpp b/include/rfl/cbor.hpp new file mode 100644 index 0000000..e539617 --- /dev/null +++ b/include/rfl/cbor.hpp @@ -0,0 +1,13 @@ +#ifndef RFL_CBOR_HPP_ +#define RFL_CBOR_HPP_ + +#include "../rfl.hpp" +#include "cbor/Parser.hpp" +#include "cbor/Reader.hpp" +#include "cbor/Writer.hpp" +#include "cbor/load.hpp" +#include "cbor/read.hpp" +#include "cbor/save.hpp" +#include "cbor/write.hpp" + +#endif diff --git a/include/rfl/cbor/Parser.hpp b/include/rfl/cbor/Parser.hpp new file mode 100644 index 0000000..811978d --- /dev/null +++ b/include/rfl/cbor/Parser.hpp @@ -0,0 +1,45 @@ +#ifndef RFL_CBOR_PARSER_HPP_ +#define RFL_CBOR_PARSER_HPP_ + +#include "../parsing/Parser.hpp" +#include "Reader.hpp" +#include "Writer.hpp" + +namespace rfl { +namespace parsing { + +/// CBOR requires us to explicitly set the number of fields in advance. Because +/// of that, we require all of the fields and then set them to nullptr, if +/// necessary. +template +requires AreReaderAndWriter> +struct Parser, + ProcessorsType> + : public NamedTupleParser { +}; + +template +requires AreReaderAndWriter> +struct Parser, ProcessorsType> + : public TupleParser { +}; + +} // namespace parsing +} // namespace rfl + +namespace rfl { +namespace cbor { + +template +using Parser = parsing::Parser; + +} +} // namespace rfl + +#endif diff --git a/include/rfl/cbor/Reader.hpp b/include/rfl/cbor/Reader.hpp new file mode 100644 index 0000000..42b1aee --- /dev/null +++ b/include/rfl/cbor/Reader.hpp @@ -0,0 +1,259 @@ +#ifndef RFL_CBOR_READER_HPP_ +#define RFL_CBOR_READER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Box.hpp" +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace cbor { + +/// Please refer to https://intel.github.io/tinycbor/current/index.html +struct Reader { + struct CBORInputArray { + CborValue* val_; + }; + + struct CBORInputObject { + CborValue* val_; + }; + + struct CBORInputVar { + CborValue* val_; + }; + + using InputArrayType = CBORInputArray; + using InputObjectType = CBORInputObject; + using InputVarType = CBORInputVar; + + template + static constexpr bool has_custom_constructor = (requires(InputVarType var) { + T::from_cbor_obj(var); + }); + + rfl::Result get_field( + const std::string& _name, const InputObjectType& _obj) const noexcept { + CborValue val; + auto buffer = std::vector(); + auto err = cbor_value_enter_container(_obj.val_, &val); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + size_t length = 0; + err = cbor_value_get_map_length(_obj.val_, &length); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + for (size_t i = 0; i < length; ++i) { + if (!cbor_value_is_text_string(&val)) { + return Error("Expected the key to be a string value."); + } + err = get_string(&val, &buffer); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + err = cbor_value_advance(&val); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + if (_name == buffer.data()) { + return to_input_var(&val); + } + err = cbor_value_advance(&val); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + } + return Error("No field named '" + _name + "' was found."); + } + + bool is_empty(const InputVarType& _var) const noexcept { + return cbor_value_is_null(_var.val_); + } + + template + rfl::Result to_basic_type(const InputVarType& _var) const noexcept { + if constexpr (std::is_same, std::string>()) { + if (!cbor_value_is_text_string(_var.val_)) { + return Error("Could not cast to string."); + } + std::vector buffer; + const auto err = get_string(_var.val_, &buffer); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + return std::string(buffer.data()); + } else if constexpr (std::is_same, bool>()) { + if (!cbor_value_is_boolean(_var.val_)) { + return rfl::Error("Could not cast to boolean."); + } + bool result = false; + const auto err = cbor_value_get_boolean(_var.val_, &result); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + return result; + } else if constexpr (std::is_floating_point>() || + std::is_integral>()) { + if (cbor_value_is_integer(_var.val_)) { + std::int64_t result = 0; + const auto err = cbor_value_get_int64(_var.val_, &result); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + return static_cast(result); + } else if (cbor_value_is_float(_var.val_)) { + float result = 0.0; + const auto err = cbor_value_get_float(_var.val_, &result); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + return static_cast(result); + } else if (cbor_value_is_double(_var.val_)) { + double result = 0.0; + const auto err = cbor_value_get_double(_var.val_, &result); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + return static_cast(result); + } + return rfl::Error( + "Could not cast to numeric value. The type must be integral, float " + "or double."); + + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + } + + rfl::Result to_array( + const InputVarType& _var) const noexcept { + if (!cbor_value_is_array(_var.val_)) { + return Error("Could not cast to an array."); + } + return InputArrayType{_var.val_}; + } + + rfl::Result to_object( + const InputVarType& _var) const noexcept { + if (!cbor_value_is_map(_var.val_)) { + return Error("Could not cast to an object."); + } + return InputObjectType{_var.val_}; + } + + template + std::optional read_array(const ArrayReader& _array_reader, + const InputArrayType& _arr) const noexcept { + CborValue val; + auto buffer = std::vector(); + auto err = cbor_value_enter_container(_arr.val_, &val); + if (err != CborNoError && err != CborErrorOutOfMemory) { + return Error(cbor_error_string(err)); + } + size_t length = 0; + err = cbor_value_get_array_length(_arr.val_, &length); + if (err != CborNoError && err != CborErrorOutOfMemory) { + return Error(cbor_error_string(err)); + } + for (size_t i = 0; i < length; ++i) { + const auto err2 = _array_reader.read(to_input_var(&val)); + if (err2) { + return err2; + } + err = cbor_value_advance(&val); + if (err != CborNoError && err != CborErrorOutOfMemory) { + return Error(cbor_error_string(err)); + } + } + return std::nullopt; + } + + template + std::optional read_object(const ObjectReader& _object_reader, + const InputObjectType& _obj) const noexcept { + size_t length = 0; + auto err = cbor_value_get_map_length(_obj.val_, &length); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + + CborValue val; + err = cbor_value_enter_container(_obj.val_, &val); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + + auto buffer = std::vector(); + + for (size_t i = 0; i < length; ++i) { + err = get_string(&val, &buffer); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + err = cbor_value_advance(&val); + if (err != CborNoError) { + return Error(cbor_error_string(err)); + } + const auto name = std::string_view(buffer.data(), buffer.size() - 1); + _object_reader.read(name, InputVarType{&val}); + cbor_value_advance(&val); + } + + return std::nullopt; + } + + template + rfl::Result use_custom_constructor( + const InputVarType& _var) const noexcept { + try { + return T::from_cbor_obj(_var); + } catch (std::exception& e) { + return rfl::Error(e.what()); + } + } + + private: + CborError get_string(const CborValue* _ptr, + std::vector* _buffer) const noexcept { + size_t length = 0; + auto err = cbor_value_get_string_length(_ptr, &length); + if (err != CborNoError && err != CborErrorOutOfMemory) { + return err; + } + _buffer->resize(length + 1); + (*_buffer)[length] = '\0'; + return cbor_value_copy_text_string(_ptr, _buffer->data(), &length, NULL); + } + + InputVarType to_input_var(CborValue* _ptr) const noexcept { + values_->emplace_back(rfl::Box::make(*_ptr)); + auto* last_value = values_->back().get(); + return InputVarType{last_value}; + } + + private: + /// Contains the values inside the object. + rfl::Box>> values_; +}; + +} // namespace cbor +} // namespace rfl + +#endif // JSON_PARSER_HPP_ diff --git a/include/rfl/cbor/Writer.hpp b/include/rfl/cbor/Writer.hpp new file mode 100644 index 0000000..d2cb7d1 --- /dev/null +++ b/include/rfl/cbor/Writer.hpp @@ -0,0 +1,164 @@ +#ifndef RFL_CBOR_WRITER_HPP_ +#define RFL_CBOR_WRITER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Box.hpp" +#include "../Ref.hpp" +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace cbor { + +class Writer { + public: + struct CBOROutputArray { + CborEncoder* encoder_; + CborEncoder* parent_; + }; + + struct CBOROutputObject { + CborEncoder* encoder_; + CborEncoder* parent_; + }; + + struct CBOROutputVar {}; + + using OutputArrayType = CBOROutputArray; + using OutputObjectType = CBOROutputObject; + using OutputVarType = CBOROutputVar; + + Writer(CborEncoder* _encoder) : encoder_(_encoder) {} + + ~Writer() = default; + + OutputArrayType array_as_root(const size_t _size) const noexcept { + return new_array(_size, encoder_); + } + + OutputObjectType object_as_root(const size_t _size) const noexcept { + return new_object(_size, encoder_); + } + + OutputVarType null_as_root() const noexcept { + cbor_encode_null(encoder_); + return OutputVarType{}; + } + + template + OutputVarType value_as_root(const T& _var) const noexcept { + return new_value(_var, encoder_); + } + + OutputArrayType add_array_to_array(const size_t _size, + OutputArrayType* _parent) const noexcept { + return new_array(_size, _parent->encoder_); + } + + OutputArrayType add_array_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + cbor_encode_text_string(_parent->encoder_, _name.data(), _name.size()); + return new_array(_size, _parent->encoder_); + } + + OutputObjectType add_object_to_array( + const size_t _size, OutputArrayType* _parent) const noexcept { + return new_object(_size, _parent->encoder_); + } + + OutputObjectType add_object_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + cbor_encode_text_string(_parent->encoder_, _name.data(), _name.size()); + return new_object(_size, _parent->encoder_); + } + + template + OutputVarType add_value_to_array(const T& _var, + OutputArrayType* _parent) const noexcept { + return new_value(_var, _parent->encoder_); + } + + template + OutputVarType add_value_to_object(const std::string_view& _name, + const T& _var, + OutputObjectType* _parent) const noexcept { + cbor_encode_text_string(_parent->encoder_, _name.data(), _name.size()); + return new_value(_var, _parent->encoder_); + } + + OutputVarType add_null_to_array(OutputArrayType* _parent) const noexcept { + cbor_encode_null(_parent->encoder_); + return OutputVarType{}; + } + + OutputVarType add_null_to_object(const std::string_view& _name, + OutputObjectType* _parent) const noexcept { + cbor_encode_text_string(_parent->encoder_, _name.data(), _name.size()); + cbor_encode_null(_parent->encoder_); + return OutputVarType{}; + } + + void end_array(OutputArrayType* _arr) const noexcept { + cbor_encoder_close_container(_arr->parent_, _arr->encoder_); + } + + void end_object(OutputObjectType* _obj) const noexcept { + cbor_encoder_close_container(_obj->parent_, _obj->encoder_); + } + + private: + OutputArrayType new_array(const size_t _size, + CborEncoder* _parent) const noexcept { + subencoders_->emplace_back(rfl::Box::make()); + cbor_encoder_create_array(_parent, subencoders_->back().get(), _size); + return OutputArrayType{subencoders_->back().get(), _parent}; + } + + OutputObjectType new_object(const size_t _size, + CborEncoder* _parent) const noexcept { + subencoders_->emplace_back(rfl::Box::make()); + cbor_encoder_create_map(_parent, subencoders_->back().get(), _size); + return OutputObjectType{subencoders_->back().get(), _parent}; + } + + template + OutputVarType new_value(const T& _var, CborEncoder* _parent) const noexcept { + if constexpr (std::is_same, std::string>()) { + cbor_encode_text_string(_parent, _var.c_str(), _var.size()); + } else if constexpr (std::is_same, bool>()) { + cbor_encode_boolean(_parent, _var); + } else if constexpr (std::is_floating_point>()) { + cbor_encode_double(_parent, static_cast(_var)); + } else if constexpr (std::is_integral>()) { + cbor_encode_int(_parent, static_cast(_var)); + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + return OutputVarType{}; + } + + private: + /// The underlying TinyCBOR encoder. + CborEncoder* const encoder_; + + /// Contain all of the subobjects and subarrays. + const rfl::Box>> subencoders_; +}; + +} // namespace cbor +} // namespace rfl + +#endif // CBOR_PARSER_HPP_ diff --git a/include/rfl/cbor/load.hpp b/include/rfl/cbor/load.hpp new file mode 100644 index 0000000..574ea00 --- /dev/null +++ b/include/rfl/cbor/load.hpp @@ -0,0 +1,23 @@ +#ifndef RFL_CBOR_LOAD_HPP_ +#define RFL_CBOR_LOAD_HPP_ + +#include "../Processors.hpp" +#include "../Result.hpp" +#include "../io/load_bytes.hpp" +#include "read.hpp" + +namespace rfl { +namespace cbor { + +template +Result load(const std::string& _fname) { + const auto read_bytes = [](const auto& _bytes) { + return read(_bytes); + }; + return rfl::io::load_bytes(_fname).and_then(read_bytes); +} + +} // namespace cbor +} // namespace rfl + +#endif diff --git a/include/rfl/cbor/read.hpp b/include/rfl/cbor/read.hpp new file mode 100644 index 0000000..32abb59 --- /dev/null +++ b/include/rfl/cbor/read.hpp @@ -0,0 +1,57 @@ +#ifndef RFL_CBOR_READ_HPP_ +#define RFL_CBOR_READ_HPP_ + +#include + +#include +#include + +#include "../Processors.hpp" +#include "../internal/wrap_in_rfl_array_t.hpp" +#include "Parser.hpp" +#include "Reader.hpp" + +namespace rfl { +namespace cbor { + +using InputObjectType = typename Reader::InputObjectType; +using InputVarType = typename Reader::InputVarType; + +/// Parses an object from a CBOR var. +template +auto read(const InputVarType& _obj) { + const auto r = Reader(); + return Parser>::read(r, _obj); +} + +/// Parses an object from CBOR using reflection. +template +Result> read(const char* _bytes, + const size_t _size) { + CborParser parser; + CborValue value; + cbor_parser_init(reinterpret_cast(_bytes), _size, 0, &parser, + &value); + auto doc = InputVarType{&value}; + auto result = read(doc); + return result; +} + +/// Parses an object from CBOR using reflection. +template +auto read(const std::vector& _bytes) { + return read(_bytes.data(), _bytes.size()); +} + +/// Parses an object from a stream. +template +auto read(std::istream& _stream) { + std::istreambuf_iterator begin(_stream), end; + auto bytes = std::vector(begin, end); + return read(bytes.data(), bytes.size()); +} + +} // namespace cbor +} // namespace rfl + +#endif diff --git a/include/rfl/cbor/save.hpp b/include/rfl/cbor/save.hpp new file mode 100644 index 0000000..59343e0 --- /dev/null +++ b/include/rfl/cbor/save.hpp @@ -0,0 +1,26 @@ +#ifndef RFL_CBOR_SAVE_HPP_ +#define RFL_CBOR_SAVE_HPP_ + +#include +#include +#include + +#include "../Result.hpp" +#include "../io/save_bytes.hpp" +#include "write.hpp" + +namespace rfl { +namespace cbor { + +template +Result save(const std::string& _fname, const auto& _obj) { + const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { + return write(_obj, _stream); + }; + return rfl::io::save_bytes(_fname, _obj, write_func); +} + +} // namespace cbor +} // namespace rfl + +#endif diff --git a/include/rfl/cbor/write.hpp b/include/rfl/cbor/write.hpp new file mode 100644 index 0000000..867f150 --- /dev/null +++ b/include/rfl/cbor/write.hpp @@ -0,0 +1,59 @@ +#ifndef RFL_CBOR_WRITE_HPP_ +#define RFL_CBOR_WRITE_HPP_ + +#include + +#include +#include +#include +#include +#include + +#include "../parsing/Parent.hpp" +#include "Parser.hpp" + +namespace rfl { +namespace cbor { + +template +void write_into_buffer(const auto& _obj, CborEncoder* _encoder, + std::vector* _buffer) noexcept { + using T = std::remove_cvref_t; + using ParentType = parsing::Parent; + cbor_encoder_init(_encoder, reinterpret_cast(_buffer->data()), + _buffer->size(), 0); + const auto writer = Writer(_encoder); + Parser>::write(writer, _obj, + typename ParentType::Root{}); +} + +/// Returns CBOR bytes. +template +std::vector write(const auto& _obj) noexcept { + std::vector buffer(4096); + CborEncoder encoder; + write_into_buffer(_obj, &encoder, &buffer); + const auto total_bytes_needed = + buffer.size() + cbor_encoder_get_extra_bytes_needed(&encoder); + if (total_bytes_needed != buffer.size()) { + buffer.resize(total_bytes_needed); + write_into_buffer(_obj, &encoder, &buffer); + } + const auto length = cbor_encoder_get_buffer_size( + &encoder, reinterpret_cast(buffer.data())); + buffer.resize(length); + return buffer; +} + +/// Writes a CBOR into an ostream. +template +std::ostream& write(const auto& _obj, std::ostream& _stream) noexcept { + auto buffer = write(_obj); + _stream.write(buffer.data(), buffer.size()); + return _stream; +} + +} // namespace cbor +} // namespace rfl + +#endif diff --git a/include/rfl/flexbuf.hpp b/include/rfl/flexbuf.hpp new file mode 100644 index 0000000..b1e7325 --- /dev/null +++ b/include/rfl/flexbuf.hpp @@ -0,0 +1,13 @@ +#ifndef RFL_FLEXBUF_HPP_ +#define RFL_FLEXBUF_HPP_ + +#include "../rfl.hpp" +#include "flexbuf/Parser.hpp" +#include "flexbuf/Reader.hpp" +#include "flexbuf/Writer.hpp" +#include "flexbuf/load.hpp" +#include "flexbuf/read.hpp" +#include "flexbuf/save.hpp" +#include "flexbuf/write.hpp" + +#endif diff --git a/include/rfl/flexbuf/Parser.hpp b/include/rfl/flexbuf/Parser.hpp new file mode 100644 index 0000000..dd7020f --- /dev/null +++ b/include/rfl/flexbuf/Parser.hpp @@ -0,0 +1,17 @@ +#ifndef FLEXBUF_PARSER_HPP_ +#define FLEXBUF_PARSER_HPP_ + +#include "../parsing/Parser.hpp" +#include "Reader.hpp" +#include "Writer.hpp" + +namespace rfl { +namespace flexbuf { + +template +using Parser = parsing::Parser; + +} +} // namespace rfl + +#endif diff --git a/include/rfl/flexbuf/Reader.hpp b/include/rfl/flexbuf/Reader.hpp new file mode 100644 index 0000000..16a2de0 --- /dev/null +++ b/include/rfl/flexbuf/Reader.hpp @@ -0,0 +1,145 @@ +#ifndef FLEXBUF_READER_HPP_ +#define FLEXBUF_READER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace flexbuf { + +struct Reader { + using InputArrayType = flexbuffers::Vector; + using InputObjectType = flexbuffers::Map; + using InputVarType = flexbuffers::Reference; + + template + struct has_from_flexbuf : std::false_type {}; + + template + struct has_from_flexbuf< + T, std::enable_if_t::value>> + : std::true_type {}; + + template + struct has_from_flexbuf< + T, std::enable_if_t, decltype(T::from_flexbuf), InputVarType>::value>> + : std::true_type {}; + + template + static constexpr bool has_custom_constructor = has_from_flexbuf::value; + + rfl::Result get_field( + const std::string& _name, const InputObjectType& _obj) const noexcept { + const auto keys = _obj.Keys(); + for (size_t i = 0; i < keys.size(); ++i) { + if (_name == keys[i].AsString().c_str()) { + return _obj.Values()[i]; + } + } + return rfl::Error("Map does not contain any element called '" + _name + + "'."); + } + + bool is_empty(const InputVarType& _var) const noexcept { + return _var.IsNull(); + } + + template + rfl::Result to_basic_type(const InputVarType& _var) const noexcept { + if constexpr (std::is_same, std::string>()) { + if (!_var.IsString()) { + return rfl::Error("Could not cast to string."); + } + return std::string(_var.AsString().c_str()); + } else if constexpr (std::is_same, bool>()) { + if (!_var.IsBool()) { + return rfl::Error("Could not cast to boolean."); + } + return _var.AsBool(); + } else if constexpr (std::is_floating_point>()) { + if (!_var.IsNumeric()) { + return rfl::Error("Could not cast to double."); + } + return static_cast(_var.AsDouble()); + } else if constexpr (std::is_integral>()) { + if (!_var.IsNumeric()) { + return rfl::Error("Could not cast to int."); + } + return static_cast(_var.AsInt64()); + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + } + + template + std::optional read_array(const ArrayReader& _array_reader, + const InputArrayType& _arr) const noexcept { + const auto size = _arr.size(); + for (size_t i = 0; i < size; ++i) { + const auto err = _array_reader.read(InputVarType(_arr[i])); + if (err) { + return err; + } + } + return std::nullopt; + } + + template + std::optional read_object(const ObjectReader& _object_reader, + const InputObjectType& _obj) const noexcept { + const auto keys = _obj.Keys(); + const auto values = _obj.Values(); + const auto num_values = std::min(keys.size(), values.size()); + + for (size_t i = 0; i < num_values; ++i) { + _object_reader.read(std::string_view(keys[i].AsString().c_str()), + values[i]); + } + + return std::nullopt; + } + + rfl::Result to_array( + const InputVarType& _var) const noexcept { + if (!_var.IsVector()) { + return rfl::Error("Could not cast to Vector."); + } + return _var.AsVector(); + } + + rfl::Result to_object( + const InputVarType& _var) const noexcept { + if (!_var.IsMap()) { + return rfl::Error("Could not cast to Map!"); + } + return _var.AsMap(); + } + + template + rfl::Result use_custom_constructor( + const InputVarType& _var) const noexcept { + try { + return T::from_flexbuf(_var); + } catch (std::exception& e) { + return rfl::Error(e.what()); + } + } +}; + +} // namespace flexbuf +} // namespace rfl + +#endif diff --git a/include/rfl/flexbuf/Writer.hpp b/include/rfl/flexbuf/Writer.hpp new file mode 100644 index 0000000..3659a6e --- /dev/null +++ b/include/rfl/flexbuf/Writer.hpp @@ -0,0 +1,176 @@ +#ifndef FLEXBUF_WRITER_HPP_ +#define FLEXBUF_WRITER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Ref.hpp" +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace flexbuf { + +struct Writer { + struct OutputArray { + size_t start_; + }; + + struct OutputObject { + size_t start_; + }; + + struct OutputVar {}; + + using OutputArrayType = OutputArray; + using OutputObjectType = OutputObject; + using OutputVarType = OutputVar; + + Writer(const Ref& _fbb) : fbb_(_fbb) {} + + ~Writer() = default; + + OutputArrayType array_as_root(const size_t _size) const noexcept { + return new_array(); + } + + OutputObjectType object_as_root(const size_t _size) const noexcept { + return new_object(); + } + + OutputVarType null_as_root() const noexcept { + fbb_->Null(); + return OutputVarType{}; + } + + template + OutputVarType value_as_root(const T& _var) const noexcept { + return insert_value(_var); + } + + OutputArrayType add_array_to_array(const size_t _size, + OutputArrayType* _parent) const noexcept { + return new_array(); + } + + OutputArrayType add_array_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + return new_array(_name); + } + + OutputObjectType add_object_to_array( + const size_t _size, OutputArrayType* _parent) const noexcept { + return new_object(); + } + + OutputObjectType add_object_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + return new_object(_name); + } + + template + OutputVarType add_value_to_array(const T& _var, + OutputArrayType* _parent) const noexcept { + return insert_value(_var); + } + + template + OutputVarType add_value_to_object(const std::string_view& _name, + const T& _var, + OutputObjectType* _parent) const noexcept { + return insert_value(_name, _var); + } + + OutputVarType add_null_to_array(OutputArrayType* _parent) const noexcept { + fbb_->Null(); + return OutputVarType{}; + } + + OutputVarType add_null_to_object(const std::string_view& _name, + OutputObjectType* _parent) const noexcept { + fbb_->Null(_name.data()); + return OutputVarType{}; + } + + void end_array(OutputArrayType* _arr) const noexcept { + fbb_->EndVector(_arr->start_, false, false); + } + + void end_object(OutputObjectType* _obj) const noexcept { + fbb_->EndMap(_obj->start_); + } + + private: + template + OutputVarType insert_value(const std::string_view& _name, + const T& _var) const noexcept { + if constexpr (std::is_same, std::string>()) { + fbb_->String(_name.data(), _var); + } else if constexpr (std::is_same, bool>()) { + fbb_->Bool(_name.data(), _var); + } else if constexpr (std::is_floating_point>()) { + fbb_->Double(_name.data(), _var); + } else if constexpr (std::is_integral>()) { + fbb_->Int(_name.data(), _var); + } else { + static_assert(always_false_v, "Unsupported type"); + } + return OutputVarType{}; + } + + template + OutputVarType insert_value(const T& _var) const noexcept { + if constexpr (std::is_same, std::string>()) { + fbb_->String(_var); + } else if constexpr (std::is_same, bool>()) { + fbb_->Bool(_var); + } else if constexpr (std::is_floating_point>()) { + fbb_->Double(_var); + } else if constexpr (std::is_integral>()) { + fbb_->Int(_var); + } else { + static_assert(always_false_v, "Unsupported type"); + } + return OutputVarType{}; + } + + OutputArrayType new_array(const std::string_view& _name) const noexcept { + const auto start = fbb_->StartVector(_name.data()); + return OutputArrayType{start}; + } + + OutputArrayType new_array() const noexcept { + const auto start = fbb_->StartVector(); + return OutputArrayType{start}; + } + + OutputObjectType new_object(const std::string_view& _name) const noexcept { + const auto start = fbb_->StartMap(_name.data()); + return OutputObjectType{start}; + } + + OutputObjectType new_object() const noexcept { + const auto start = fbb_->StartMap(); + return OutputObjectType{start}; + } + + private: + Ref fbb_; +}; + +} // namespace flexbuf +} // namespace rfl + +#endif diff --git a/include/rfl/flexbuf/load.hpp b/include/rfl/flexbuf/load.hpp new file mode 100644 index 0000000..ec0a4e7 --- /dev/null +++ b/include/rfl/flexbuf/load.hpp @@ -0,0 +1,22 @@ +#ifndef RFL_FLEXBUF_LOAD_HPP_ +#define RFL_FLEXBUF_LOAD_HPP_ + +#include "../Result.hpp" +#include "../io/load_bytes.hpp" +#include "read.hpp" + +namespace rfl { +namespace flexbuf { + +template +Result load(const std::string& _fname) { + const auto read_bytes = [](const auto& _bytes) { + return read(_bytes); + }; + return rfl::io::load_bytes(_fname).and_then(read_bytes); +} + +} // namespace flexbuf +} // namespace rfl + +#endif diff --git a/include/rfl/flexbuf/read.hpp b/include/rfl/flexbuf/read.hpp new file mode 100644 index 0000000..afdb805 --- /dev/null +++ b/include/rfl/flexbuf/read.hpp @@ -0,0 +1,50 @@ +#ifndef FLEXBUF_READ_HPP_ +#define FLEXBUF_READ_HPP_ + +#include + +#include +#include + +#include "../Processors.hpp" +#include "../Result.hpp" +#include "Parser.hpp" + +namespace rfl { +namespace flexbuf { + +using InputVarType = typename Reader::InputVarType; + +/// Parses an object from flexbuf var. +template +auto read(const InputVarType& _obj) { + const auto r = Reader(); + return Parser>::read(r, _obj); +} + +/// Parses an object from flexbuf using reflection. +template +auto read(const char* _bytes, const size_t _size) { + const InputVarType root = + flexbuffers::GetRoot(reinterpret_cast(_bytes), _size); + return read(root); +} + +/// Parses an object from flexbuf using reflection. +template +auto read(const std::vector& _bytes) { + return read(_bytes.data(), _bytes.size()); +} + +/// Parses an object directly from a stream. +template +auto read(std::istream& _stream) { + std::istreambuf_iterator begin(_stream), end; + const auto bytes = std::vector(begin, end); + return read(bytes.data(), bytes.size()); +} + +} // namespace flexbuf +} // namespace rfl + +#endif diff --git a/include/rfl/flexbuf/save.hpp b/include/rfl/flexbuf/save.hpp new file mode 100644 index 0000000..cc2a8d2 --- /dev/null +++ b/include/rfl/flexbuf/save.hpp @@ -0,0 +1,26 @@ +#ifndef RFL_FLEXBUF_SAVE_HPP_ +#define RFL_FLEXBUF_SAVE_HPP_ + +#include +#include +#include + +#include "../Result.hpp" +#include "../io/save_bytes.hpp" +#include "write.hpp" + +namespace rfl { +namespace flexbuf { + +template +Result save(const std::string& _fname, const auto& _obj) { + const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { + return write(_obj, _stream); + }; + return rfl::io::save_bytes(_fname, _obj, write_func); +} + +} // namespace flexbuf +} // namespace rfl + +#endif diff --git a/include/rfl/flexbuf/write.hpp b/include/rfl/flexbuf/write.hpp new file mode 100644 index 0000000..5409ead --- /dev/null +++ b/include/rfl/flexbuf/write.hpp @@ -0,0 +1,50 @@ +#ifndef FLEXBUF_WRITE_HPP_ +#define FLEXBUF_WRITE_HPP_ + +#include + +#include +#include +#include +#include + +#include "../Processors.hpp" +#include "../Ref.hpp" +#include "../parsing/Parent.hpp" +#include "Parser.hpp" + +namespace rfl { +namespace flexbuf { + +template +std::vector to_buffer(const auto& _obj) { + using T = std::remove_cvref_t; + using ParentType = parsing::Parent; + const auto fbb = Ref::make(); + auto w = Writer(fbb); + Parser>::write(w, _obj, typename ParentType::Root{}); + fbb->Finish(); + return fbb->GetBuffer(); +} + +/// Writes an object to flexbuf. +template +std::vector write(const auto& _obj) { + const auto buffer = to_buffer(_obj); + const auto data = reinterpret_cast(buffer.data()); + return std::vector(data, data + buffer.size()); +} + +/// Writes an object to an ostream. +template +std::ostream& write(const auto& _obj, std::ostream& _stream) { + const auto buffer = to_buffer(_obj); + const auto data = reinterpret_cast(buffer.data()); + _stream.write(data, buffer.size()); + return _stream; +} + +} // namespace flexbuf +} // namespace rfl + +#endif diff --git a/include/rfl/json.hpp b/include/rfl/json.hpp new file mode 100644 index 0000000..cac6b0e --- /dev/null +++ b/include/rfl/json.hpp @@ -0,0 +1,14 @@ +#ifndef RFL_JSON_HPP_ +#define RFL_JSON_HPP_ + +#include "../rfl.hpp" +#include "json/Parser.hpp" +#include "json/Reader.hpp" +#include "json/Writer.hpp" +#include "json/load.hpp" +#include "json/read.hpp" +#include "json/save.hpp" +#include "json/to_schema.hpp" +#include "json/write.hpp" + +#endif diff --git a/include/rfl/json/Parser.hpp b/include/rfl/json/Parser.hpp new file mode 100644 index 0000000..9de1755 --- /dev/null +++ b/include/rfl/json/Parser.hpp @@ -0,0 +1,15 @@ +#ifndef RFL_JSON_PARSER_HPP_ +#define RFL_JSON_PARSER_HPP_ + +#include "../parsing/Parser.hpp" +#include "Reader.hpp" +#include "Writer.hpp" + +namespace rfl::json { + +template +using Parser = parsing::Parser; + +} // namespace rfl::json + +#endif diff --git a/include/rfl/json/Reader.hpp b/include/rfl/json/Reader.hpp new file mode 100644 index 0000000..958df68 --- /dev/null +++ b/include/rfl/json/Reader.hpp @@ -0,0 +1,154 @@ +#ifndef RFL_JSON_READER_HPP_ +#define RFL_JSON_READER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace json { + +struct Reader { + struct YYJSONInputArray { + YYJSONInputArray(yyjson_val* _val) : val_(_val) {} + yyjson_val* val_; + }; + + struct YYJSONInputObject { + YYJSONInputObject(yyjson_val* _val) : val_(_val) {} + yyjson_val* val_; + }; + + struct YYJSONInputVar { + YYJSONInputVar() : val_(nullptr) {} + YYJSONInputVar(yyjson_val* _val) : val_(_val) {} + yyjson_val* val_; + }; + + using InputArrayType = YYJSONInputArray; + using InputObjectType = YYJSONInputObject; + using InputVarType = YYJSONInputVar; + + template + static constexpr bool has_custom_constructor = (requires(InputVarType var) { + T::from_json_obj(var); + }); + + rfl::Result get_field( + const std::string& _name, const InputObjectType _obj) const noexcept { + const auto var = InputVarType(yyjson_obj_get(_obj.val_, _name.c_str())); + if (!var.val_) { + return rfl::Error("Object contains no field named '" + _name + "'."); + } + return var; + } + + bool is_empty(const InputVarType _var) const noexcept { + return !_var.val_ || yyjson_is_null(_var.val_); + } + + template + std::optional read_array(const ArrayReader& _array_reader, + const InputArrayType& _arr) const noexcept { + yyjson_val* val; + yyjson_arr_iter iter; + yyjson_arr_iter_init(_arr.val_, &iter); + while ((val = yyjson_arr_iter_next(&iter))) { + const auto err = _array_reader.read(InputVarType(val)); + if (err) { + return err; + } + } + return std::nullopt; + } + + template + std::optional read_object(const ObjectReader& _object_reader, + const InputObjectType& _obj) const noexcept { + yyjson_obj_iter iter; + yyjson_obj_iter_init(_obj.val_, &iter); + yyjson_val* key; + while ((key = yyjson_obj_iter_next(&iter))) { + const auto name = std::string_view(yyjson_get_str(key)); + _object_reader.read(name, InputVarType(yyjson_obj_iter_get_val(key))); + } + return std::nullopt; + } + + template + rfl::Result to_basic_type(const InputVarType _var) const noexcept { + if constexpr (std::is_same, std::string>()) { + const auto r = yyjson_get_str(_var.val_); + if (r == NULL) { + return rfl::Error("Could not cast to string."); + } + return std::string(r); + } else if constexpr (std::is_same, bool>()) { + if (!yyjson_is_bool(_var.val_)) { + return rfl::Error("Could not cast to boolean."); + } + return yyjson_get_bool(_var.val_); + } else if constexpr (std::is_floating_point>()) { + if (!yyjson_is_num(_var.val_)) { + return rfl::Error("Could not cast to double."); + } + return static_cast(yyjson_get_num(_var.val_)); + } else if constexpr (std::is_unsigned>()) { + if (!yyjson_is_int(_var.val_)) { + return rfl::Error("Could not cast to int."); + } + return static_cast(yyjson_get_uint(_var.val_)); + } else if constexpr (std::is_integral>()) { + if (!yyjson_is_int(_var.val_)) { + return rfl::Error("Could not cast to int."); + } + return static_cast(yyjson_get_sint(_var.val_)); + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + } + + rfl::Result to_array(const InputVarType _var) const noexcept { + if (!yyjson_is_arr(_var.val_)) { + return rfl::Error("Could not cast to array!"); + } + return InputArrayType(_var.val_); + } + + rfl::Result to_object( + const InputVarType _var) const noexcept { + if (!yyjson_is_obj(_var.val_)) { + return rfl::Error("Could not cast to object!"); + } + return InputObjectType(_var.val_); + } + + template + rfl::Result use_custom_constructor( + const InputVarType _var) const noexcept { + try { + return T::from_json_obj(_var); + } catch (std::exception& e) { + return rfl::Error(e.what()); + } + } +}; + +} // namespace json +} // namespace rfl + +#endif // JSON_PARSER_HPP_ diff --git a/include/rfl/json/Writer.hpp b/include/rfl/json/Writer.hpp new file mode 100644 index 0000000..81d794f --- /dev/null +++ b/include/rfl/json/Writer.hpp @@ -0,0 +1,169 @@ +#ifndef RFL_JSON_WRITER_HPP_ +#define RFL_JSON_WRITER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace json { + +class Writer { + public: + struct YYJSONOutputArray { + YYJSONOutputArray(yyjson_mut_val* _val) : val_(_val) {} + yyjson_mut_val* val_; + }; + + struct YYJSONOutputObject { + YYJSONOutputObject(yyjson_mut_val* _val) : val_(_val) {} + yyjson_mut_val* val_; + }; + + struct YYJSONOutputVar { + YYJSONOutputVar(yyjson_mut_val* _val) : val_(_val) {} + + YYJSONOutputVar(YYJSONOutputArray _arr) : val_(_arr.val_) {} + + YYJSONOutputVar(YYJSONOutputObject _obj) : val_(_obj.val_) {} + + yyjson_mut_val* val_; + }; + + using OutputArrayType = YYJSONOutputArray; + using OutputObjectType = YYJSONOutputObject; + using OutputVarType = YYJSONOutputVar; + + Writer(yyjson_mut_doc* _doc) : doc_(_doc) {} + + ~Writer() = default; + + OutputArrayType array_as_root(const size_t _size) const noexcept { + const auto arr = yyjson_mut_arr(doc_); + yyjson_mut_doc_set_root(doc_, arr); + return OutputArrayType(arr); + } + + OutputObjectType object_as_root(const size_t _size) const noexcept { + const auto obj = yyjson_mut_obj(doc_); + yyjson_mut_doc_set_root(doc_, obj); + return OutputObjectType(obj); + } + + OutputVarType null_as_root() const noexcept { + const auto null = yyjson_mut_null(doc_); + yyjson_mut_doc_set_root(doc_, null); + return OutputVarType(null); + } + + template + OutputVarType value_as_root(const T& _var) const noexcept { + const auto val = from_basic_type(_var); + yyjson_mut_doc_set_root(doc_, val.val_); + return OutputVarType(val); + } + + OutputArrayType add_array_to_array(const size_t _size, + OutputArrayType* _parent) const noexcept { + const auto arr = yyjson_mut_arr(doc_); + yyjson_mut_arr_add_val(_parent->val_, arr); + return OutputArrayType(arr); + } + + OutputArrayType add_array_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + const auto arr = yyjson_mut_arr(doc_); + yyjson_mut_obj_add(_parent->val_, yyjson_mut_strcpy(doc_, _name.data()), + arr); + return OutputArrayType(arr); + } + + OutputObjectType add_object_to_array( + const size_t _size, OutputArrayType* _parent) const noexcept { + const auto obj = yyjson_mut_obj(doc_); + yyjson_mut_arr_add_val(_parent->val_, obj); + return OutputObjectType(obj); + } + + OutputObjectType add_object_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + const auto obj = yyjson_mut_obj(doc_); + yyjson_mut_obj_add(_parent->val_, yyjson_mut_strcpy(doc_, _name.data()), + obj); + return OutputObjectType(obj); + } + + template + OutputVarType add_value_to_array(const T& _var, + OutputArrayType* _parent) const noexcept { + const auto val = from_basic_type(_var); + yyjson_mut_arr_add_val(_parent->val_, val.val_); + return OutputVarType(val); + } + + template + OutputVarType add_value_to_object(const std::string_view& _name, + const T& _var, + OutputObjectType* _parent) const noexcept { + const auto val = from_basic_type(_var); + yyjson_mut_obj_add(_parent->val_, yyjson_mut_strcpy(doc_, _name.data()), + val.val_); + return OutputVarType(val); + } + + OutputVarType add_null_to_array(OutputArrayType* _parent) const noexcept { + const auto null = yyjson_mut_null(doc_); + yyjson_mut_arr_add_val(_parent->val_, null); + return OutputVarType(null); + } + + OutputVarType add_null_to_object(const std::string_view& _name, + OutputObjectType* _parent) const noexcept { + const auto null = yyjson_mut_null(doc_); + yyjson_mut_obj_add(_parent->val_, yyjson_mut_strcpy(doc_, _name.data()), + null); + return OutputVarType(null); + } + + void end_array(OutputArrayType* _arr) const noexcept {} + + void end_object(OutputObjectType* _obj) const noexcept {} + + private: + template + OutputVarType from_basic_type(const T& _var) const noexcept { + if constexpr (std::is_same, std::string>()) { + return OutputVarType(yyjson_mut_strcpy(doc_, _var.c_str())); + } else if constexpr (std::is_same, bool>()) { + return OutputVarType(yyjson_mut_bool(doc_, _var)); + } else if constexpr (std::is_floating_point>()) { + return OutputVarType(yyjson_mut_real(doc_, static_cast(_var))); + } else if constexpr (std::is_unsigned>()) { + return OutputVarType(yyjson_mut_uint(doc_, static_cast(_var))); + } else if constexpr (std::is_integral>()) { + return OutputVarType(yyjson_mut_int(doc_, static_cast(_var))); + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + } + + public: + yyjson_mut_doc* doc_; +}; + +} // namespace json +} // namespace rfl + +#endif // JSON_PARSER_HPP_ diff --git a/include/rfl/json/load.hpp b/include/rfl/json/load.hpp new file mode 100644 index 0000000..5f7e8f4 --- /dev/null +++ b/include/rfl/json/load.hpp @@ -0,0 +1,22 @@ +#ifndef RFL_JSON_LOAD_HPP_ +#define RFL_JSON_LOAD_HPP_ + +#include "../Result.hpp" +#include "../io/load_string.hpp" +#include "read.hpp" + +namespace rfl { +namespace json { + +template +Result load(const std::string& _fname) { + const auto read_string = [](const auto& _str) { + return read(_str); + }; + return rfl::io::load_string(_fname).and_then(read_string); +} + +} // namespace json +} // namespace rfl + +#endif diff --git a/include/rfl/json/read.hpp b/include/rfl/json/read.hpp new file mode 100644 index 0000000..30bef1b --- /dev/null +++ b/include/rfl/json/read.hpp @@ -0,0 +1,52 @@ +#ifndef RFL_JSON_READ_HPP_ +#define RFL_JSON_READ_HPP_ + +#include + +#include +#include + +#include "../Processors.hpp" +#include "../internal/wrap_in_rfl_array_t.hpp" +#include "Parser.hpp" +#include "Reader.hpp" + +namespace rfl { +namespace json { + +using InputObjectType = typename Reader::InputObjectType; +using InputVarType = typename Reader::InputVarType; + +/// Parses an object from a JSON var. +template +auto read(const InputVarType& _obj) { + const auto r = Reader(); + return Parser>::read(r, _obj); +} + +/// Parses an object from JSON using reflection. +template +Result> read(const std::string& _json_str) { + yyjson_doc* doc = yyjson_read(_json_str.c_str(), _json_str.size(), 0); + if (!doc) { + return Error("Could not parse document"); + } + yyjson_val* root = yyjson_doc_get_root(doc); + const auto r = Reader(); + auto res = Parser>::read(r, InputVarType(root)); + yyjson_doc_free(doc); + return res; +} + +/// Parses an object from a stringstream. +template +auto read(std::istream& _stream) { + const auto json_str = std::string(std::istreambuf_iterator(_stream), + std::istreambuf_iterator()); + return read(json_str); +} + +} // namespace json +} // namespace rfl + +#endif diff --git a/include/rfl/json/save.hpp b/include/rfl/json/save.hpp new file mode 100644 index 0000000..9875df8 --- /dev/null +++ b/include/rfl/json/save.hpp @@ -0,0 +1,29 @@ +#ifndef RFL_JSON_SAVE_HPP_ +#define RFL_JSON_SAVE_HPP_ + +#include + +#include +#include +#include + +#include "../Result.hpp" +#include "../io/save_string.hpp" +#include "write.hpp" + +namespace rfl { +namespace json { + +template +Result save(const std::string& _fname, const auto& _obj, + const yyjson_write_flag _flag = 0) { + const auto write_func = [_flag](const auto& _obj, auto& _stream) -> auto& { + return write(_obj, _stream, _flag); + }; + return rfl::io::save_string(_fname, _obj, write_func); +} + +} // namespace json +} // namespace rfl + +#endif diff --git a/include/rfl/json/schema/JSONSchema.hpp b/include/rfl/json/schema/JSONSchema.hpp new file mode 100644 index 0000000..7aedfb7 --- /dev/null +++ b/include/rfl/json/schema/JSONSchema.hpp @@ -0,0 +1,25 @@ +#ifndef RFL_JSON_SCHEMA_JSONSCHEMA_HPP_ +#define RFL_JSON_SCHEMA_JSONSCHEMA_HPP_ + +#include +#include +#include + +#include "../../Flatten.hpp" +#include "../../Literal.hpp" +#include "../../Rename.hpp" +#include "Type.hpp" + +namespace rfl::json::schema { + +template +struct JSONSchema { + Rename<"$schema", Literal<"https://json-schema.org/draft/2020-12/schema">> + schema; + Flatten root; + std::map definitions; +}; + +} // namespace rfl::json::schema + +#endif diff --git a/include/rfl/json/schema/Type.hpp b/include/rfl/json/schema/Type.hpp new file mode 100644 index 0000000..7352cad --- /dev/null +++ b/include/rfl/json/schema/Type.hpp @@ -0,0 +1,147 @@ +#ifndef RFL_JSON_SCHEMA_TYPE_HPP_ +#define RFL_JSON_SCHEMA_TYPE_HPP_ + +#include +#include +#include +#include +#include + +#include "../../Literal.hpp" +#include "../../Rename.hpp" + +namespace rfl::json::schema { + +/// The JSON representation of internal::schema::Type. +struct Type { + struct Boolean { + std::optional description; + Literal<"boolean"> type; + }; + + struct Integer { + Literal<"integer"> type; + std::optional description; + }; + + struct Number { + Literal<"number"> type; + std::optional description; + }; + + struct String { + Literal<"string"> type; + std::optional description; + }; + + using NumericType = std::variant; + + struct AllOf { + std::optional description; + std::vector allOf; + }; + + struct AnyOf { + std::optional description; + std::vector anyOf; + }; + + struct ExclusiveMaximum { + std::optional description; + std::variant exclusiveMaximum; + std::string type; + }; + + struct ExclusiveMinimum { + std::optional description; + std::variant exclusiveMinimum; + std::string type; + }; + + struct FixedSizeTypedArray { + Literal<"array"> type; + std::optional description; + rfl::Ref items; + size_t minContains; + size_t maxContains; + }; + + struct Maximum { + std::optional description; + std::variant maximum; + std::string type; + }; + + struct Minimum { + std::optional description; + std::variant minimum; + std::string type; + }; + + struct Null { + Literal<"null"> type; + std::optional description; + }; + + struct Object { + Literal<"object"> type; + std::optional description; + std::map properties; + std::vector required; + }; + + struct OneOf { + std::optional description; + std::vector oneOf; + }; + + struct Reference { + Rename<"$ref", std::optional> ref; + std::optional description; + }; + + struct Regex { + Literal<"string"> type; + std::optional description; + std::string pattern; + }; + + struct StringEnum { + Literal<"string"> type; + std::optional description; + rfl::Rename<"enum", std::vector> values; + }; + + struct StringMap { + Literal<"object"> type; + std::optional description; + rfl::Ref additionalProperties; + }; + + struct Tuple { + Literal<"array"> type; + std::optional description; + std::vector prefixItems; + bool items = false; + }; + + struct TypedArray { + Literal<"array"> type; + std::optional description; + rfl::Ref items; + }; + + using ReflectionType = + std::variant; + + const auto& reflection() const { return value; } + + ReflectionType value; +}; + +} // namespace rfl::json::schema + +#endif diff --git a/include/rfl/json/to_schema.hpp b/include/rfl/json/to_schema.hpp new file mode 100644 index 0000000..37ff2d5 --- /dev/null +++ b/include/rfl/json/to_schema.hpp @@ -0,0 +1,262 @@ +#ifndef RFL_JSON_TOSCHEMA_HPP_ +#define RFL_JSON_TOSCHEMA_HPP_ + +#include + +#include +#include +#include +#include + +#include "../Literal.hpp" +#include "../Processors.hpp" +#include "../parsing/schema/Type.hpp" +#include "../parsing/schema/ValidationType.hpp" +#include "../parsing/schema/make.hpp" +#include "Reader.hpp" +#include "Writer.hpp" +#include "schema/JSONSchema.hpp" +#include "schema/Type.hpp" +#include "write.hpp" + +namespace rfl::json { + +inline schema::Type type_to_json_schema_type( + const parsing::schema::Type& _type); + +inline bool is_optional(const parsing::schema::Type& _t) { + const auto handle = [](const auto& _v) -> bool { + using T = std::remove_cvref_t; + return std::is_same(); + }; + return std::visit(handle, _t.variant_); +} + +inline std::string numeric_type_to_string(const parsing::schema::Type& _type) { + const auto handle_variant = [](const auto& _t) -> std::string { + using T = std::remove_cvref_t; + using Type = parsing::schema::Type; + if constexpr (std::is_same() || + std::is_same() || + std::is_same() || + std::is_same() || + std::is_same()) { + return schema::Type::Integer{}.type.str(); + } else { + return schema::Type::Number{}.type.str(); + } + }; + return std::visit(handle_variant, _type.variant_); +} + +inline schema::Type handle_validation_type( + const parsing::schema::Type& _type, + const parsing::schema::ValidationType& _validation_type) { + const auto handle_variant = [&](const auto& _v) -> schema::Type { + using T = std::remove_cvref_t; + using ValidationType = parsing::schema::ValidationType; + if constexpr (std::is_same()) { + auto all_of = std::vector(); + for (const auto& t : _v.types_) { + all_of.emplace_back(handle_validation_type(_type, t)); + } + return schema::Type{.value = schema::Type::AllOf{.allOf = all_of}}; + + } else if constexpr (std::is_same()) { + auto any_of = std::vector(); + for (const auto& t : _v.types_) { + any_of.emplace_back(handle_validation_type(_type, t)); + } + return schema::Type{.value = schema::Type::AnyOf{.anyOf = any_of}}; + + } else if constexpr (std::is_same()) { + auto one_of = std::vector(); + for (const auto& t : _v.types_) { + one_of.emplace_back(handle_validation_type(_type, t)); + } + return schema::Type{.value = schema::Type::OneOf{.oneOf = one_of}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::Regex{.pattern = _v.pattern_}}; + + } else if constexpr (std::is_same()) { + return type_to_json_schema_type(_type); + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::ExclusiveMaximum{ + .exclusiveMaximum = _v.value_, + .type = numeric_type_to_string(_type)}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::ExclusiveMinimum{ + .exclusiveMinimum = _v.value_, + .type = numeric_type_to_string(_type)}}; + + } else if constexpr (std::is_same()) { + return schema::Type{ + .value = schema::Type::Maximum{ + .maximum = _v.value_, .type = numeric_type_to_string(_type)}}; + + } else if constexpr (std::is_same()) { + return schema::Type{ + .value = schema::Type::Minimum{ + .minimum = _v.value_, .type = numeric_type_to_string(_type)}}; + + } else if constexpr (std::is_same()) { + const auto maximum = schema::Type{ + .value = schema::Type::Maximum{ + .maximum = _v.value_, .type = numeric_type_to_string(_type)}}; + const auto minimum = schema::Type{ + .value = schema::Type::Minimum{ + .minimum = _v.value_, .type = numeric_type_to_string(_type)}}; + return schema::Type{.value = + schema::Type::AllOf{.allOf = {maximum, minimum}}}; + + } else if constexpr (std::is_same()) { + const auto excl_maximum = + schema::Type{.value = schema::Type::ExclusiveMaximum{ + .exclusiveMaximum = _v.value_, + .type = numeric_type_to_string(_type)}}; + const auto excl_minimum = + schema::Type{.value = schema::Type::ExclusiveMinimum{ + .exclusiveMinimum = _v.value_, + .type = numeric_type_to_string(_type)}}; + return schema::Type{ + .value = schema::Type::AnyOf{.anyOf = {excl_maximum, excl_minimum}}}; + + } else { + static_assert(rfl::always_false_v, "Not all cases were covered."); + } + }; + + return std::visit(handle_variant, _validation_type.variant_); +} + +inline schema::Type type_to_json_schema_type( + const parsing::schema::Type& _type) { + const auto handle_variant = [](const auto& _t) -> schema::Type { + using T = std::remove_cvref_t; + using Type = parsing::schema::Type; + if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::Boolean{}}; + + } else if constexpr (std::is_same() || + std::is_same() || + std::is_same() || + std::is_same() || + std::is_same()) { + return schema::Type{.value = schema::Type::Integer{}}; + + } else if constexpr (std::is_same() || + std::is_same()) { + return schema::Type{.value = schema::Type::Number{}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::String{}}; + + } else if constexpr (std::is_same()) { + auto any_of = std::vector(); + for (const auto& t : _t.types_) { + any_of.emplace_back(type_to_json_schema_type(t)); + } + return schema::Type{.value = schema::Type::AnyOf{.anyOf = any_of}}; + + } else if constexpr (std::is_same()) { + auto res = type_to_json_schema_type(*_t.type_); + const auto update_prediction = [&](auto _v) -> schema::Type { + _v.description = _t.description_; + return schema::Type{_v}; + }; + return std::visit(update_prediction, res.value); + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::FixedSizeTypedArray{ + .items = Ref::make( + type_to_json_schema_type(*_t.type_)), + .minContains = _t.size_, + .maxContains = _t.size_}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = + schema::Type::StringEnum{.values = _t.values_}}; + + } else if constexpr (std::is_same()) { + auto properties = std::map(); + auto required = std::vector(); + for (const auto& [k, v] : _t.types_) { + properties[k] = type_to_json_schema_type(v); + if (!is_optional(v)) { + required.push_back(k); + } + } + return schema::Type{.value = schema::Type::Object{ + .properties = properties, .required = required}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::AnyOf{ + .anyOf = {type_to_json_schema_type(*_t.type_), + schema::Type{schema::Type::Null{}}}}}; + + } else if constexpr (std::is_same()) { + return schema::Type{ + .value = schema::Type::Reference{.ref = "#/definitions/" + _t.name_}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::StringMap{ + .additionalProperties = Ref::make( + type_to_json_schema_type(*_t.value_type_))}}; + + } else if constexpr (std::is_same()) { + auto items = std::vector(); + for (const auto& t : _t.types_) { + items.emplace_back(type_to_json_schema_type(t)); + } + return schema::Type{.value = schema::Type::Tuple{.prefixItems = items}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::TypedArray{ + .items = Ref::make( + type_to_json_schema_type(*_t.type_))}}; + + } else if constexpr (std::is_same()) { + return handle_validation_type(*_t.type_, _t.validation_); + + } else { + static_assert(rfl::always_false_v, "Not all cases were covered."); + } + }; + + return std::visit(handle_variant, _type.variant_); +} + +template +struct TypeHelper {}; + +template +struct TypeHelper> { + using JSONSchemaType = std::variant...>; +}; + +/// Returns the JSON schema for a class. +template +std::string to_schema(const yyjson_write_flag _flag = 0) { + const auto internal_schema = + parsing::schema::make>(); + auto definitions = std::map(); + for (const auto& [k, v] : internal_schema.definitions_) { + definitions[k] = type_to_json_schema_type(v); + } + using JSONSchemaType = + typename TypeHelper::JSONSchemaType; + const auto to_schema = [&](auto&& _root) -> JSONSchemaType { + using U = std::decay_t; + return schema::JSONSchema{.root = std::move(_root), + .definitions = definitions}; + }; + auto root = type_to_json_schema_type(internal_schema.root_); + const auto json_schema = std::visit(to_schema, std::move(root.value)); + return write(json_schema, _flag); +} +} // namespace rfl::json + +#endif diff --git a/include/rfl/json/write.hpp b/include/rfl/json/write.hpp new file mode 100644 index 0000000..8f5bc50 --- /dev/null +++ b/include/rfl/json/write.hpp @@ -0,0 +1,52 @@ +#ifndef RFL_JSON_WRITE_HPP_ +#define RFL_JSON_WRITE_HPP_ + +#include + +#include +#include +#include + +#include "../Processors.hpp" +#include "../parsing/Parent.hpp" +#include "Parser.hpp" + +namespace rfl { +namespace json { + +/// Convenient alias for the YYJSON pretty flag +inline constexpr yyjson_write_flag pretty = YYJSON_WRITE_PRETTY; + +/// Returns a JSON string. +template +std::string write(const auto& _obj, const yyjson_write_flag _flag = 0) { + using T = std::remove_cvref_t; + using ParentType = parsing::Parent; + auto w = Writer(yyjson_mut_doc_new(NULL)); + Parser>::write(w, _obj, typename ParentType::Root{}); + const char* json_c_str = yyjson_mut_write(w.doc_, _flag, NULL); + const auto json_str = std::string(json_c_str); + free((void*)json_c_str); + yyjson_mut_doc_free(w.doc_); + return json_str; +} + +/// Writes a JSON into an ostream. +template +std::ostream& write(const auto& _obj, std::ostream& _stream, + const yyjson_write_flag _flag = 0) { + using T = std::remove_cvref_t; + using ParentType = parsing::Parent; + auto w = Writer(yyjson_mut_doc_new(NULL)); + Parser>::write(w, _obj, typename ParentType::Root{}); + const char* json_c_str = yyjson_mut_write(w.doc_, _flag, NULL); + _stream << json_c_str; + free((void*)json_c_str); + yyjson_mut_doc_free(w.doc_); + return _stream; +} + +} // namespace json +} // namespace rfl + +#endif // JSON_PARSER_HPP_ diff --git a/include/rfl/msgpack.hpp b/include/rfl/msgpack.hpp new file mode 100644 index 0000000..45e8c66 --- /dev/null +++ b/include/rfl/msgpack.hpp @@ -0,0 +1,13 @@ +#ifndef RFL_MSGPACK_HPP_ +#define RFL_MSGPACK_HPP_ + +#include "../rfl.hpp" +#include "msgpack/Parser.hpp" +#include "msgpack/Reader.hpp" +#include "msgpack/Writer.hpp" +#include "msgpack/load.hpp" +#include "msgpack/read.hpp" +#include "msgpack/save.hpp" +#include "msgpack/write.hpp" + +#endif diff --git a/include/rfl/msgpack/Parser.hpp b/include/rfl/msgpack/Parser.hpp new file mode 100644 index 0000000..79da146 --- /dev/null +++ b/include/rfl/msgpack/Parser.hpp @@ -0,0 +1,46 @@ +#ifndef RFL_MSGPACK_PARSER_HPP_ +#define RFL_MSGPACK_PARSER_HPP_ + +#include "../parsing/Parser.hpp" +#include "Reader.hpp" +#include "Writer.hpp" + +namespace rfl { +namespace parsing { + +/// msgpack-c requires us to explicitly set the number of fields in advance. +/// Because of that, we require all of the fields and then set them to nullptr, +/// if necessary. +template +requires AreReaderAndWriter> +struct Parser, + ProcessorsType> + : public NamedTupleParser { +}; + +template +requires AreReaderAndWriter> +struct Parser, + ProcessorsType> + : public TupleParser { +}; + +} // namespace parsing +} // namespace rfl + +namespace rfl { +namespace msgpack { + +template +using Parser = parsing::Parser; + +} +} // namespace rfl + +#endif diff --git a/include/rfl/msgpack/Reader.hpp b/include/rfl/msgpack/Reader.hpp new file mode 100644 index 0000000..004251d --- /dev/null +++ b/include/rfl/msgpack/Reader.hpp @@ -0,0 +1,148 @@ +#ifndef RFL_MSGPACK_READER_HPP_ +#define RFL_MSGPACK_READER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Box.hpp" +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace msgpack { + +struct Reader { + using InputArrayType = msgpack_object_array; + using InputObjectType = msgpack_object_map; + using InputVarType = msgpack_object; + + template + static constexpr bool has_custom_constructor = (requires(InputVarType var) { + T::from_msgpack_obj(var); + }); + + rfl::Result get_field( + const std::string& _name, const InputObjectType& _obj) const noexcept { + for (uint32_t i = 0; i < _obj.size; ++i) { + const auto& key = _obj.ptr[i].key; + if (key.type != MSGPACK_OBJECT_STR) { + return Error("Key in element " + std::to_string(i) + + " was not a string."); + } + const auto current_name = + std::string_view(key.via.str.ptr, key.via.str.size); + if (_name == current_name) { + return _obj.ptr[i].val; + } + } + return Error("No field named '" + _name + "' was found."); + } + + bool is_empty(const InputVarType& _var) const noexcept { + return _var.type == MSGPACK_OBJECT_NIL; + } + + template + rfl::Result to_basic_type(const InputVarType& _var) const noexcept { + const auto type = _var.type; + if constexpr (std::is_same, std::string>()) { + if (type != MSGPACK_OBJECT_STR) { + return Error("Could not cast to string."); + } + const auto str = _var.via.str; + return std::string(str.ptr, str.size); + } else if constexpr (std::is_same, bool>()) { + if (type != MSGPACK_OBJECT_BOOLEAN) { + return Error("Could not cast to boolean."); + } + return _var.via.boolean; + } else if constexpr (std::is_floating_point>() || + std::is_integral>()) { + if (type == MSGPACK_OBJECT_FLOAT32 || type == MSGPACK_OBJECT_FLOAT64 || + type == MSGPACK_OBJECT_FLOAT) { + return static_cast(_var.via.f64); + } else if (type == MSGPACK_OBJECT_POSITIVE_INTEGER) { + return static_cast(_var.via.u64); + } else if (type == MSGPACK_OBJECT_NEGATIVE_INTEGER) { + return static_cast(_var.via.i64); + } + return rfl::Error( + "Could not cast to numeric value. The type must be integral, float " + "or double."); + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + } + + rfl::Result to_array( + const InputVarType& _var) const noexcept { + if (_var.type != MSGPACK_OBJECT_ARRAY) { + return Error("Could not cast to an array."); + } + return _var.via.array; + } + + rfl::Result to_object( + const InputVarType& _var) const noexcept { + if (_var.type != MSGPACK_OBJECT_MAP) { + return Error("Could not cast to a map."); + } + return _var.via.map; + } + + template + std::optional read_array(const ArrayReader& _array_reader, + const InputArrayType& _arr) const noexcept { + for (uint32_t i = 0; i < _arr.size; ++i) { + const auto err = _array_reader.read(_arr.ptr[i]); + if (err) { + return err; + } + } + return std::nullopt; + } + + template + std::optional read_object(const ObjectReader& _object_reader, + const InputObjectType& _obj) const noexcept { + for (uint32_t i = 0; i < _obj.size; ++i) { + const auto& key = _obj.ptr[i].key; + const auto& val = _obj.ptr[i].val; + if (key.type != MSGPACK_OBJECT_STR) { + return Error("Key in element " + std::to_string(i) + + " was not a string."); + } + const auto name = std::string_view(key.via.str.ptr, key.via.str.size); + _object_reader.read(name, val); + } + return std::nullopt; + } + + template + rfl::Result use_custom_constructor( + const InputVarType& _var) const noexcept { + try { + return T::from_msgpack_obj(_var); + } catch (std::exception& e) { + return rfl::Error(e.what()); + } + } +}; + +} // namespace msgpack +} // namespace rfl + +#endif // JSON_PARSER_HPP_ diff --git a/include/rfl/msgpack/Writer.hpp b/include/rfl/msgpack/Writer.hpp new file mode 100644 index 0000000..0ee2796 --- /dev/null +++ b/include/rfl/msgpack/Writer.hpp @@ -0,0 +1,154 @@ +#ifndef RFL_MSGPACK_WRITER_HPP_ +#define RFL_MSGPACK_WRITER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Box.hpp" +#include "../Ref.hpp" +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl::msgpack { + +class Writer { + public: + struct MsgpackOutputArray {}; + + struct MsgpackOutputObject {}; + + struct MsgpackOutputVar {}; + + using OutputArrayType = MsgpackOutputArray; + using OutputObjectType = MsgpackOutputObject; + using OutputVarType = MsgpackOutputVar; + + Writer(msgpack_packer* _pk) : pk_(_pk) {} + + ~Writer() = default; + + OutputArrayType array_as_root(const size_t _size) const noexcept { + return new_array(_size); + } + + OutputObjectType object_as_root(const size_t _size) const noexcept { + return new_object(_size); + } + + OutputVarType null_as_root() const noexcept { + msgpack_pack_nil(pk_); + return OutputVarType{}; + } + + template + OutputVarType value_as_root(const T& _var) const noexcept { + return new_value(_var); + } + + OutputArrayType add_array_to_array(const size_t _size, + OutputArrayType* _parent) const noexcept { + return new_array(_size); + } + + OutputArrayType add_array_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + msgpack_pack_str(pk_, _name.size()); + msgpack_pack_str_body(pk_, _name.data(), _name.size()); + return new_array(_size); + } + + OutputObjectType add_object_to_array( + const size_t _size, OutputArrayType* _parent) const noexcept { + return new_object(_size); + } + + OutputObjectType add_object_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + msgpack_pack_str(pk_, _name.size()); + msgpack_pack_str_body(pk_, _name.data(), _name.size()); + return new_object(_size); + } + + template + OutputVarType add_value_to_array(const T& _var, + OutputArrayType* _parent) const noexcept { + return new_value(_var); + } + + template + OutputVarType add_value_to_object(const std::string_view& _name, + const T& _var, + OutputObjectType* _parent) const noexcept { + msgpack_pack_str(pk_, _name.size()); + msgpack_pack_str_body(pk_, _name.data(), _name.size()); + return new_value(_var); + } + + OutputVarType add_null_to_array(OutputArrayType* _parent) const noexcept { + msgpack_pack_nil(pk_); + return OutputVarType{}; + } + + OutputVarType add_null_to_object(const std::string_view& _name, + OutputObjectType* _parent) const noexcept { + msgpack_pack_str(pk_, _name.size()); + msgpack_pack_str_body(pk_, _name.data(), _name.size()); + msgpack_pack_nil(pk_); + return OutputVarType{}; + } + + void end_array(OutputArrayType* _arr) const noexcept {} + + void end_object(OutputObjectType* _obj) const noexcept {} + + private: + OutputArrayType new_array(const size_t _size) const noexcept { + msgpack_pack_array(pk_, _size); + return OutputArrayType{}; + } + + OutputObjectType new_object(const size_t _size) const noexcept { + msgpack_pack_map(pk_, _size); + return OutputObjectType{}; + } + + template + OutputVarType new_value(const T& _var) const noexcept { + if constexpr (std::is_same, std::string>()) { + msgpack_pack_str(pk_, _var.size()); + msgpack_pack_str_body(pk_, _var.c_str(), _var.size()); + } else if constexpr (std::is_same, bool>()) { + if (_var) { + msgpack_pack_true(pk_); + } else { + msgpack_pack_false(pk_); + } + } else if constexpr (std::is_floating_point>()) { + msgpack_pack_double(pk_, static_cast(_var)); + } else if constexpr (std::is_integral>()) { + msgpack_pack_int64(pk_, static_cast(_var)); + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + return OutputVarType{}; + } + + private: + /// The underlying packer. + msgpack_packer* pk_; +}; + +} // namespace rfl::msgpack + +#endif // MSGPACK_PARSER_HPP_ diff --git a/include/rfl/msgpack/load.hpp b/include/rfl/msgpack/load.hpp new file mode 100644 index 0000000..5780257 --- /dev/null +++ b/include/rfl/msgpack/load.hpp @@ -0,0 +1,22 @@ +#ifndef RFL_MSGPACK_LOAD_HPP_ +#define RFL_MSGPACK_LOAD_HPP_ + +#include "../Result.hpp" +#include "../io/load_bytes.hpp" +#include "read.hpp" + +namespace rfl { +namespace msgpack { + +template +Result load(const std::string& _fname) { + const auto read_bytes = [](const auto& _bytes) { + return read(_bytes); + }; + return rfl::io::load_bytes(_fname).and_then(read_bytes); +} + +} // namespace msgpack +} // namespace rfl + +#endif diff --git a/include/rfl/msgpack/read.hpp b/include/rfl/msgpack/read.hpp new file mode 100644 index 0000000..0e0b676 --- /dev/null +++ b/include/rfl/msgpack/read.hpp @@ -0,0 +1,57 @@ +#ifndef RFL_MSGPACK_READ_HPP_ +#define RFL_MSGPACK_READ_HPP_ + +#include + +#include +#include + +#include "../Processors.hpp" +#include "../internal/wrap_in_rfl_array_t.hpp" +#include "Parser.hpp" +#include "Reader.hpp" + +namespace rfl { +namespace msgpack { + +using InputObjectType = typename Reader::InputObjectType; +using InputVarType = typename Reader::InputVarType; + +/// Parses an object from a MSGPACK var. +template +auto read(const InputVarType& _obj) { + const auto r = Reader(); + return Parser>::read(r, _obj); +} + +/// Parses an object from MSGPACK using reflection. +template +Result> read(const char* _bytes, + const size_t _size) { + msgpack_zone mempool; + msgpack_zone_init(&mempool, 2048); + msgpack_object deserialized; + msgpack_unpack(_bytes, _size, NULL, &mempool, &deserialized); + auto r = read(deserialized); + msgpack_zone_destroy(&mempool); + return r; +} + +/// Parses an object from MSGPACK using reflection. +template +auto read(const std::vector& _bytes) { + return read(_bytes.data(), _bytes.size()); +} + +/// Parses an object from a stream. +template +auto read(std::istream& _stream) { + std::istreambuf_iterator begin(_stream), end; + auto bytes = std::vector(begin, end); + return read(bytes.data(), bytes.size()); +} + +} // namespace msgpack +} // namespace rfl + +#endif diff --git a/include/rfl/msgpack/save.hpp b/include/rfl/msgpack/save.hpp new file mode 100644 index 0000000..1d2cfe5 --- /dev/null +++ b/include/rfl/msgpack/save.hpp @@ -0,0 +1,26 @@ +#ifndef RFL_MSGPACK_SAVE_HPP_ +#define RFL_MSGPACK_SAVE_HPP_ + +#include +#include +#include + +#include "../Result.hpp" +#include "../io/save_bytes.hpp" +#include "write.hpp" + +namespace rfl { +namespace msgpack { + +template +Result save(const std::string& _fname, const auto& _obj) { + const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { + return write(_obj, _stream); + }; + return rfl::io::save_bytes(_fname, _obj, write_func); +} + +} // namespace msgpack +} // namespace rfl + +#endif diff --git a/include/rfl/msgpack/write.hpp b/include/rfl/msgpack/write.hpp new file mode 100644 index 0000000..620ebb9 --- /dev/null +++ b/include/rfl/msgpack/write.hpp @@ -0,0 +1,44 @@ +#ifndef RFL_MSGPACK_WRITE_HPP_ +#define RFL_MSGPACK_WRITE_HPP_ + +#include + +#include +#include +#include +#include +#include + +#include "../Processors.hpp" +#include "../parsing/Parent.hpp" +#include "Parser.hpp" + +namespace rfl::msgpack { + +/// Returns msgpack bytes. +template +std::vector write(const auto& _obj) noexcept { + using T = std::remove_cvref_t; + using ParentType = parsing::Parent; + msgpack_sbuffer sbuf; + msgpack_sbuffer_init(&sbuf); + msgpack_packer pk; + msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); + auto w = Writer(&pk); + Parser>::write(w, _obj, typename ParentType::Root{}); + auto bytes = std::vector(sbuf.data, sbuf.data + sbuf.size); + msgpack_sbuffer_destroy(&sbuf); + return bytes; +} + +/// Writes a MSGPACK into an ostream. +template +std::ostream& write(const auto& _obj, std::ostream& _stream) noexcept { + auto buffer = write(_obj); + _stream.write(buffer.data(), buffer.size()); + return _stream; +} + +} // namespace rfl::msgpack + +#endif diff --git a/include/rfl/parsing/NamedTupleParser.hpp b/include/rfl/parsing/NamedTupleParser.hpp index 9882868..59fc718 100644 --- a/include/rfl/parsing/NamedTupleParser.hpp +++ b/include/rfl/parsing/NamedTupleParser.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../NamedTuple.hpp" #include "../Result.hpp" @@ -59,7 +60,7 @@ struct NamedTupleParser { using ViewType = std::remove_cvref_t; const auto err = Parser::read_view(_r, _var, &view); - if (err) { + if (err) [[unlikely]] { return *err; } return *ptr; @@ -69,11 +70,11 @@ struct NamedTupleParser { static std::optional read_view( const R& _r, const InputVarType& _var, NamedTuple* _view) noexcept { - const auto obj = _r.to_object(_var); - if (obj) { - return read_object(_r, *obj, _view); + auto obj = _r.to_object(_var); + if (!obj) [[unlikely]] { + return obj.error(); } - return obj.error(); + return read_object(_r, *obj, _view); } /// For writing, we do not need to make the distinction between @@ -147,38 +148,43 @@ struct NamedTupleParser { } /// Generates error messages for when fields are missing. - template - static void handle_missing_fields(const std::array& _found, - const NamedTupleType& _view, - std::array* _set, - std::vector* _errors) noexcept { - if constexpr (_i < sizeof...(FieldTypes)) { - using FieldType = - std::tuple_element_t<_i, typename NamedTupleType::Fields>; - using ValueType = std::remove_reference_t< - std::remove_pointer_t>; + template + static void handle_one_missing_field(const std::array& _found, + const NamedTupleType& _view, + std::array* _set, + std::vector* _errors) noexcept { + using FieldType = std::tuple_element_t<_i, typename NamedTupleType::Fields>; + using ValueType = std::remove_reference_t< + std::remove_pointer_t>; - if (!std::get<_i>(_found)) { - if constexpr (_all_required || - is_required()) { - constexpr auto current_name = - std::tuple_element_t<_i, typename NamedTupleType::Fields>::name(); - _errors->push_back("Field named '" + std::string(current_name) + - "' not found."); + if (!std::get<_i>(_found)) { + if constexpr (_all_required || + is_required()) { + constexpr auto current_name = + std::tuple_element_t<_i, typename NamedTupleType::Fields>::name(); + _errors->emplace_back(Error( + "Field named '" + std::string(current_name) + "' not found.")); + } else { + if constexpr (!std::is_const_v) { + ::new (rfl::get<_i>(_view)) ValueType(); } else { - if constexpr (!std::is_const_v) { - ::new (rfl::get<_i>(_view)) ValueType(); - } else { - using NonConstT = std::remove_const_t; - ::new (const_cast(rfl::get<_i>(_view))) NonConstT(); - } - std::get<_i>(*_set) = true; + using NonConstT = std::remove_const_t; + ::new (const_cast(rfl::get<_i>(_view))) NonConstT(); } + std::get<_i>(*_set) = true; } - handle_missing_fields<_i + 1>(_found, _view, _set, _errors); } } + /// Generates error messages for when fields are missing. + template + static void handle_missing_fields( + const std::array& _found, const NamedTupleType& _view, + std::array* _set, std::vector* _errors, + std::integer_sequence) noexcept { + (handle_one_missing_field<_is>(_found, _view, _set, _errors), ...); + } + static std::optional read_object(const R& _r, const InputObjectType& _obj, NamedTupleType* _view) noexcept { @@ -193,7 +199,8 @@ struct NamedTupleParser { if (err) { return *err; } - handle_missing_fields(found, *_view, &set, &errors); + handle_missing_fields(found, *_view, &set, &errors, + std::make_integer_sequence()); if (errors.size() != 0) { object_reader.call_destructors_where_necessary(); return to_single_error_message(errors); diff --git a/include/rfl/parsing/Parser_default.hpp b/include/rfl/parsing/Parser_default.hpp index a3b5b0a..88e5606 100644 --- a/include/rfl/parsing/Parser_default.hpp +++ b/include/rfl/parsing/Parser_default.hpp @@ -17,11 +17,11 @@ #include "../internal/is_validator.hpp" #include "../internal/processed_t.hpp" #include "../internal/to_ptr_named_tuple.hpp" +#include "../to_view.hpp" #include "../type_name_t.hpp" #include "AreReaderAndWriter.hpp" #include "Parent.hpp" #include "Parser_base.hpp" -#include "StructReader.hpp" #include "is_tagged_union_wrapper.hpp" #include "schema/Type.hpp" @@ -55,19 +55,13 @@ struct Parser { return Parser::read(_r, _var) .and_then(wrap_in_t); } else if constexpr (std::is_class_v && std::is_aggregate_v) { - return StructReader::read(_r, _var); + return read_struct(_r, _var); } else if constexpr (std::is_enum_v) { using StringConverter = internal::enums::StringConverter; return _r.template to_basic_type(_var).and_then( StringConverter::string_to_enum); - } else if constexpr (internal::is_basic_type_v) { - return _r.template to_basic_type>(_var); } else { - static_assert( - always_false_v, - "Unsupported type. Please refer to the sections on custom " - "classes and custom parsers for information on how add " - "support for your own classes."); + return _r.template to_basic_type>(_var); } } } @@ -93,13 +87,8 @@ struct Parser { using StringConverter = internal::enums::StringConverter; const auto str = StringConverter::enum_to_string(_var); ParentType::add_value(_w, str, _parent); - } else if constexpr (internal::is_basic_type_v) { - ParentType::add_value(_w, _var, _parent); } else { - static_assert(always_false_v, - "Unsupported type. Please refer to the sections on custom " - "classes and custom parsers for information on how add " - "support for your own classes."); + ParentType::add_value(_w, _var, _parent); } } @@ -222,6 +211,23 @@ struct Parser { } } + /// The way this works is that we allocate space on the stack in this size of + /// the struct in which we then write the individual fields using + /// views and placement new. This is how we deal with the fact that some + /// fields might not be default-constructible. + static Result read_struct(const R& _r, const InputVarType& _var) { + alignas(T) unsigned char buf[sizeof(T)]; + auto ptr = reinterpret_cast(buf); + auto view = ProcessorsType::template process(to_view(*ptr)); + using ViewType = std::remove_cvref_t; + const auto err = + Parser::read_view(_r, _var, &view); + if (err) [[unlikely]] { + return *err; + } + return std::move(*ptr); + } + static std::string replace_non_alphanumeric(std::string _str) { for (auto& ch : _str) { ch = std::isalnum(ch) ? ch : '_'; diff --git a/include/rfl/parsing/StructReader.hpp b/include/rfl/parsing/StructReader.hpp deleted file mode 100644 index e32f2c6..0000000 --- a/include/rfl/parsing/StructReader.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef RFL_PARSING_STRUCTREADER_HPP_ -#define RFL_PARSING_STRUCTREADER_HPP_ - -#include -#include -#include -#include - -#include "../Result.hpp" -#include "../to_view.hpp" -#include "AreReaderAndWriter.hpp" - -namespace rfl::parsing { - -template -requires AreReaderAndWriter -struct StructReader { - public: - using InputVarType = typename R::InputVarType; - - /// The way this works is that we allocate space on the stack in this size of - /// the struct in which we then write the individual fields using - /// views and placement new. This is how we deal with the fact that some - /// fields might not be default-constructible. - static Result read(const R& _r, const InputVarType& _var) { - alignas(StructType) unsigned char buf[sizeof(StructType)]; - auto ptr = reinterpret_cast(buf); - auto view = ProcessorsType::template process(to_view(*ptr)); - using ViewType = std::remove_cvref_t; - const auto err = - Parser::read_view(_r, _var, &view); - if (err) { - return *err; - } - return std::move(*ptr); - } -}; - -} // namespace rfl::parsing - -#endif diff --git a/include/rfl/parsing/ViewReader.hpp b/include/rfl/parsing/ViewReader.hpp index 3f3eb5c..d1ba971 100644 --- a/include/rfl/parsing/ViewReader.hpp +++ b/include/rfl/parsing/ViewReader.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "../Result.hpp" @@ -24,63 +25,68 @@ class ViewReader { ~ViewReader() = default; - template + /// Assigns the parsed version of _var to the field signified by _name, if + /// such a field exists in the underlying view. void read(const std::string_view& _name, const InputVarType& _var) const { - if constexpr (_i < size_) { - using FieldType = std::tuple_element_t<_i, typename ViewType::Fields>; - using OriginalType = std::remove_cvref_t; - using CurrentType = - std::remove_cvref_t>; - constexpr auto current_name = FieldType::name(); - if (!std::get<_i>(*found_) && _name == current_name) { - auto res = Parser::read(*r_, _var); - if (res) { - if constexpr (std::is_pointer_v) { - move_to(rfl::get<_i>(*view_), &(*res)); - } else { - rfl::get<_i>(*view_) = *res; - } - std::get<_i>(*set_) = true; - } else { - errors_->push_back(Error("Failed to parse field '" + - std::string(current_name) + - "': " + res.error()->what())); - } - std::get<_i>(*found_) = true; - return; - } - read<_i + 1>(_name, _var); - } + assign_to_matching_field(*r_, _name, _var, view_, errors_, found_, set_, + std::make_integer_sequence()); } /// Because of the way we have allocated the fields, we need to manually /// trigger the destructors. - template void call_destructors_where_necessary() const { - if constexpr (_i < size_) { - using FieldType = std::tuple_element_t<_i, typename ViewType::Fields>; - using OriginalType = std::remove_cvref_t; - using ValueType = - std::remove_cvref_t>; - if constexpr (!std::is_array_v && - std::is_pointer_v && - std::is_destructible_v) { - if (std::get<_i>(*set_)) { - rfl::get<_i>(*view_)->~ValueType(); - } - } else if constexpr (std::is_array_v) { - if (std::get<_i>(*set_)) { - auto ptr = rfl::get<_i>(*view_); - call_destructor_on_array(sizeof(*ptr) / sizeof(**ptr), *ptr); - } - } - call_destructors_where_necessary<_i + 1>(); + [&](std::integer_sequence) { + (call_destructor_on_one_if_necessary(), ...); } + (std::make_integer_sequence()); } private: + template + static void assign_if_field_matches(const R& _r, + const std::string_view& _current_name, + const auto& _var, auto* _view, + auto* _errors, auto* _found, auto* _set, + bool* _already_assigned) { + using FieldType = std::tuple_element_t; + using OriginalType = typename FieldType::Type; + using T = + std::remove_cvref_t>; + constexpr auto name = FieldType::name(); + if (!(*_already_assigned) && !std::get(*_found) && + _current_name == name) { + std::get(*_found) = true; + *_already_assigned = true; + auto res = Parser::read(_r, _var); + if (!res) { + _errors->emplace_back(Error("Failed to parse field '" + + std::string(name) + + "': " + std::move(res.error()->what()))); + return; + } + if constexpr (std::is_pointer_v) { + move_to(rfl::get(*_view), &(*res)); + } else { + rfl::get(*_view) = std::move(*res); + } + std::get(*_set) = true; + } + } + + template + static void assign_to_matching_field(const R& _r, + const std::string_view& _current_name, + const auto& _var, auto* _view, + auto* _errors, auto* _found, auto* _set, + std::integer_sequence) { + bool already_assigned = false; + (assign_if_field_matches(_r, _current_name, _var, _view, _errors, + _found, _set, &already_assigned), + ...); + } + template - void call_destructor_on_array(const size_t _size, T* _ptr) const { + static void call_destructor_on_array(const size_t _size, T* _ptr) { for (size_t i = 0; i < _size; ++i) { if constexpr (std::is_array_v) { call_destructor_on_array(sizeof(*_ptr) / sizeof(**_ptr), *(_ptr + i)); @@ -90,14 +96,34 @@ class ViewReader { } } + template + void call_destructor_on_one_if_necessary() const { + using FieldType = std::tuple_element_t<_i, typename ViewType::Fields>; + using OriginalType = std::remove_cvref_t; + using ValueType = + std::remove_cvref_t>; + if constexpr (!std::is_array_v && + std::is_pointer_v && + std::is_destructible_v) { + if (std::get<_i>(*set_)) { + rfl::get<_i>(*view_)->~ValueType(); + } + } else if constexpr (std::is_array_v) { + if (std::get<_i>(*set_)) { + auto ptr = rfl::get<_i>(*view_); + call_destructor_on_array(sizeof(*ptr) / sizeof(**ptr), *ptr); + } + } + } + template - void move_to(Target* _t, Source* _s) const { + static void move_to(Target* _t, Source* _s) { if constexpr (std::is_const_v) { return move_to(const_cast*>(_t), _s); - } else if constexpr (!internal::is_array_v && + } else if constexpr (!rfl::internal::is_array_v && !std::is_array_v) { ::new (_t) Target(std::move(*_s)); - } else if constexpr (internal::is_array_v) { + } else if constexpr (rfl::internal::is_array_v) { static_assert(std::is_array_v, "Expected target to be a c-array."); for (size_t i = 0; i < _s->arr_.size(); ++i) { diff --git a/include/rfl/xml.hpp b/include/rfl/xml.hpp new file mode 100644 index 0000000..ecb20c8 --- /dev/null +++ b/include/rfl/xml.hpp @@ -0,0 +1,13 @@ +#ifndef RFL_XML_HPP_ +#define RFL_XML_HPP_ + +#include "../rfl.hpp" +#include "xml/Parser.hpp" +#include "xml/Reader.hpp" +#include "xml/Writer.hpp" +#include "xml/load.hpp" +#include "xml/read.hpp" +#include "xml/save.hpp" +#include "xml/write.hpp" + +#endif diff --git a/include/rfl/xml/Parser.hpp b/include/rfl/xml/Parser.hpp new file mode 100644 index 0000000..687f751 --- /dev/null +++ b/include/rfl/xml/Parser.hpp @@ -0,0 +1,40 @@ +#ifndef RFL_XML_PARSER_HPP_ +#define RFL_XML_PARSER_HPP_ + +#include + +#include "../internal/is_attribute.hpp" +#include "../parsing/NamedTupleParser.hpp" +#include "../parsing/Parser.hpp" +#include "Reader.hpp" +#include "Writer.hpp" + +namespace rfl { +namespace parsing { + +/// XML is very special. It doesn't have proper support for arrays, which means +/// that we just need to ignore empty containers. Therefore, we need to a +/// template specialization for the NamedTuple parser to accommodate for it. +template +requires AreReaderAndWriter> +struct Parser, + ProcessorsType> + : public NamedTupleParser { +}; + +} // namespace parsing +} // namespace rfl + +namespace rfl { +namespace xml { + +template +using Parser = parsing::Parser; + +} +} // namespace rfl + +#endif diff --git a/include/rfl/xml/Reader.hpp b/include/rfl/xml/Reader.hpp new file mode 100644 index 0000000..6500b0d --- /dev/null +++ b/include/rfl/xml/Reader.hpp @@ -0,0 +1,174 @@ +#ifndef RFL_XML_READER_HPP_ +#define RFL_XML_READER_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Result.hpp" +#include "../always_false.hpp" +#include "../parsing/is_view_reader.hpp" + +namespace rfl { +namespace xml { + +struct Reader { + struct XMLInputArray { + XMLInputArray(pugi::xml_node _node) : node_(_node) {} + pugi::xml_node node_; + }; + + struct XMLInputObject { + XMLInputObject(pugi::xml_node _node) : node_(_node) {} + pugi::xml_node node_; + }; + + struct XMLInputVar { + XMLInputVar() : node_or_attribute_(pugi::xml_node()) {} + XMLInputVar(pugi::xml_attribute _attr) : node_or_attribute_(_attr) {} + XMLInputVar(pugi::xml_node _node) : node_or_attribute_(_node) {} + std::variant node_or_attribute_; + }; + + using InputArrayType = XMLInputArray; + using InputObjectType = XMLInputObject; + using InputVarType = XMLInputVar; + + // TODO + template + static constexpr bool has_custom_constructor = false; + + /// XML-only helper function. This is needed because XML distinguishes between + /// nodes and attributes. + static rfl::Result cast_as_node( + const std::variant& + _node_or_attribute) { + const auto cast = [](const auto& _n) -> Result { + using Type = std::remove_cvref_t; + if constexpr (std::is_same()) { + return _n; + } else { + return Error("Field '" + std::string(_n.name()) + "' is an attribute."); + } + }; + return std::visit(cast, _node_or_attribute); + } + + rfl::Result get_field( + const std::string& _name, const InputObjectType _obj) const noexcept { + const auto node = _obj.node_.child(_name.c_str()); + if (!node) { + return rfl::Error("Object contains no field named '" + _name + "'."); + } + return InputVarType(node); + } + + bool is_empty(const InputVarType _var) const noexcept { + const auto wrap = [](const auto& _node) { return !_node; }; + return std::visit(cast_as_node, _var.node_or_attribute_) + .transform(wrap) + .value_or(false); + } + + template + rfl::Result to_basic_type(const InputVarType _var) const noexcept { + const auto get_value = [](const auto& _n) -> std::string { + using Type = std::remove_cvref_t; + if constexpr (std::is_same()) { + return std::string(_n.child_value()); + } else { + return std::string(_n.value()); + } + }; + + if constexpr (std::is_same, std::string>()) { + return std::visit(get_value, _var.node_or_attribute_); + } else if constexpr (std::is_same, bool>()) { + return std::visit(get_value, _var.node_or_attribute_) == "true"; + } else if constexpr (std::is_floating_point>()) { + const auto str = std::visit(get_value, _var.node_or_attribute_); + try { + return static_cast(std::stod(str)); + } catch (std::exception& e) { + return Error("Could not cast '" + std::string(str) + + "' to floating point value."); + } + } else if constexpr (std::is_integral>()) { + const auto str = std::visit(get_value, _var.node_or_attribute_); + try { + return static_cast(std::stoi(str)); + } catch (std::exception& e) { + return Error("Could not cast '" + std::string(str) + "' to integer."); + } + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + } + + rfl::Result to_array(const InputVarType _var) const noexcept { + const auto wrap = [](const auto& _node) { return InputArrayType(_node); }; + return std::visit(cast_as_node, _var.node_or_attribute_).transform(wrap); + } + + template + std::optional read_array(const ArrayReader& _array_reader, + const InputArrayType& _arr) const noexcept { + const auto name = _arr.node_.name(); + for (auto node = _arr.node_; node; node = node.next_sibling(name)) { + const auto err = _array_reader.read(InputVarType(node)); + if (err) { + return err; + } + } + return std::nullopt; + } + + template + std::optional read_object(const ObjectReader& _object_reader, + const InputObjectType& _obj) const noexcept { + for (auto child = _obj.node_.first_child(); child; + child = child.next_sibling()) { + _object_reader.read(std::string_view(child.name()), InputVarType(child)); + } + + for (auto attr = _obj.node_.first_attribute(); attr; + attr = attr.next_attribute()) { + _object_reader.read(std::string_view(attr.name()), InputVarType(attr)); + } + + if constexpr (parsing::is_view_reader_v) { + _object_reader.read(std::string_view("xml_content"), + InputVarType(_obj.node_)); + } + + return std::nullopt; + } + + rfl::Result to_object( + const InputVarType _var) const noexcept { + const auto wrap = [](const auto& _node) { return InputObjectType(_node); }; + return std::visit(cast_as_node, _var.node_or_attribute_).transform(wrap); + } + + template + rfl::Result use_custom_constructor( + const InputVarType _var) const noexcept { + return rfl::Error("TODO"); + } +}; + +} // namespace xml +} // namespace rfl + +#endif diff --git a/include/rfl/xml/Writer.hpp b/include/rfl/xml/Writer.hpp new file mode 100644 index 0000000..be9131a --- /dev/null +++ b/include/rfl/xml/Writer.hpp @@ -0,0 +1,181 @@ +#ifndef RFL_XML_WRITER_HPP_ +#define RFL_XML_WRITER_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Ref.hpp" +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace xml { + +struct Writer { + static constexpr const char* XML_CONTENT = "xml_content"; + + struct XMLOutputArray { + XMLOutputArray(const std::string_view& _name, + const Ref& _node) + : name_(_name), node_(_node) {} + std::string_view name_; + Ref node_; + }; + + struct XMLOutputObject { + XMLOutputObject(const Ref& _node) : node_(_node) {} + Ref node_; + }; + + struct XMLOutputVar { + XMLOutputVar(const Ref& _node) : node_(_node) {} + Ref node_; + }; + + using OutputArrayType = XMLOutputArray; + using OutputObjectType = XMLOutputObject; + using OutputVarType = XMLOutputVar; + + Writer(const Ref& _root, const std::string& _root_name) + : root_(_root), root_name_(_root_name) {} + + ~Writer() = default; + + OutputArrayType array_as_root(const size_t _size) const noexcept { + auto node_child = + Ref::make(root_->append_child(root_name_.c_str())); + return OutputArrayType(root_name_, node_child); + } + + OutputObjectType object_as_root(const size_t _size) const noexcept { + auto node_child = + Ref::make(root_->append_child(root_name_.c_str())); + return OutputObjectType(node_child); + } + + OutputVarType null_as_root() const noexcept { + auto node_child = + Ref::make(root_->append_child(root_name_.c_str())); + return OutputVarType(node_child); + } + + template + OutputVarType value_as_root(const T& _var) const noexcept { + const auto str = to_string(_var); + auto node_child = + Ref::make(root_->append_child(root_name_.c_str())); + node_child->append_child(pugi::node_pcdata).set_value(str.c_str()); + return OutputVarType(node_child); + } + + OutputArrayType add_array_to_array(const size_t _size, + OutputArrayType* _parent) const noexcept { + return *_parent; + } + + OutputArrayType add_array_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + return OutputArrayType(_name, _parent->node_); + } + + OutputObjectType add_object_to_array( + const size_t _size, OutputArrayType* _parent) const noexcept { + auto node_child = Ref::make( + _parent->node_->append_child(_parent->name_.data())); + return OutputObjectType(node_child); + } + + OutputObjectType add_object_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + auto node_child = + Ref::make(_parent->node_->append_child(_name.data())); + return OutputObjectType(node_child); + } + + template + OutputVarType add_value_to_array(const T& _var, + OutputArrayType* _parent) const noexcept { + const auto str = to_string(_var); + auto node_child = Ref::make( + _parent->node_->append_child(_parent->name_.data())); + node_child->append_child(pugi::node_pcdata).set_value(str.c_str()); + return OutputVarType(node_child); + } + + template + OutputVarType add_value_to_object( + const std::string_view& _name, const T& _var, OutputObjectType* _parent, + const bool _is_attribute = false) const noexcept { + const auto str = to_string(_var); + if (_is_attribute) { + _parent->node_->append_attribute(_name.data()) = str.c_str(); + return OutputVarType(_parent->node_); + } else if (_name == XML_CONTENT) { + _parent->node_->append_child(pugi::node_pcdata).set_value(str.c_str()); + return OutputVarType(_parent->node_); + } else { + auto node_child = + Ref::make(_parent->node_->append_child(_name.data())); + node_child->append_child(pugi::node_pcdata).set_value(str.c_str()); + return OutputVarType(node_child); + } + } + + OutputVarType add_null_to_array(OutputArrayType* _parent) const noexcept { + auto node_child = Ref::make( + _parent->node_->append_child(_parent->name_.data())); + return OutputVarType(node_child); + } + + OutputVarType add_null_to_object( + const std::string_view& _name, OutputObjectType* _parent, + const bool _is_attribute = false) const noexcept { + if (_is_attribute) { + return OutputVarType(_parent->node_); + } else if (_name == XML_CONTENT) { + return OutputVarType(_parent->node_); + } else { + auto node_child = + Ref::make(_parent->node_->append_child(_name.data())); + return OutputVarType(node_child); + } + } + + void end_array(OutputArrayType* _arr) const noexcept {} + + void end_object(OutputObjectType* _obj) const noexcept {} + + private: + template + std::string to_string(const T& _val) const noexcept { + if constexpr (std::is_same, std::string>()) { + return _val; + } else if constexpr (std::is_same, bool>()) { + return _val ? "true" : "false"; + } else if constexpr (std::is_floating_point>() || + std::is_integral>()) { + return std::to_string(_val); + } else { + static_assert(always_false_v, "Unsupported type"); + } + } + + public: + Ref root_; + + std::string root_name_; +}; + +} // namespace xml +} // namespace rfl + +#endif // XML_PARSER_HPP_ diff --git a/include/rfl/xml/load.hpp b/include/rfl/xml/load.hpp new file mode 100644 index 0000000..861f8c4 --- /dev/null +++ b/include/rfl/xml/load.hpp @@ -0,0 +1,22 @@ +#ifndef RFL_XML_LOAD_HPP_ +#define RFL_XML_LOAD_HPP_ + +#include "../Result.hpp" +#include "../io/load_string.hpp" +#include "read.hpp" + +namespace rfl { +namespace xml { + +template +Result load(const std::string& _fname) { + const auto read_string = [](const auto& _str) { + return read(_str); + }; + return rfl::io::load_string(_fname).and_then(read_string); +} + +} // namespace xml +} // namespace rfl + +#endif diff --git a/include/rfl/xml/read.hpp b/include/rfl/xml/read.hpp new file mode 100644 index 0000000..e20d4c5 --- /dev/null +++ b/include/rfl/xml/read.hpp @@ -0,0 +1,50 @@ +#ifndef RFL_XML_READ_HPP_ +#define RFL_XML_READ_HPP_ + +#include +#include +#include + +#include "../Processors.hpp" +#include "../internal/get_type_name.hpp" +#include "../internal/remove_namespaces.hpp" +#include "Parser.hpp" +#include "Reader.hpp" + +namespace rfl { +namespace xml { + +using InputVarType = typename Reader::InputVarType; + +/// Parses an object from a XML var. +template +auto read(const InputVarType& _var) { + const auto r = Reader(); + return Parser>::read(r, _var); +} + +/// Parses an object from XML using reflection. +template +Result read(const std::string& _xml_str) { + pugi::xml_document doc; + const auto result = doc.load_string(_xml_str.c_str()); + if (!result) { + return Error("XML string could not be parsed: " + + std::string(result.description())); + } + const auto var = InputVarType(doc.first_child()); + return read(var); +} + +/// Parses an object from a stringstream. +template +auto read(std::istream& _stream) { + const auto xml_str = std::string(std::istreambuf_iterator(_stream), + std::istreambuf_iterator()); + return read(xml_str); +} + +} // namespace xml +} // namespace rfl + +#endif diff --git a/include/rfl/xml/save.hpp b/include/rfl/xml/save.hpp new file mode 100644 index 0000000..48c3e5c --- /dev/null +++ b/include/rfl/xml/save.hpp @@ -0,0 +1,28 @@ +#ifndef RFL_XML_SAVE_HPP_ +#define RFL_XML_SAVE_HPP_ + +#include +#include +#include + +#include "../Result.hpp" +#include "../internal/StringLiteral.hpp" +#include "../io/save_string.hpp" +#include "write.hpp" + +namespace rfl { +namespace xml { + +template +Result save(const std::string& _fname, const auto& _obj) { + const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { + return write<_root, Ps...>(_obj, _stream); + }; + return rfl::io::save_string(_fname, _obj, write_func); +} + +} // namespace xml +} // namespace rfl + +#endif diff --git a/include/rfl/xml/write.hpp b/include/rfl/xml/write.hpp new file mode 100644 index 0000000..023c757 --- /dev/null +++ b/include/rfl/xml/write.hpp @@ -0,0 +1,74 @@ +#ifndef RFL_XML_WRITE_HPP_ +#define RFL_XML_WRITE_HPP_ + +#include +#include +#include +#include +#include + +#include "../Processors.hpp" +#include "../internal/StringLiteral.hpp" +#include "../internal/get_type_name.hpp" +#include "../internal/remove_namespaces.hpp" +#include "../parsing/Parent.hpp" +#include "Parser.hpp" + +namespace rfl { +namespace xml { + +template +consteval auto get_root_name() { + if constexpr (_root != internal::StringLiteral("")) { + return _root; + } else { + return internal::remove_namespaces< + internal::get_type_name>()>(); + } +} + +/// Writes a XML into an ostream. +template +std::ostream& write(const auto& _obj, std::ostream& _stream, + const std::string& _indent = " ") { + using T = std::remove_cvref_t; + using ParentType = parsing::Parent; + + constexpr auto root_name = get_root_name<_root, T>(); + + static_assert(root_name.string_view().find("<") == std::string_view::npos && + root_name.string_view().find(">") == std::string_view::npos, + "The name of an XML root node cannot contain '<' or '>'. " + "Please assign an " + "explicit root name to rfl::xml::write(...) like this: " + "rfl::xml::write<\"root_name\">(...)."); + + const auto doc = rfl::Ref::make(); + + auto declaration_node = doc->append_child(pugi::node_declaration); + declaration_node.append_attribute("version") = "1.0"; + declaration_node.append_attribute("encoding") = "UTF-8"; + + auto w = Writer(doc, root_name.str()); + + Parser>::write(w, _obj, typename ParentType::Root{}); + + doc->save(_stream, _indent.c_str()); + + return _stream; +} + +/// Returns a XML string. +template +std::string write(const auto& _obj, const std::string& _indent = " ") { + std::stringstream stream; + write<_root, Ps...>(_obj, stream); + return stream.str(); +} + +} // namespace xml +} // namespace rfl + +#endif // XML_PARSER_HPP_ diff --git a/include/rfl/yaml.hpp b/include/rfl/yaml.hpp new file mode 100644 index 0000000..11cb13e --- /dev/null +++ b/include/rfl/yaml.hpp @@ -0,0 +1,13 @@ +#ifndef RFL_YAML_HPP_ +#define RFL_YAML_HPP_ + +#include "../rfl.hpp" +#include "yaml/Parser.hpp" +#include "yaml/Reader.hpp" +#include "yaml/Writer.hpp" +#include "yaml/load.hpp" +#include "yaml/read.hpp" +#include "yaml/save.hpp" +#include "yaml/write.hpp" + +#endif diff --git a/include/rfl/yaml/Parser.hpp b/include/rfl/yaml/Parser.hpp new file mode 100644 index 0000000..78ef335 --- /dev/null +++ b/include/rfl/yaml/Parser.hpp @@ -0,0 +1,17 @@ +#ifndef RFL_YAML_PARSER_HPP_ +#define RFL_YAML_PARSER_HPP_ + +#include "../parsing/Parser.hpp" +#include "Reader.hpp" +#include "Writer.hpp" + +namespace rfl { +namespace yaml { + +template +using Parser = parsing::Parser; + +} +} // namespace rfl + +#endif diff --git a/include/rfl/yaml/Reader.hpp b/include/rfl/yaml/Reader.hpp new file mode 100644 index 0000000..ab950ce --- /dev/null +++ b/include/rfl/yaml/Reader.hpp @@ -0,0 +1,137 @@ +#ifndef RFL_YAML_READER_HPP_ +#define RFL_YAML_READER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace yaml { + +struct Reader { + struct YAMLInputArray { + YAMLInputArray(const YAML::Node& _node) : node_(_node) {} + YAML::Node node_; + }; + + struct YAMLInputObject { + YAMLInputObject(const YAML::Node& _node) : node_(_node) {} + YAML::Node node_; + }; + + struct YAMLInputVar { + YAMLInputVar(const YAML::Node& _node) : node_(_node) {} + YAML::Node node_; + }; + + using InputArrayType = YAMLInputArray; + using InputObjectType = YAMLInputObject; + using InputVarType = YAMLInputVar; + + template + struct has_from_json_obj : std::false_type {}; + + template + static constexpr bool has_custom_constructor = (requires(InputVarType var) { + T::from_yaml_obj(var); + }); + + rfl::Result get_field( + const std::string& _name, const InputObjectType& _obj) const noexcept { + auto var = InputVarType(_obj.node_[_name]); + if (!var.node_) { + return rfl::Error("Object contains no field named '" + _name + "'."); + } + return var; + } + + bool is_empty(const InputVarType& _var) const noexcept { + return !_var.node_ && true; + } + + template + rfl::Result to_basic_type(const InputVarType& _var) const noexcept { + try { + if constexpr (std::is_same, std::string>() || + std::is_same, bool>() || + std::is_floating_point>() || + std::is_integral>()) { + return _var.node_.as>(); + } else { + static_assert(rfl::always_false_v, "Unsupported type."); + } + } catch (std::exception& e) { + return rfl::Error(e.what()); + } + } + + rfl::Result to_array( + const InputVarType& _var) const noexcept { + if (!_var.node_.IsSequence()) { + return rfl::Error("Could not cast to sequence!"); + } + return InputArrayType(_var.node_); + } + + template + std::optional read_array(const ArrayReader& _array_reader, + const InputArrayType& _arr) const noexcept { + for (size_t i = 0; i < _arr.node_.size(); ++i) { + const auto err = _array_reader.read(_arr.node_[i]); + if (err) { + return err; + } + } + return std::nullopt; + } + + template + std::optional read_object(const ObjectReader& _object_reader, + const InputObjectType& _obj) const noexcept { + for (const auto& p : _obj.node_) { + try { + const auto k = p.first.as(); + _object_reader.read(std::string_view(k), InputVarType(p.second)); + } catch (std::exception& e) { + continue; + } + } + return std::nullopt; + } + + rfl::Result to_object( + const InputVarType& _var) const noexcept { + if (!_var.node_.IsMap()) { + return rfl::Error("Could not cast to map!"); + } + return InputObjectType(_var.node_); + } + + template + rfl::Result use_custom_constructor( + const InputVarType _var) const noexcept { + try { + return T::from_yaml_obj(_var); + } catch (std::exception& e) { + return rfl::Error(e.what()); + } + } +}; + +} // namespace yaml +} // namespace rfl + +#endif diff --git a/include/rfl/yaml/Writer.hpp b/include/rfl/yaml/Writer.hpp new file mode 100644 index 0000000..c55d88e --- /dev/null +++ b/include/rfl/yaml/Writer.hpp @@ -0,0 +1,148 @@ +#ifndef RFL_YAML_WRITER_HPP_ +#define RFL_YAML_WRITER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Ref.hpp" +#include "../Result.hpp" +#include "../always_false.hpp" + +namespace rfl { +namespace yaml { + +class Writer { + public: + struct YAMLArray {}; + + struct YAMLObject {}; + + struct YAMLVar {}; + + using OutputArrayType = YAMLArray; + using OutputObjectType = YAMLObject; + using OutputVarType = YAMLVar; + + Writer(const Ref& _out) : out_(_out) {} + + ~Writer() = default; + + OutputArrayType array_as_root(const size_t _size) const noexcept { + return new_array(); + } + + OutputObjectType object_as_root(const size_t _size) const noexcept { + return new_object(); + } + + OutputVarType null_as_root() const noexcept { + return insert_value(YAML::Null); + } + + template + OutputVarType value_as_root(const T& _var) const noexcept { + return insert_value(_var); + } + + OutputArrayType add_array_to_array(const size_t _size, + OutputArrayType* _parent) const noexcept { + return new_array(); + } + + OutputArrayType add_array_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + return new_array(_name); + } + + OutputObjectType add_object_to_array( + const size_t _size, OutputArrayType* _parent) const noexcept { + return new_object(); + } + + OutputObjectType add_object_to_object( + const std::string_view& _name, const size_t _size, + OutputObjectType* _parent) const noexcept { + return new_object(_name); + } + + template + OutputVarType add_value_to_array(const T& _var, + OutputArrayType* _parent) const noexcept { + return insert_value(_var); + } + + template + OutputVarType add_value_to_object(const std::string_view& _name, + const T& _var, + OutputObjectType* _parent) const noexcept { + return insert_value(_name, _var); + } + + OutputVarType add_null_to_array(OutputArrayType* _parent) const noexcept { + return insert_value(YAML::Null); + } + + OutputVarType add_null_to_object(const std::string_view& _name, + OutputObjectType* _parent) const noexcept { + return insert_value(_name, YAML::Null); + } + + void end_array(OutputArrayType* _arr) const noexcept { + (*out_) << YAML::EndSeq; + } + + void end_object(OutputObjectType* _obj) const noexcept { + (*out_) << YAML::EndMap; + } + + private: + template + OutputVarType insert_value(const std::string_view& _name, + const T& _var) const noexcept { + (*out_) << YAML::Key << _name.data() << YAML::Value << _var; + return OutputVarType{}; + } + + template + OutputVarType insert_value(const T& _var) const noexcept { + (*out_) << _var; + return OutputVarType{}; + } + + OutputArrayType new_array(const std::string_view& _name) const noexcept { + (*out_) << YAML::Key << _name.data() << YAML::Value << YAML::BeginSeq; + return OutputArrayType{}; + } + + OutputArrayType new_array() const noexcept { + (*out_) << YAML::BeginSeq; + return OutputArrayType{}; + } + + OutputObjectType new_object(const std::string_view& _name) const noexcept { + (*out_) << YAML::Key << _name.data() << YAML::Value << YAML::BeginMap; + return OutputObjectType{}; + } + + OutputObjectType new_object() const noexcept { + (*out_) << YAML::BeginMap; + return OutputObjectType{}; + } + + public: + const Ref out_; +}; + +} // namespace yaml +} // namespace rfl + +#endif // JSON_PARSER_HPP_ diff --git a/include/rfl/yaml/load.hpp b/include/rfl/yaml/load.hpp new file mode 100644 index 0000000..7f3fa92 --- /dev/null +++ b/include/rfl/yaml/load.hpp @@ -0,0 +1,22 @@ +#ifndef RFL_YAML_LOAD_HPP_ +#define RFL_YAML_LOAD_HPP_ + +#include "../Result.hpp" +#include "../io/load_string.hpp" +#include "read.hpp" + +namespace rfl { +namespace yaml { + +template +Result load(const std::string& _fname) { + const auto read_string = [](const auto& _str) { + return read(_str); + }; + return rfl::io::load_string(_fname).and_then(read_string); +} + +} // namespace yaml +} // namespace rfl + +#endif diff --git a/include/rfl/yaml/read.hpp b/include/rfl/yaml/read.hpp new file mode 100644 index 0000000..0d00eb6 --- /dev/null +++ b/include/rfl/yaml/read.hpp @@ -0,0 +1,47 @@ +#ifndef RFL_YAML_READ_HPP_ +#define RFL_YAML_READ_HPP_ + +#include + +#include +#include + +#include "../Processors.hpp" +#include "../internal/wrap_in_rfl_array_t.hpp" +#include "Parser.hpp" +#include "Reader.hpp" +namespace rfl { +namespace yaml { + +using InputVarType = typename Reader::InputVarType; + +/// Parses an object from a YAML var. +template +auto read(const InputVarType& _var) { + const auto r = Reader(); + return Parser>::read(r, _var); +} + +/// Parses an object from YAML using reflection. +template +Result> read(const std::string& _yaml_str) { + try { + const auto var = InputVarType(YAML::Load(_yaml_str)); + return read(var); + } catch (std::exception& e) { + return Error(e.what()); + } +} + +/// Parses an object from a stringstream. +template +auto read(std::istream& _stream) { + const auto yaml_str = std::string(std::istreambuf_iterator(_stream), + std::istreambuf_iterator()); + return read(yaml_str); +} + +} // namespace yaml +} // namespace rfl + +#endif diff --git a/include/rfl/yaml/save.hpp b/include/rfl/yaml/save.hpp new file mode 100644 index 0000000..6333c99 --- /dev/null +++ b/include/rfl/yaml/save.hpp @@ -0,0 +1,27 @@ +#ifndef RFL_YAML_SAVE_HPP_ +#define RFL_YAML_SAVE_HPP_ + +#include +#include +#include + +#include "../Processors.hpp" +#include "../Result.hpp" +#include "../io/save_string.hpp" +#include "write.hpp" + +namespace rfl { +namespace yaml { + +template +Result save(const std::string& _fname, const auto& _obj) { + const auto write_func = [](const auto& _obj, auto& _stream) -> auto& { + return write(_obj, _stream); + }; + return rfl::io::save_string(_fname, _obj, write_func); +} + +} // namespace yaml +} // namespace rfl + +#endif diff --git a/include/rfl/yaml/write.hpp b/include/rfl/yaml/write.hpp new file mode 100644 index 0000000..f6613ce --- /dev/null +++ b/include/rfl/yaml/write.hpp @@ -0,0 +1,44 @@ +#ifndef RFL_YAML_WRITE_HPP_ +#define RFL_YAML_WRITE_HPP_ + +#include + +#include +#include +#include +#include + +#include "../Processors.hpp" +#include "../parsing/Parent.hpp" +#include "Parser.hpp" + +namespace rfl { +namespace yaml { + +/// Writes a YAML into an ostream. +template +std::ostream& write(const auto& _obj, std::ostream& _stream) { + using T = std::remove_cvref_t; + using ParentType = parsing::Parent; + const auto out = Ref::make(); + auto w = Writer(out); + Parser>::write(w, _obj, typename ParentType::Root{}); + _stream << out->c_str(); + return _stream; +} + +/// Returns a YAML string. +template +std::string write(const auto& _obj) { + using T = std::remove_cvref_t; + using ParentType = parsing::Parent; + const auto out = Ref::make(); + auto w = Writer(out); + Parser>::write(w, _obj, typename ParentType::Root{}); + return out->c_str(); +} + +} // namespace yaml +} // namespace rfl + +#endif diff --git a/include/yyjson.h b/include/yyjson.h new file mode 100644 index 0000000..7b3a5b7 --- /dev/null +++ b/include/yyjson.h @@ -0,0 +1,7690 @@ +/*============================================================================== + * Created by Yaoyuan on 2019/3/9. + * Copyright (C) 2019 Yaoyuan . + * + * Released under the MIT License: + * https://github.com/ibireme/yyjson/blob/master/LICENSE + *============================================================================*/ + +/** @file yyjson.h */ + +#ifndef YYJSON_H +#define YYJSON_H + + + +/*============================================================================== + * Header Files + *============================================================================*/ + +#include +#include +#include +#include +#include +#include + + + +/*============================================================================== + * Compile-time Options + *============================================================================*/ + +/* + Define as 1 to disable JSON reader if JSON parsing is not required. + + This will disable these functions at compile-time: + - yyjson_read_opts() + - yyjson_read_file() + - yyjson_read() + - yyjson_read_number() + - yyjson_mut_read_number() + + This will reduce the binary size by about 60%. + */ +#ifndef YYJSON_DISABLE_READER +#endif + +/* + Define as 1 to disable JSON writer if JSON serialization is not required. + + This will disable these functions at compile-time: + - yyjson_write() + - yyjson_write_file() + - yyjson_write_opts() + - yyjson_val_write() + - yyjson_val_write_file() + - yyjson_val_write_opts() + - yyjson_mut_write() + - yyjson_mut_write_file() + - yyjson_mut_write_opts() + - yyjson_mut_val_write() + - yyjson_mut_val_write_file() + - yyjson_mut_val_write_opts() + + This will reduce the binary size by about 30%. + */ +#ifndef YYJSON_DISABLE_WRITER +#endif + +/* + Define as 1 to disable JSON Pointer, JSON Patch and JSON Merge Patch supports. + + This will disable these functions at compile-time: + - yyjson_ptr_xxx() + - yyjson_mut_ptr_xxx() + - yyjson_doc_ptr_xxx() + - yyjson_mut_doc_ptr_xxx() + - yyjson_patch() + - yyjson_mut_patch() + - yyjson_merge_patch() + - yyjson_mut_merge_patch() + */ +#ifndef YYJSON_DISABLE_UTILS +#endif + +/* + Define as 1 to disable the fast floating-point number conversion in yyjson, + and use libc's `strtod/snprintf` instead. + + This will reduce the binary size by about 30%, but significantly slow down the + floating-point read/write speed. + */ +#ifndef YYJSON_DISABLE_FAST_FP_CONV +#endif + +/* + Define as 1 to disable non-standard JSON support at compile-time: + - Reading and writing inf/nan literal, such as `NaN`, `-Infinity`. + - Single line and multiple line comments. + - Single trailing comma at the end of an object or array. + - Invalid unicode in string value. + + This will also invalidate these run-time options: + - YYJSON_READ_ALLOW_INF_AND_NAN + - YYJSON_READ_ALLOW_COMMENTS + - YYJSON_READ_ALLOW_TRAILING_COMMAS + - YYJSON_READ_ALLOW_INVALID_UNICODE + - YYJSON_WRITE_ALLOW_INF_AND_NAN + - YYJSON_WRITE_ALLOW_INVALID_UNICODE + + This will reduce the binary size by about 10%, and slightly improve the JSON + read/write speed. + */ +#ifndef YYJSON_DISABLE_NON_STANDARD +#endif + +/* + Define as 1 to disable unaligned memory access if target architecture does not + support unaligned memory access (such as some embedded processors). + + If this value is not defined, yyjson will perform some automatic detection. + The wrong definition of this option may cause some performance degradation, + but will not cause any run-time errors. + */ +#ifndef YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS +#endif + +/* Define as 1 to export symbols when building this library as Windows DLL. */ +#ifndef YYJSON_EXPORTS +#endif + +/* Define as 1 to import symbols when using this library as Windows DLL. */ +#ifndef YYJSON_IMPORTS +#endif + +/* Define as 1 to include for compiler which doesn't support C99. */ +#ifndef YYJSON_HAS_STDINT_H +#endif + +/* Define as 1 to include for compiler which doesn't support C99. */ +#ifndef YYJSON_HAS_STDBOOL_H +#endif + + + +/*============================================================================== + * Compiler Macros + *============================================================================*/ + +/** compiler version (MSVC) */ +#ifdef _MSC_VER +# define YYJSON_MSC_VER _MSC_VER +#else +# define YYJSON_MSC_VER 0 +#endif + +/** compiler version (GCC) */ +#ifdef __GNUC__ +# define YYJSON_GCC_VER __GNUC__ +#else +# define YYJSON_GCC_VER 0 +#endif + +/** C version (STDC) */ +#if defined(__STDC__) && (__STDC__ >= 1) && defined(__STDC_VERSION__) +# define YYJSON_STDC_VER __STDC_VERSION__ +#else +# define YYJSON_STDC_VER 0 +#endif + +/** C++ version */ +#if defined(__cplusplus) +# define YYJSON_CPP_VER __cplusplus +#else +# define YYJSON_CPP_VER 0 +#endif + +/** compiler builtin check (since gcc 10.0, clang 2.6, icc 2021) */ +#ifndef yyjson_has_builtin +# ifdef __has_builtin +# define yyjson_has_builtin(x) __has_builtin(x) +# else +# define yyjson_has_builtin(x) 0 +# endif +#endif + +/** compiler attribute check (since gcc 5.0, clang 2.9, icc 17) */ +#ifndef yyjson_has_attribute +# ifdef __has_attribute +# define yyjson_has_attribute(x) __has_attribute(x) +# else +# define yyjson_has_attribute(x) 0 +# endif +#endif + +/** compiler feature check (since clang 2.6, icc 17) */ +#ifndef yyjson_has_feature +# ifdef __has_feature +# define yyjson_has_feature(x) __has_feature(x) +# else +# define yyjson_has_feature(x) 0 +# endif +#endif + +/** include check (since gcc 5.0, clang 2.7, icc 16, msvc 2017 15.3) */ +#ifndef yyjson_has_include +# ifdef __has_include +# define yyjson_has_include(x) __has_include(x) +# else +# define yyjson_has_include(x) 0 +# endif +#endif + +/** inline for compiler */ +#ifndef yyjson_inline +# if YYJSON_MSC_VER >= 1200 +# define yyjson_inline __forceinline +# elif defined(_MSC_VER) +# define yyjson_inline __inline +# elif yyjson_has_attribute(always_inline) || YYJSON_GCC_VER >= 4 +# define yyjson_inline __inline__ __attribute__((always_inline)) +# elif defined(__clang__) || defined(__GNUC__) +# define yyjson_inline __inline__ +# elif defined(__cplusplus) || YYJSON_STDC_VER >= 199901L +# define yyjson_inline inline +# else +# define yyjson_inline +# endif +#endif + +/** noinline for compiler */ +#ifndef yyjson_noinline +# if YYJSON_MSC_VER >= 1400 +# define yyjson_noinline __declspec(noinline) +# elif yyjson_has_attribute(noinline) || YYJSON_GCC_VER >= 4 +# define yyjson_noinline __attribute__((noinline)) +# else +# define yyjson_noinline +# endif +#endif + +/** align for compiler */ +#ifndef yyjson_align +# if YYJSON_MSC_VER >= 1300 +# define yyjson_align(x) __declspec(align(x)) +# elif yyjson_has_attribute(aligned) || defined(__GNUC__) +# define yyjson_align(x) __attribute__((aligned(x))) +# elif YYJSON_CPP_VER >= 201103L +# define yyjson_align(x) alignas(x) +# else +# define yyjson_align(x) +# endif +#endif + +/** likely for compiler */ +#ifndef yyjson_likely +# if yyjson_has_builtin(__builtin_expect) || \ + (YYJSON_GCC_VER >= 4 && YYJSON_GCC_VER != 5) +# define yyjson_likely(expr) __builtin_expect(!!(expr), 1) +# else +# define yyjson_likely(expr) (expr) +# endif +#endif + +/** unlikely for compiler */ +#ifndef yyjson_unlikely +# if yyjson_has_builtin(__builtin_expect) || \ + (YYJSON_GCC_VER >= 4 && YYJSON_GCC_VER != 5) +# define yyjson_unlikely(expr) __builtin_expect(!!(expr), 0) +# else +# define yyjson_unlikely(expr) (expr) +# endif +#endif + +/** deprecate warning */ +#ifndef yyjson_deprecated +# if YYJSON_MSC_VER >= 1400 +# define yyjson_deprecated(msg) __declspec(deprecated(msg)) +# elif yyjson_has_feature(attribute_deprecated_with_message) || \ + (YYJSON_GCC_VER > 4 || (YYJSON_GCC_VER == 4 && __GNUC_MINOR__ >= 5)) +# define yyjson_deprecated(msg) __attribute__((deprecated(msg))) +# elif YYJSON_GCC_VER >= 3 +# define yyjson_deprecated(msg) __attribute__((deprecated)) +# else +# define yyjson_deprecated(msg) +# endif +#endif + +/** function export */ +#ifndef yyjson_api +# if defined(_WIN32) +# if defined(YYJSON_EXPORTS) && YYJSON_EXPORTS +# define yyjson_api __declspec(dllexport) +# elif defined(YYJSON_IMPORTS) && YYJSON_IMPORTS +# define yyjson_api __declspec(dllimport) +# else +# define yyjson_api +# endif +# elif yyjson_has_attribute(visibility) || YYJSON_GCC_VER >= 4 +# define yyjson_api __attribute__((visibility("default"))) +# else +# define yyjson_api +# endif +#endif + +/** inline function export */ +#ifndef yyjson_api_inline +# define yyjson_api_inline static yyjson_inline +#endif + +/** stdint (C89 compatible) */ +#if (defined(YYJSON_HAS_STDINT_H) && YYJSON_HAS_STDINT_H) || \ + YYJSON_MSC_VER >= 1600 || YYJSON_STDC_VER >= 199901L || \ + defined(_STDINT_H) || defined(_STDINT_H_) || \ + defined(__CLANG_STDINT_H) || defined(_STDINT_H_INCLUDED) || \ + yyjson_has_include() +# include +#elif defined(_MSC_VER) +# if _MSC_VER < 1300 + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; +# else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; +# endif +#else +# if UCHAR_MAX == 0xFFU + typedef signed char int8_t; + typedef unsigned char uint8_t; +# else +# error cannot find 8-bit integer type +# endif +# if USHRT_MAX == 0xFFFFU + typedef unsigned short uint16_t; + typedef signed short int16_t; +# elif UINT_MAX == 0xFFFFU + typedef unsigned int uint16_t; + typedef signed int int16_t; +# else +# error cannot find 16-bit integer type +# endif +# if UINT_MAX == 0xFFFFFFFFUL + typedef unsigned int uint32_t; + typedef signed int int32_t; +# elif ULONG_MAX == 0xFFFFFFFFUL + typedef unsigned long uint32_t; + typedef signed long int32_t; +# elif USHRT_MAX == 0xFFFFFFFFUL + typedef unsigned short uint32_t; + typedef signed short int32_t; +# else +# error cannot find 32-bit integer type +# endif +# if defined(__INT64_TYPE__) && defined(__UINT64_TYPE__) + typedef __INT64_TYPE__ int64_t; + typedef __UINT64_TYPE__ uint64_t; +# elif defined(__GNUC__) || defined(__clang__) +# if !defined(_SYS_TYPES_H) && !defined(__int8_t_defined) + __extension__ typedef long long int64_t; +# endif + __extension__ typedef unsigned long long uint64_t; +# elif defined(_LONG_LONG) || defined(__MWERKS__) || defined(_CRAYC) || \ + defined(__SUNPRO_C) || defined(__SUNPRO_CC) + typedef long long int64_t; + typedef unsigned long long uint64_t; +# elif (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || \ + defined(__WATCOM_INT64__) || defined (__alpha) || defined (__DECC) + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +# else +# error cannot find 64-bit integer type +# endif +#endif + +/** stdbool (C89 compatible) */ +#if (defined(YYJSON_HAS_STDBOOL_H) && YYJSON_HAS_STDBOOL_H) || \ + (yyjson_has_include() && !defined(__STRICT_ANSI__)) || \ + YYJSON_MSC_VER >= 1800 || YYJSON_STDC_VER >= 199901L +# include +#elif !defined(__bool_true_false_are_defined) +# define __bool_true_false_are_defined 1 +# if defined(__cplusplus) +# if defined(__GNUC__) && !defined(__STRICT_ANSI__) +# define _Bool bool +# if __cplusplus < 201103L +# define bool bool +# define false false +# define true true +# endif +# endif +# else +# define bool unsigned char +# define true 1 +# define false 0 +# endif +#endif + +/** char bit check */ +#if defined(CHAR_BIT) +# if CHAR_BIT != 8 +# error non 8-bit char is not supported +# endif +#endif + +/** + Microsoft Visual C++ 6.0 doesn't support converting number from u64 to f64: + error C2520: conversion from unsigned __int64 to double not implemented. + */ +#ifndef YYJSON_U64_TO_F64_NO_IMPL +# if (0 < YYJSON_MSC_VER) && (YYJSON_MSC_VER <= 1200) +# define YYJSON_U64_TO_F64_NO_IMPL 1 +# else +# define YYJSON_U64_TO_F64_NO_IMPL 0 +# endif +#endif + + + +/*============================================================================== + * Compile Hint Begin + *============================================================================*/ + +/* extern "C" begin */ +#ifdef __cplusplus +extern "C" { +#endif + +/* warning suppress begin */ +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-function" +# pragma clang diagnostic ignored "-Wunused-parameter" +#elif defined(__GNUC__) +# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +# pragma GCC diagnostic push +# endif +# pragma GCC diagnostic ignored "-Wunused-function" +# pragma GCC diagnostic ignored "-Wunused-parameter" +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable:4800) /* 'int': forcing value to 'true' or 'false' */ +#endif + + + +/*============================================================================== + * Version + *============================================================================*/ + +/** The major version of yyjson. */ +#define YYJSON_VERSION_MAJOR 0 + +/** The minor version of yyjson. */ +#define YYJSON_VERSION_MINOR 7 + +/** The patch version of yyjson. */ +#define YYJSON_VERSION_PATCH 0 + +/** The version of yyjson in hex: `(major << 16) | (minor << 8) | (patch)`. */ +#define YYJSON_VERSION_HEX 0x000700 + +/** The version string of yyjson. */ +#define YYJSON_VERSION_STRING "0.7.0" + +/** The version of yyjson in hex, same as `YYJSON_VERSION_HEX`. */ +yyjson_api uint32_t yyjson_version(void); + + + +/*============================================================================== + * JSON Types + *============================================================================*/ + +/** Type of JSON value (3 bit). */ +typedef uint8_t yyjson_type; +#define YYJSON_TYPE_NONE ((uint8_t)0) /* _____000 */ +#define YYJSON_TYPE_RAW ((uint8_t)1) /* _____001 */ +#define YYJSON_TYPE_NULL ((uint8_t)2) /* _____010 */ +#define YYJSON_TYPE_BOOL ((uint8_t)3) /* _____011 */ +#define YYJSON_TYPE_NUM ((uint8_t)4) /* _____100 */ +#define YYJSON_TYPE_STR ((uint8_t)5) /* _____101 */ +#define YYJSON_TYPE_ARR ((uint8_t)6) /* _____110 */ +#define YYJSON_TYPE_OBJ ((uint8_t)7) /* _____111 */ + +/** Subtype of JSON value (2 bit). */ +typedef uint8_t yyjson_subtype; +#define YYJSON_SUBTYPE_NONE ((uint8_t)(0 << 3)) /* ___00___ */ +#define YYJSON_SUBTYPE_FALSE ((uint8_t)(0 << 3)) /* ___00___ */ +#define YYJSON_SUBTYPE_TRUE ((uint8_t)(1 << 3)) /* ___01___ */ +#define YYJSON_SUBTYPE_UINT ((uint8_t)(0 << 3)) /* ___00___ */ +#define YYJSON_SUBTYPE_SINT ((uint8_t)(1 << 3)) /* ___01___ */ +#define YYJSON_SUBTYPE_REAL ((uint8_t)(2 << 3)) /* ___10___ */ + +/** Mask and bits of JSON value tag. */ +#define YYJSON_TYPE_MASK ((uint8_t)0x07) /* _____111 */ +#define YYJSON_TYPE_BIT ((uint8_t)3) +#define YYJSON_SUBTYPE_MASK ((uint8_t)0x18) /* ___11___ */ +#define YYJSON_SUBTYPE_BIT ((uint8_t)2) +#define YYJSON_RESERVED_MASK ((uint8_t)0xE0) /* 111_____ */ +#define YYJSON_RESERVED_BIT ((uint8_t)3) +#define YYJSON_TAG_MASK ((uint8_t)0xFF) /* 11111111 */ +#define YYJSON_TAG_BIT ((uint8_t)8) + +/** Padding size for JSON reader. */ +#define YYJSON_PADDING_SIZE 4 + + + +/*============================================================================== + * Allocator + *============================================================================*/ + +/** + A memory allocator. + + Typically you don't need to use it, unless you want to customize your own + memory allocator. + */ +typedef struct yyjson_alc { + /** Same as libc's malloc(size), should not be NULL. */ + void *(*malloc)(void *ctx, size_t size); + /** Same as libc's realloc(ptr, size), should not be NULL. */ + void *(*realloc)(void *ctx, void *ptr, size_t old_size, size_t size); + /** Same as libc's free(ptr), should not be NULL. */ + void (*free)(void *ctx, void *ptr); + /** A context for malloc/realloc/free, can be NULL. */ + void *ctx; +} yyjson_alc; + +/** + A pool allocator uses fixed length pre-allocated memory. + + This allocator may be used to avoid malloc/realloc calls. The pre-allocated + memory should be held by the caller. The maximum amount of memory required to + read a JSON can be calculated using the `yyjson_read_max_memory_usage()` + function, but the amount of memory required to write a JSON cannot be directly + calculated. + + This is not a general-purpose allocator. If used to read multiple JSON + documents and only some of them are released, it may cause memory + fragmentation, leading to performance degradation and memory waste. Therefore, + it is recommended to use this allocator only for reading or writing a single + JSON document. + + @param alc The allocator to be initialized. + If this parameter is NULL, the function will fail and return false. + If `buf` or `size` is invalid, this will be set to an empty allocator. + @param buf The buffer memory for this allocator. + If this parameter is NULL, the function will fail and return false. + @param size The size of `buf`, in bytes. + If this parameter is less than 8 words (32/64 bytes on 32/64-bit OS), the + function will fail and return false. + @return true if the `alc` has been successfully initialized. + + @par Example + @code + // parse JSON with stack memory + char buf[1024]; + yyjson_alc alc; + yyjson_alc_pool_init(&alc, buf, 1024); + + const char *json = "{\"name\":\"Helvetica\",\"size\":16}" + yyjson_doc *doc = yyjson_read_opts(json, strlen(json), 0, &alc, NULL); + // the memory of `doc` is on the stack + @endcode + */ +yyjson_api bool yyjson_alc_pool_init(yyjson_alc *alc, void *buf, size_t size); + + + +/*============================================================================== + * JSON Structure + *============================================================================*/ + +/** + An immutable document for reading JSON. + This document holds memory for all its JSON values and strings. When it is no + longer used, the user should call `yyjson_doc_free()` to free its memory. + */ +typedef struct yyjson_doc yyjson_doc; + +/** + An immutable value for reading JSON. + A JSON Value has the same lifetime as its document. The memory is held by its + document and and cannot be freed alone. + */ +typedef struct yyjson_val yyjson_val; + +/** + A mutable document for building JSON. + This document holds memory for all its JSON values and strings. When it is no + longer used, the user should call `yyjson_mut_doc_free()` to free its memory. + */ +typedef struct yyjson_mut_doc yyjson_mut_doc; + +/** + A mutable value for building JSON. + A JSON Value has the same lifetime as its document. The memory is held by its + document and and cannot be freed alone. + */ +typedef struct yyjson_mut_val yyjson_mut_val; + + + +/*============================================================================== + * JSON Reader API + *============================================================================*/ + +/** Run-time options for JSON reader. */ +typedef uint32_t yyjson_read_flag; + +/** Default option (RFC 8259 compliant): + - Read positive integer as uint64_t. + - Read negative integer as int64_t. + - Read floating-point number as double with round-to-nearest mode. + - Read integer which cannot fit in uint64_t or int64_t as double. + - Report error if double number is infinity. + - Report error if string contains invalid UTF-8 character or BOM. + - Report error on trailing commas, comments, inf and nan literals. */ +static const yyjson_read_flag YYJSON_READ_NOFLAG = 0 << 0; + +/** Read the input data in-situ. + This option allows the reader to modify and use input data to store string + values, which can increase reading speed slightly. + The caller should hold the input data before free the document. + The input data must be padded by at least `YYJSON_PADDING_SIZE` bytes. + For example: `[1,2]` should be `[1,2]\0\0\0\0`, input length should be 5. */ +static const yyjson_read_flag YYJSON_READ_INSITU = 1 << 0; + +/** Stop when done instead of issuing an error if there's additional content + after a JSON document. This option may be used to parse small pieces of JSON + in larger data, such as `NDJSON`. */ +static const yyjson_read_flag YYJSON_READ_STOP_WHEN_DONE = 1 << 1; + +/** Allow single trailing comma at the end of an object or array, + such as `[1,2,3,]`, `{"a":1,"b":2,}` (non-standard). */ +static const yyjson_read_flag YYJSON_READ_ALLOW_TRAILING_COMMAS = 1 << 2; + +/** Allow C-style single line and multiple line comments (non-standard). */ +static const yyjson_read_flag YYJSON_READ_ALLOW_COMMENTS = 1 << 3; + +/** Allow inf/nan number and literal, case-insensitive, + such as 1e999, NaN, inf, -Infinity (non-standard). */ +static const yyjson_read_flag YYJSON_READ_ALLOW_INF_AND_NAN = 1 << 4; + +/** Read all numbers as raw strings (value with `YYJSON_TYPE_RAW` type), + inf/nan literal is also read as raw with `ALLOW_INF_AND_NAN` flag. */ +static const yyjson_read_flag YYJSON_READ_NUMBER_AS_RAW = 1 << 5; + +/** Allow reading invalid unicode when parsing string values (non-standard). + Invalid characters will be allowed to appear in the string values, but + invalid escape sequences will still be reported as errors. + This flag does not affect the performance of correctly encoded strings. + + @warning Strings in JSON values may contain incorrect encoding when this + option is used, you need to handle these strings carefully to avoid security + risks. */ +static const yyjson_read_flag YYJSON_READ_ALLOW_INVALID_UNICODE = 1 << 6; + +/** Read big numbers as raw strings. These big numbers include integers that + cannot be represented by `int64_t` and `uint64_t`, and floating-point + numbers that cannot be represented by finite `double`. + The flag will be overridden by `YYJSON_READ_NUMBER_AS_RAW` flag. */ +static const yyjson_read_flag YYJSON_READ_BIGNUM_AS_RAW = 1 << 7; + + + +/** Result code for JSON reader. */ +typedef uint32_t yyjson_read_code; + +/** Success, no error. */ +static const yyjson_read_code YYJSON_READ_SUCCESS = 0; + +/** Invalid parameter, such as NULL input string or 0 input length. */ +static const yyjson_read_code YYJSON_READ_ERROR_INVALID_PARAMETER = 1; + +/** Memory allocation failure occurs. */ +static const yyjson_read_code YYJSON_READ_ERROR_MEMORY_ALLOCATION = 2; + +/** Input JSON string is empty. */ +static const yyjson_read_code YYJSON_READ_ERROR_EMPTY_CONTENT = 3; + +/** Unexpected content after document, such as `[123]abc`. */ +static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CONTENT = 4; + +/** Unexpected ending, such as `[123`. */ +static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_END = 5; + +/** Unexpected character inside the document, such as `[abc]`. */ +static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CHARACTER = 6; + +/** Invalid JSON structure, such as `[1,]`. */ +static const yyjson_read_code YYJSON_READ_ERROR_JSON_STRUCTURE = 7; + +/** Invalid comment, such as unclosed multi-line comment. */ +static const yyjson_read_code YYJSON_READ_ERROR_INVALID_COMMENT = 8; + +/** Invalid number, such as `123.e12`, `000`. */ +static const yyjson_read_code YYJSON_READ_ERROR_INVALID_NUMBER = 9; + +/** Invalid string, such as invalid escaped character inside a string. */ +static const yyjson_read_code YYJSON_READ_ERROR_INVALID_STRING = 10; + +/** Invalid JSON literal, such as `truu`. */ +static const yyjson_read_code YYJSON_READ_ERROR_LITERAL = 11; + +/** Failed to open a file. */ +static const yyjson_read_code YYJSON_READ_ERROR_FILE_OPEN = 12; + +/** Failed to read a file. */ +static const yyjson_read_code YYJSON_READ_ERROR_FILE_READ = 13; + +/** Error information for JSON reader. */ +typedef struct yyjson_read_err { + /** Error code, see `yyjson_read_code` for all possible values. */ + yyjson_read_code code; + /** Error message, constant, no need to free (NULL if success). */ + const char *msg; + /** Error byte position for input data (0 if success). */ + size_t pos; +} yyjson_read_err; + + + +/** + Read JSON with options. + + This function is thread-safe when: + 1. The `dat` is not modified by other threads. + 2. The `alc` is thread-safe or NULL. + + @param dat The JSON data (UTF-8 without BOM), null-terminator is not required. + If this parameter is NULL, the function will fail and return NULL. + The `dat` will not be modified without the flag `YYJSON_READ_INSITU`, so you + can pass a `const char *` string and case it to `char *` if you don't use + the `YYJSON_READ_INSITU` flag. + @param len The length of JSON data in bytes. + If this parameter is 0, the function will fail and return NULL. + @param flg The JSON read options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON reader. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return A new JSON document, or NULL if an error occurs. + When it's no longer needed, it should be freed with `yyjson_doc_free()`. + */ +yyjson_api yyjson_doc *yyjson_read_opts(char *dat, + size_t len, + yyjson_read_flag flg, + const yyjson_alc *alc, + yyjson_read_err *err); + +/** + Read a JSON file. + + This function is thread-safe when: + 1. The file is not modified by other threads. + 2. The `alc` is thread-safe or NULL. + + @param path The JSON file's path. + If this path is NULL or invalid, the function will fail and return NULL. + @param flg The JSON read options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON reader. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return A new JSON document, or NULL if an error occurs. + When it's no longer needed, it should be freed with `yyjson_doc_free()`. + + @warning On 32-bit operating system, files larger than 2GB may fail to read. + */ +yyjson_api yyjson_doc *yyjson_read_file(const char *path, + yyjson_read_flag flg, + const yyjson_alc *alc, + yyjson_read_err *err); + +/** + Read JSON from a file pointer. + + @param fp The file pointer. + The data will be read from the current position of the FILE to the end. + If this fp is NULL or invalid, the function will fail and return NULL. + @param flg The JSON read options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON reader. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return A new JSON document, or NULL if an error occurs. + When it's no longer needed, it should be freed with `yyjson_doc_free()`. + + @warning On 32-bit operating system, files larger than 2GB may fail to read. + */ +yyjson_api yyjson_doc *yyjson_read_fp(FILE *fp, + yyjson_read_flag flg, + const yyjson_alc *alc, + yyjson_read_err *err); + +/** + Read a JSON string. + + This function is thread-safe. + + @param dat The JSON data (UTF-8 without BOM), null-terminator is not required. + If this parameter is NULL, the function will fail and return NULL. + @param len The length of JSON data in bytes. + If this parameter is 0, the function will fail and return NULL. + @param flg The JSON read options. + Multiple options can be combined with `|` operator. 0 means no options. + @return A new JSON document, or NULL if an error occurs. + When it's no longer needed, it should be freed with `yyjson_doc_free()`. + */ +yyjson_api_inline yyjson_doc *yyjson_read(const char *dat, + size_t len, + yyjson_read_flag flg) { + flg &= ~YYJSON_READ_INSITU; /* const string cannot be modified */ + return yyjson_read_opts((char *)(void *)(size_t)(const void *)dat, + len, flg, NULL, NULL); +} + +/** + Returns the size of maximum memory usage to read a JSON data. + + You may use this value to avoid malloc() or calloc() call inside the reader + to get better performance, or read multiple JSON with one piece of memory. + + @param len The length of JSON data in bytes. + @param flg The JSON read options. + @return The maximum memory size to read this JSON, or 0 if overflow. + + @par Example + @code + // read multiple JSON with same pre-allocated memory + + char *dat1, *dat2, *dat3; // JSON data + size_t len1, len2, len3; // JSON length + size_t max_len = MAX(len1, MAX(len2, len3)); + yyjson_doc *doc; + + // use one allocator for multiple JSON + size_t size = yyjson_read_max_memory_usage(max_len, 0); + void *buf = malloc(size); + yyjson_alc alc; + yyjson_alc_pool_init(&alc, buf, size); + + // no more alloc() or realloc() call during reading + doc = yyjson_read_opts(dat1, len1, 0, &alc, NULL); + yyjson_doc_free(doc); + doc = yyjson_read_opts(dat2, len2, 0, &alc, NULL); + yyjson_doc_free(doc); + doc = yyjson_read_opts(dat3, len3, 0, &alc, NULL); + yyjson_doc_free(doc); + + free(buf); + @endcode + @see yyjson_alc_pool_init() + */ +yyjson_api_inline size_t yyjson_read_max_memory_usage(size_t len, + yyjson_read_flag flg) { + /* + 1. The max value count is (json_size / 2 + 1), + for example: "[1,2,3,4]" size is 9, value count is 5. + 2. Some broken JSON may cost more memory during reading, but fail at end, + for example: "[[[[[[[[". + 3. yyjson use 16 bytes per value, see struct yyjson_val. + 4. yyjson use dynamic memory with a growth factor of 1.5. + + The max memory size is (json_size / 2 * 16 * 1.5 + padding). + */ + size_t mul = (size_t)12 + !(flg & YYJSON_READ_INSITU); + size_t pad = 256; + size_t max = (size_t)(~(size_t)0); + if (flg & YYJSON_READ_STOP_WHEN_DONE) len = len < 256 ? 256 : len; + if (len >= (max - pad - mul) / mul) return 0; + return len * mul + pad; +} + +/** + Read a JSON number. + + This function is thread-safe when data is not modified by other threads. + + @param dat The JSON data (UTF-8 without BOM), null-terminator is required. + If this parameter is NULL, the function will fail and return NULL. + @param val The output value where result is stored. + If this parameter is NULL, the function will fail and return NULL. + The value will hold either UINT or SINT or REAL number; + @param flg The JSON read options. + Multiple options can be combined with `|` operator. 0 means no options. + Supports `YYJSON_READ_NUMBER_AS_RAW` and `YYJSON_READ_ALLOW_INF_AND_NAN`. + @param alc The memory allocator used for long number. + It is only used when the built-in floating point reader is disabled. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return If successful, a pointer to the character after the last character + used in the conversion, NULL if an error occurs. + */ +yyjson_api const char *yyjson_read_number(const char *dat, + yyjson_val *val, + yyjson_read_flag flg, + const yyjson_alc *alc, + yyjson_read_err *err); + +/** + Read a JSON number. + + This function is thread-safe when data is not modified by other threads. + + @param dat The JSON data (UTF-8 without BOM), null-terminator is required. + If this parameter is NULL, the function will fail and return NULL. + @param val The output value where result is stored. + If this parameter is NULL, the function will fail and return NULL. + The value will hold either UINT or SINT or REAL number; + @param flg The JSON read options. + Multiple options can be combined with `|` operator. 0 means no options. + Supports `YYJSON_READ_NUMBER_AS_RAW` and `YYJSON_READ_ALLOW_INF_AND_NAN`. + @param alc The memory allocator used for long number. + It is only used when the built-in floating point reader is disabled. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return If successful, a pointer to the character after the last character + used in the conversion, NULL if an error occurs. + */ +yyjson_api_inline const char *yyjson_mut_read_number(const char *dat, + yyjson_mut_val *val, + yyjson_read_flag flg, + const yyjson_alc *alc, + yyjson_read_err *err) { + return yyjson_read_number(dat, (yyjson_val *)val, flg, alc, err); +} + + +/*============================================================================== + * JSON Writer API + *============================================================================*/ + +/** Run-time options for JSON writer. */ +typedef uint32_t yyjson_write_flag; + +/** Default option: + - Write JSON minify. + - Report error on inf or nan number. + - Report error on invalid UTF-8 string. + - Do not escape unicode or slash. */ +static const yyjson_write_flag YYJSON_WRITE_NOFLAG = 0 << 0; + +/** Write JSON pretty with 4 space indent. */ +static const yyjson_write_flag YYJSON_WRITE_PRETTY = 1 << 0; + +/** Escape unicode as `uXXXX`, make the output ASCII only. */ +static const yyjson_write_flag YYJSON_WRITE_ESCAPE_UNICODE = 1 << 1; + +/** Escape '/' as '\/'. */ +static const yyjson_write_flag YYJSON_WRITE_ESCAPE_SLASHES = 1 << 2; + +/** Write inf and nan number as 'Infinity' and 'NaN' literal (non-standard). */ +static const yyjson_write_flag YYJSON_WRITE_ALLOW_INF_AND_NAN = 1 << 3; + +/** Write inf and nan number as null literal. + This flag will override `YYJSON_WRITE_ALLOW_INF_AND_NAN` flag. */ +static const yyjson_write_flag YYJSON_WRITE_INF_AND_NAN_AS_NULL = 1 << 4; + +/** Allow invalid unicode when encoding string values (non-standard). + Invalid characters in string value will be copied byte by byte. + If `YYJSON_WRITE_ESCAPE_UNICODE` flag is also set, invalid character will be + escaped as `U+FFFD` (replacement character). + This flag does not affect the performance of correctly encoded strings. */ +static const yyjson_write_flag YYJSON_WRITE_ALLOW_INVALID_UNICODE = 1 << 5; + +/** Write JSON pretty with 2 space indent. + This flag will override `YYJSON_WRITE_PRETTY` flag. */ +static const yyjson_write_flag YYJSON_WRITE_PRETTY_TWO_SPACES = 1 << 6; + + + +/** Result code for JSON writer */ +typedef uint32_t yyjson_write_code; + +/** Success, no error. */ +static const yyjson_write_code YYJSON_WRITE_SUCCESS = 0; + +/** Invalid parameter, such as NULL document. */ +static const yyjson_write_code YYJSON_WRITE_ERROR_INVALID_PARAMETER = 1; + +/** Memory allocation failure occurs. */ +static const yyjson_write_code YYJSON_WRITE_ERROR_MEMORY_ALLOCATION = 2; + +/** Invalid value type in JSON document. */ +static const yyjson_write_code YYJSON_WRITE_ERROR_INVALID_VALUE_TYPE = 3; + +/** NaN or Infinity number occurs. */ +static const yyjson_write_code YYJSON_WRITE_ERROR_NAN_OR_INF = 4; + +/** Failed to open a file. */ +static const yyjson_write_code YYJSON_WRITE_ERROR_FILE_OPEN = 5; + +/** Failed to write a file. */ +static const yyjson_write_code YYJSON_WRITE_ERROR_FILE_WRITE = 6; + +/** Invalid unicode in string. */ +static const yyjson_write_code YYJSON_WRITE_ERROR_INVALID_STRING = 7; + +/** Error information for JSON writer. */ +typedef struct yyjson_write_err { + /** Error code, see `yyjson_write_code` for all possible values. */ + yyjson_write_code code; + /** Error message, constant, no need to free (NULL if success). */ + const char *msg; +} yyjson_write_err; + + + +/*============================================================================== + * JSON Document Writer API + *============================================================================*/ + +/** + Write a document to JSON string with options. + + This function is thread-safe when: + The `alc` is thread-safe or NULL. + + @param doc The JSON document. + If this doc is NULL or has no root, the function will fail and return false. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param len A pointer to receive output length in bytes (not including the + null-terminator). Pass NULL if you don't need length information. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return A new JSON string, or NULL if an error occurs. + This string is encoded as UTF-8 with a null-terminator. + When it's no longer needed, it should be freed with free() or alc->free(). + */ +yyjson_api char *yyjson_write_opts(const yyjson_doc *doc, + yyjson_write_flag flg, + const yyjson_alc *alc, + size_t *len, + yyjson_write_err *err); + +/** + Write a document to JSON file with options. + + This function is thread-safe when: + 1. The file is not accessed by other threads. + 2. The `alc` is thread-safe or NULL. + + @param path The JSON file's path. + If this path is NULL or invalid, the function will fail and return false. + If this file is not empty, the content will be discarded. + @param doc The JSON document. + If this doc is NULL or has no root, the function will fail and return false. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return true if successful, false if an error occurs. + + @warning On 32-bit operating system, files larger than 2GB may fail to write. + */ +yyjson_api bool yyjson_write_file(const char *path, + const yyjson_doc *doc, + yyjson_write_flag flg, + const yyjson_alc *alc, + yyjson_write_err *err); + +/** + Write a document to file pointer with options. + + @param fp The file pointer. + The data will be written to the current position of the file. + If this fp is NULL or invalid, the function will fail and return false. + @param doc The JSON document. + If this doc is NULL or has no root, the function will fail and return false. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return true if successful, false if an error occurs. + + @warning On 32-bit operating system, files larger than 2GB may fail to write. + */ +yyjson_api bool yyjson_write_fp(FILE *fp, + const yyjson_doc *doc, + yyjson_write_flag flg, + const yyjson_alc *alc, + yyjson_write_err *err); + +/** + Write a document to JSON string. + + This function is thread-safe. + + @param doc The JSON document. + If this doc is NULL or has no root, the function will fail and return false. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param len A pointer to receive output length in bytes (not including the + null-terminator). Pass NULL if you don't need length information. + @return A new JSON string, or NULL if an error occurs. + This string is encoded as UTF-8 with a null-terminator. + When it's no longer needed, it should be freed with free(). + */ +yyjson_api_inline char *yyjson_write(const yyjson_doc *doc, + yyjson_write_flag flg, + size_t *len) { + return yyjson_write_opts(doc, flg, NULL, len, NULL); +} + + + +/** + Write a document to JSON string with options. + + This function is thread-safe when: + 1. The `doc` is not modified by other threads. + 2. The `alc` is thread-safe or NULL. + + @param doc The mutable JSON document. + If this doc is NULL or has no root, the function will fail and return false. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param len A pointer to receive output length in bytes (not including the + null-terminator). Pass NULL if you don't need length information. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return A new JSON string, or NULL if an error occurs. + This string is encoded as UTF-8 with a null-terminator. + When it's no longer needed, it should be freed with free() or alc->free(). + */ +yyjson_api char *yyjson_mut_write_opts(const yyjson_mut_doc *doc, + yyjson_write_flag flg, + const yyjson_alc *alc, + size_t *len, + yyjson_write_err *err); + +/** + Write a document to JSON file with options. + + This function is thread-safe when: + 1. The file is not accessed by other threads. + 2. The `doc` is not modified by other threads. + 3. The `alc` is thread-safe or NULL. + + @param path The JSON file's path. + If this path is NULL or invalid, the function will fail and return false. + If this file is not empty, the content will be discarded. + @param doc The mutable JSON document. + If this doc is NULL or has no root, the function will fail and return false. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return true if successful, false if an error occurs. + + @warning On 32-bit operating system, files larger than 2GB may fail to write. + */ +yyjson_api bool yyjson_mut_write_file(const char *path, + const yyjson_mut_doc *doc, + yyjson_write_flag flg, + const yyjson_alc *alc, + yyjson_write_err *err); + +/** + Write a document to file pointer with options. + + @param fp The file pointer. + The data will be written to the current position of the file. + If this fp is NULL or invalid, the function will fail and return false. + @param doc The mutable JSON document. + If this doc is NULL or has no root, the function will fail and return false. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return true if successful, false if an error occurs. + + @warning On 32-bit operating system, files larger than 2GB may fail to write. + */ +yyjson_api bool yyjson_mut_write_fp(FILE *fp, + const yyjson_mut_doc *doc, + yyjson_write_flag flg, + const yyjson_alc *alc, + yyjson_write_err *err); + +/** + Write a document to JSON string. + + This function is thread-safe when: + The `doc` is not modified by other threads. + + @param doc The JSON document. + If this doc is NULL or has no root, the function will fail and return false. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param len A pointer to receive output length in bytes (not including the + null-terminator). Pass NULL if you don't need length information. + @return A new JSON string, or NULL if an error occurs. + This string is encoded as UTF-8 with a null-terminator. + When it's no longer needed, it should be freed with free(). + */ +yyjson_api_inline char *yyjson_mut_write(const yyjson_mut_doc *doc, + yyjson_write_flag flg, + size_t *len) { + return yyjson_mut_write_opts(doc, flg, NULL, len, NULL); +} + + + +/*============================================================================== + * JSON Value Writer API + *============================================================================*/ + +/** + Write a value to JSON string with options. + + This function is thread-safe when: + The `alc` is thread-safe or NULL. + + @param val The JSON root value. + If this parameter is NULL, the function will fail and return NULL. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param len A pointer to receive output length in bytes (not including the + null-terminator). Pass NULL if you don't need length information. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return A new JSON string, or NULL if an error occurs. + This string is encoded as UTF-8 with a null-terminator. + When it's no longer needed, it should be freed with free() or alc->free(). + */ +yyjson_api char *yyjson_val_write_opts(const yyjson_val *val, + yyjson_write_flag flg, + const yyjson_alc *alc, + size_t *len, + yyjson_write_err *err); + +/** + Write a value to JSON file with options. + + This function is thread-safe when: + 1. The file is not accessed by other threads. + 2. The `alc` is thread-safe or NULL. + + @param path The JSON file's path. + If this path is NULL or invalid, the function will fail and return false. + If this file is not empty, the content will be discarded. + @param val The JSON root value. + If this parameter is NULL, the function will fail and return NULL. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return true if successful, false if an error occurs. + + @warning On 32-bit operating system, files larger than 2GB may fail to write. + */ +yyjson_api bool yyjson_val_write_file(const char *path, + const yyjson_val *val, + yyjson_write_flag flg, + const yyjson_alc *alc, + yyjson_write_err *err); + +/** + Write a value to file pointer with options. + + @param fp The file pointer. + The data will be written to the current position of the file. + If this path is NULL or invalid, the function will fail and return false. + @param val The JSON root value. + If this parameter is NULL, the function will fail and return NULL. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return true if successful, false if an error occurs. + + @warning On 32-bit operating system, files larger than 2GB may fail to write. + */ +yyjson_api bool yyjson_val_write_fp(FILE *fp, + const yyjson_val *val, + yyjson_write_flag flg, + const yyjson_alc *alc, + yyjson_write_err *err); + +/** + Write a value to JSON string. + + This function is thread-safe. + + @param val The JSON root value. + If this parameter is NULL, the function will fail and return NULL. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param len A pointer to receive output length in bytes (not including the + null-terminator). Pass NULL if you don't need length information. + @return A new JSON string, or NULL if an error occurs. + This string is encoded as UTF-8 with a null-terminator. + When it's no longer needed, it should be freed with free(). + */ +yyjson_api_inline char *yyjson_val_write(const yyjson_val *val, + yyjson_write_flag flg, + size_t *len) { + return yyjson_val_write_opts(val, flg, NULL, len, NULL); +} + +/** + Write a value to JSON string with options. + + This function is thread-safe when: + 1. The `val` is not modified by other threads. + 2. The `alc` is thread-safe or NULL. + + @param val The mutable JSON root value. + If this parameter is NULL, the function will fail and return NULL. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param len A pointer to receive output length in bytes (not including the + null-terminator). Pass NULL if you don't need length information. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return A new JSON string, or NULL if an error occurs. + This string is encoded as UTF-8 with a null-terminator. + When it's no longer needed, it should be freed with free() or alc->free(). + */ +yyjson_api char *yyjson_mut_val_write_opts(const yyjson_mut_val *val, + yyjson_write_flag flg, + const yyjson_alc *alc, + size_t *len, + yyjson_write_err *err); + +/** + Write a value to JSON file with options. + + This function is thread-safe when: + 1. The file is not accessed by other threads. + 2. The `val` is not modified by other threads. + 3. The `alc` is thread-safe or NULL. + + @param path The JSON file's path. + If this path is NULL or invalid, the function will fail and return false. + If this file is not empty, the content will be discarded. + @param val The mutable JSON root value. + If this parameter is NULL, the function will fail and return NULL. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return true if successful, false if an error occurs. + + @warning On 32-bit operating system, files larger than 2GB may fail to write. + */ +yyjson_api bool yyjson_mut_val_write_file(const char *path, + const yyjson_mut_val *val, + yyjson_write_flag flg, + const yyjson_alc *alc, + yyjson_write_err *err); + +/** + Write a value to JSON file with options. + + @param fp The file pointer. + The data will be written to the current position of the file. + If this path is NULL or invalid, the function will fail and return false. + @param val The mutable JSON root value. + If this parameter is NULL, the function will fail and return NULL. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param alc The memory allocator used by JSON writer. + Pass NULL to use the libc's default allocator. + @param err A pointer to receive error information. + Pass NULL if you don't need error information. + @return true if successful, false if an error occurs. + + @warning On 32-bit operating system, files larger than 2GB may fail to write. + */ +yyjson_api bool yyjson_mut_val_write_fp(FILE *fp, + const yyjson_mut_val *val, + yyjson_write_flag flg, + const yyjson_alc *alc, + yyjson_write_err *err); + +/** + Write a value to JSON string. + + This function is thread-safe when: + The `val` is not modified by other threads. + + @param val The JSON root value. + If this parameter is NULL, the function will fail and return NULL. + @param flg The JSON write options. + Multiple options can be combined with `|` operator. 0 means no options. + @param len A pointer to receive output length in bytes (not including the + null-terminator). Pass NULL if you don't need length information. + @return A new JSON string, or NULL if an error occurs. + This string is encoded as UTF-8 with a null-terminator. + When it's no longer needed, it should be freed with free(). + */ +yyjson_api_inline char *yyjson_mut_val_write(const yyjson_mut_val *val, + yyjson_write_flag flg, + size_t *len) { + return yyjson_mut_val_write_opts(val, flg, NULL, len, NULL); +} + + + +/*============================================================================== + * JSON Document API + *============================================================================*/ + +/** Returns the root value of this JSON document. + Returns NULL if `doc` is NULL. */ +yyjson_api_inline yyjson_val *yyjson_doc_get_root(yyjson_doc *doc); + +/** Returns read size of input JSON data. + Returns 0 if `doc` is NULL. + For example: the read size of `[1,2,3]` is 7 bytes. */ +yyjson_api_inline size_t yyjson_doc_get_read_size(yyjson_doc *doc); + +/** Returns total value count in this JSON document. + Returns 0 if `doc` is NULL. + For example: the value count of `[1,2,3]` is 4. */ +yyjson_api_inline size_t yyjson_doc_get_val_count(yyjson_doc *doc); + +/** Release the JSON document and free the memory. + After calling this function, the `doc` and all values from the `doc` are no + longer available. This function will do nothing if the `doc` is NULL. */ +yyjson_api_inline void yyjson_doc_free(yyjson_doc *doc); + + + +/*============================================================================== + * JSON Value Type API + *============================================================================*/ + +/** Returns whether the JSON value is raw. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_raw(yyjson_val *val); + +/** Returns whether the JSON value is `null`. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_null(yyjson_val *val); + +/** Returns whether the JSON value is `true`. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_true(yyjson_val *val); + +/** Returns whether the JSON value is `false`. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_false(yyjson_val *val); + +/** Returns whether the JSON value is bool (true/false). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_bool(yyjson_val *val); + +/** Returns whether the JSON value is unsigned integer (uint64_t). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_uint(yyjson_val *val); + +/** Returns whether the JSON value is signed integer (int64_t). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_sint(yyjson_val *val); + +/** Returns whether the JSON value is integer (uint64_t/int64_t). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_int(yyjson_val *val); + +/** Returns whether the JSON value is real number (double). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_real(yyjson_val *val); + +/** Returns whether the JSON value is number (uint64_t/int64_t/double). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_num(yyjson_val *val); + +/** Returns whether the JSON value is string. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_str(yyjson_val *val); + +/** Returns whether the JSON value is array. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_arr(yyjson_val *val); + +/** Returns whether the JSON value is object. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_obj(yyjson_val *val); + +/** Returns whether the JSON value is container (array/object). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_is_ctn(yyjson_val *val); + + + +/*============================================================================== + * JSON Value Content API + *============================================================================*/ + +/** Returns the JSON value's type. + Returns YYJSON_TYPE_NONE if `val` is NULL. */ +yyjson_api_inline yyjson_type yyjson_get_type(yyjson_val *val); + +/** Returns the JSON value's subtype. + Returns YYJSON_SUBTYPE_NONE if `val` is NULL. */ +yyjson_api_inline yyjson_subtype yyjson_get_subtype(yyjson_val *val); + +/** Returns the JSON value's tag. + Returns 0 if `val` is NULL. */ +yyjson_api_inline uint8_t yyjson_get_tag(yyjson_val *val); + +/** Returns the JSON value's type description. + The return value should be one of these strings: "raw", "null", "string", + "array", "object", "true", "false", "uint", "sint", "real", "unknown". */ +yyjson_api_inline const char *yyjson_get_type_desc(yyjson_val *val); + +/** Returns the content if the value is raw. + Returns NULL if `val` is NULL or type is not raw. */ +yyjson_api_inline const char *yyjson_get_raw(yyjson_val *val); + +/** Returns the content if the value is bool. + Returns NULL if `val` is NULL or type is not bool. */ +yyjson_api_inline bool yyjson_get_bool(yyjson_val *val); + +/** Returns the content and cast to uint64_t. + Returns 0 if `val` is NULL or type is not integer(sint/uint). */ +yyjson_api_inline uint64_t yyjson_get_uint(yyjson_val *val); + +/** Returns the content and cast to int64_t. + Returns 0 if `val` is NULL or type is not integer(sint/uint). */ +yyjson_api_inline int64_t yyjson_get_sint(yyjson_val *val); + +/** Returns the content and cast to int. + Returns 0 if `val` is NULL or type is not integer(sint/uint). */ +yyjson_api_inline int yyjson_get_int(yyjson_val *val); + +/** Returns the content if the value is real number, or 0.0 on error. + Returns 0.0 if `val` is NULL or type is not real(double). */ +yyjson_api_inline double yyjson_get_real(yyjson_val *val); + +/** Returns the content and typecast to `double` if the value is number. + Returns 0.0 if `val` is NULL or type is not number(uint/sint/real). */ +yyjson_api_inline double yyjson_get_num(yyjson_val *val); + +/** Returns the content if the value is string. + Returns NULL if `val` is NULL or type is not string. */ +yyjson_api_inline const char *yyjson_get_str(yyjson_val *val); + +/** Returns the content length (string length, array size, object size. + Returns 0 if `val` is NULL or type is not string/array/object. */ +yyjson_api_inline size_t yyjson_get_len(yyjson_val *val); + +/** Returns whether the JSON value is equals to a string. + Returns false if input is NULL or type is not string. */ +yyjson_api_inline bool yyjson_equals_str(yyjson_val *val, const char *str); + +/** Returns whether the JSON value is equals to a string. + The `str` should be a UTF-8 string, null-terminator is not required. + Returns false if input is NULL or type is not string. */ +yyjson_api_inline bool yyjson_equals_strn(yyjson_val *val, const char *str, + size_t len); + +/** Returns whether two JSON values are equal (deep compare). + Returns false if input is NULL. + @note the result may be inaccurate if object has duplicate keys. + @warning This function is recursive and may cause a stack overflow + if the object level is too deep. */ +yyjson_api_inline bool yyjson_equals(yyjson_val *lhs, yyjson_val *rhs); + +/** Set the value to raw. + Returns false if input is NULL or `val` is object or array. + @warning This will modify the `immutable` value, use with caution. */ +yyjson_api_inline bool yyjson_set_raw(yyjson_val *val, + const char *raw, size_t len); + +/** Set the value to null. + Returns false if input is NULL or `val` is object or array. + @warning This will modify the `immutable` value, use with caution. */ +yyjson_api_inline bool yyjson_set_null(yyjson_val *val); + +/** Set the value to bool. + Returns false if input is NULL or `val` is object or array. + @warning This will modify the `immutable` value, use with caution. */ +yyjson_api_inline bool yyjson_set_bool(yyjson_val *val, bool num); + +/** Set the value to uint. + Returns false if input is NULL or `val` is object or array. + @warning This will modify the `immutable` value, use with caution. */ +yyjson_api_inline bool yyjson_set_uint(yyjson_val *val, uint64_t num); + +/** Set the value to sint. + Returns false if input is NULL or `val` is object or array. + @warning This will modify the `immutable` value, use with caution. */ +yyjson_api_inline bool yyjson_set_sint(yyjson_val *val, int64_t num); + +/** Set the value to int. + Returns false if input is NULL or `val` is object or array. + @warning This will modify the `immutable` value, use with caution. */ +yyjson_api_inline bool yyjson_set_int(yyjson_val *val, int num); + +/** Set the value to real. + Returns false if input is NULL or `val` is object or array. + @warning This will modify the `immutable` value, use with caution. */ +yyjson_api_inline bool yyjson_set_real(yyjson_val *val, double num); + +/** Set the value to string (null-terminated). + Returns false if input is NULL or `val` is object or array. + @warning This will modify the `immutable` value, use with caution. */ +yyjson_api_inline bool yyjson_set_str(yyjson_val *val, const char *str); + +/** Set the value to string (with length). + Returns false if input is NULL or `val` is object or array. + @warning This will modify the `immutable` value, use with caution. */ +yyjson_api_inline bool yyjson_set_strn(yyjson_val *val, + const char *str, size_t len); + + + +/*============================================================================== + * JSON Array API + *============================================================================*/ + +/** Returns the number of elements in this array. + Returns 0 if `arr` is NULL or type is not array. */ +yyjson_api_inline size_t yyjson_arr_size(yyjson_val *arr); + +/** Returns the element at the specified position in this array. + Returns NULL if array is NULL/empty or the index is out of bounds. + @warning This function takes a linear search time if array is not flat. + For example: `[1,{},3]` is flat, `[1,[2],3]` is not flat. */ +yyjson_api_inline yyjson_val *yyjson_arr_get(yyjson_val *arr, size_t idx); + +/** Returns the first element of this array. + Returns NULL if `arr` is NULL/empty or type is not array. */ +yyjson_api_inline yyjson_val *yyjson_arr_get_first(yyjson_val *arr); + +/** Returns the last element of this array. + Returns NULL if `arr` is NULL/empty or type is not array. + @warning This function takes a linear search time if array is not flat. + For example: `[1,{},3]` is flat, `[1,[2],3]` is not flat.*/ +yyjson_api_inline yyjson_val *yyjson_arr_get_last(yyjson_val *arr); + + + +/*============================================================================== + * JSON Array Iterator API + *============================================================================*/ + +/** + A JSON array iterator. + + @par Example + @code + yyjson_val *val; + yyjson_arr_iter iter = yyjson_arr_iter_with(arr); + while ((val = yyjson_arr_iter_next(&iter))) { + your_func(val); + } + @endcode + */ +typedef struct yyjson_arr_iter { + size_t idx; /**< next value's index */ + size_t max; /**< maximum index (arr.size) */ + yyjson_val *cur; /**< next value */ +} yyjson_arr_iter; + +/** + Initialize an iterator for this array. + + @param arr The array to be iterated over. + If this parameter is NULL or not an array, `iter` will be set to empty. + @param iter The iterator to be initialized. + If this parameter is NULL, the function will fail and return false. + @return true if the `iter` has been successfully initialized. + + @note The iterator does not need to be destroyed. + */ +yyjson_api_inline bool yyjson_arr_iter_init(yyjson_val *arr, + yyjson_arr_iter *iter); + +/** + Create an iterator with an array , same as `yyjson_arr_iter_init()`. + + @param arr The array to be iterated over. + If this parameter is NULL or not an array, an empty iterator will returned. + @return A new iterator for the array. + + @note The iterator does not need to be destroyed. + */ +yyjson_api_inline yyjson_arr_iter yyjson_arr_iter_with(yyjson_val *arr); + +/** + Returns whether the iteration has more elements. + If `iter` is NULL, this function will return false. + */ +yyjson_api_inline bool yyjson_arr_iter_has_next(yyjson_arr_iter *iter); + +/** + Returns the next element in the iteration, or NULL on end. + If `iter` is NULL, this function will return NULL. + */ +yyjson_api_inline yyjson_val *yyjson_arr_iter_next(yyjson_arr_iter *iter); + +/** + Macro for iterating over an array. + It works like iterator, but with a more intuitive API. + + @par Example + @code + size_t idx, max; + yyjson_val *val; + yyjson_arr_foreach(arr, idx, max, val) { + your_func(idx, val); + } + @endcode + */ +#define yyjson_arr_foreach(arr, idx, max, val) \ + for ((idx) = 0, \ + (max) = yyjson_arr_size(arr), \ + (val) = yyjson_arr_get_first(arr); \ + (idx) < (max); \ + (idx)++, \ + (val) = unsafe_yyjson_get_next(val)) + + + +/*============================================================================== + * JSON Object API + *============================================================================*/ + +/** Returns the number of key-value pairs in this object. + Returns 0 if `obj` is NULL or type is not object. */ +yyjson_api_inline size_t yyjson_obj_size(yyjson_val *obj); + +/** Returns the value to which the specified key is mapped. + Returns NULL if this object contains no mapping for the key. + Returns NULL if `obj/key` is NULL, or type is not object. + + The `key` should be a null-terminated UTF-8 string. + + @warning This function takes a linear search time. */ +yyjson_api_inline yyjson_val *yyjson_obj_get(yyjson_val *obj, const char *key); + +/** Returns the value to which the specified key is mapped. + Returns NULL if this object contains no mapping for the key. + Returns NULL if `obj/key` is NULL, or type is not object. + + The `key` should be a UTF-8 string, null-terminator is not required. + The `key_len` should be the length of the key, in bytes. + + @warning This function takes a linear search time. */ +yyjson_api_inline yyjson_val *yyjson_obj_getn(yyjson_val *obj, const char *key, + size_t key_len); + + + +/*============================================================================== + * JSON Object Iterator API + *============================================================================*/ + +/** + A JSON object iterator. + + @par Example + @code + yyjson_val *key, *val; + yyjson_obj_iter iter = yyjson_obj_iter_with(obj); + while ((key = yyjson_obj_iter_next(&iter))) { + val = yyjson_obj_iter_get_val(key); + your_func(key, val); + } + @endcode + + If the ordering of the keys is known at compile-time, you can use this method + to speed up value lookups: + @code + // {"k1":1, "k2": 3, "k3": 3} + yyjson_val *key, *val; + yyjson_obj_iter iter = yyjson_obj_iter_with(obj); + yyjson_val *v1 = yyjson_obj_iter_get(&iter, "k1"); + yyjson_val *v3 = yyjson_obj_iter_get(&iter, "k3"); + @endcode + @see yyjson_obj_iter_get() and yyjson_obj_iter_getn() + */ +typedef struct yyjson_obj_iter { + size_t idx; /**< next key's index */ + size_t max; /**< maximum key index (obj.size) */ + yyjson_val *cur; /**< next key */ + yyjson_val *obj; /**< the object being iterated */ +} yyjson_obj_iter; + +/** + Initialize an iterator for this object. + + @param obj The object to be iterated over. + If this parameter is NULL or not an object, `iter` will be set to empty. + @param iter The iterator to be initialized. + If this parameter is NULL, the function will fail and return false. + @return true if the `iter` has been successfully initialized. + + @note The iterator does not need to be destroyed. + */ +yyjson_api_inline bool yyjson_obj_iter_init(yyjson_val *obj, + yyjson_obj_iter *iter); + +/** + Create an iterator with an object, same as `yyjson_obj_iter_init()`. + + @param obj The object to be iterated over. + If this parameter is NULL or not an object, an empty iterator will returned. + @return A new iterator for the object. + + @note The iterator does not need to be destroyed. + */ +yyjson_api_inline yyjson_obj_iter yyjson_obj_iter_with(yyjson_val *obj); + +/** + Returns whether the iteration has more elements. + If `iter` is NULL, this function will return false. + */ +yyjson_api_inline bool yyjson_obj_iter_has_next(yyjson_obj_iter *iter); + +/** + Returns the next key in the iteration, or NULL on end. + If `iter` is NULL, this function will return NULL. + */ +yyjson_api_inline yyjson_val *yyjson_obj_iter_next(yyjson_obj_iter *iter); + +/** + Returns the value for key inside the iteration. + If `iter` is NULL, this function will return NULL. + */ +yyjson_api_inline yyjson_val *yyjson_obj_iter_get_val(yyjson_val *key); + +/** + Iterates to a specified key and returns the value. + + This function does the same thing as `yyjson_obj_get()`, but is much faster + if the ordering of the keys is known at compile-time and you are using the same + order to look up the values. If the key exists in this object, then the + iterator will stop at the next key, otherwise the iterator will not change and + NULL is returned. + + @param iter The object iterator, should not be NULL. + @param key The key, should be a UTF-8 string with null-terminator. + @return The value to which the specified key is mapped. + NULL if this object contains no mapping for the key or input is invalid. + + @warning This function takes a linear search time if the key is not nearby. + */ +yyjson_api_inline yyjson_val *yyjson_obj_iter_get(yyjson_obj_iter *iter, + const char *key); + +/** + Iterates to a specified key and returns the value. + + This function does the same thing as `yyjson_obj_getn()`, but is much faster + if the ordering of the keys is known at compile-time and you are using the same + order to look up the values. If the key exists in this object, then the + iterator will stop at the next key, otherwise the iterator will not change and + NULL is returned. + + @param iter The object iterator, should not be NULL. + @param key The key, should be a UTF-8 string, null-terminator is not required. + @param key_len The the length of `key`, in bytes. + @return The value to which the specified key is mapped. + NULL if this object contains no mapping for the key or input is invalid. + + @warning This function takes a linear search time if the key is not nearby. + */ +yyjson_api_inline yyjson_val *yyjson_obj_iter_getn(yyjson_obj_iter *iter, + const char *key, + size_t key_len); + +/** + Macro for iterating over an object. + It works like iterator, but with a more intuitive API. + + @par Example + @code + size_t idx, max; + yyjson_val *key, *val; + yyjson_obj_foreach(obj, idx, max, key, val) { + your_func(key, val); + } + @endcode + */ +#define yyjson_obj_foreach(obj, idx, max, key, val) \ + for ((idx) = 0, \ + (max) = yyjson_obj_size(obj), \ + (key) = (obj) ? unsafe_yyjson_get_first(obj) : NULL, \ + (val) = (key) + 1; \ + (idx) < (max); \ + (idx)++, \ + (key) = unsafe_yyjson_get_next(val), \ + (val) = (key) + 1) + + + +/*============================================================================== + * Mutable JSON Document API + *============================================================================*/ + +/** Returns the root value of this JSON document. + Returns NULL if `doc` is NULL. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_get_root(yyjson_mut_doc *doc); + +/** Sets the root value of this JSON document. + Pass NULL to clear root value of the document. */ +yyjson_api_inline void yyjson_mut_doc_set_root(yyjson_mut_doc *doc, + yyjson_mut_val *root); + +/** + Set the string pool size for a mutable document. + This function does not allocate memory immediately, but uses the size when + the next memory allocation is needed. + + If the caller knows the approximate bytes of strings that the document needs to + store (e.g. copy string with `yyjson_mut_strcpy` function), setting a larger + size can avoid multiple memory allocations and improve performance. + + @param doc The mutable document. + @param len The desired string pool size in bytes (total string length). + @return true if successful, false if size is 0 or overflow. + */ +yyjson_api bool yyjson_mut_doc_set_str_pool_size(yyjson_mut_doc *doc, + size_t len); + +/** + Set the value pool size for a mutable document. + This function does not allocate memory immediately, but uses the size when + the next memory allocation is needed. + + If the caller knows the approximate number of values that the document needs to + store (e.g. create new value with `yyjson_mut_xxx` functions), setting a larger + size can avoid multiple memory allocations and improve performance. + + @param doc The mutable document. + @param count The desired value pool size (number of `yyjson_mut_val`). + @return true if successful, false if size is 0 or overflow. + */ +yyjson_api bool yyjson_mut_doc_set_val_pool_size(yyjson_mut_doc *doc, + size_t count); + +/** Release the JSON document and free the memory. + After calling this function, the `doc` and all values from the `doc` are no + longer available. This function will do nothing if the `doc` is NULL. */ +yyjson_api void yyjson_mut_doc_free(yyjson_mut_doc *doc); + +/** Creates and returns a new mutable JSON document, returns NULL on error. + If allocator is NULL, the default allocator will be used. */ +yyjson_api yyjson_mut_doc *yyjson_mut_doc_new(const yyjson_alc *alc); + +/** Copies and returns a new mutable document from input, returns NULL on error. + This makes a `deep-copy` on the immutable document. + If allocator is NULL, the default allocator will be used. + @note `imut_doc` -> `mut_doc`. */ +yyjson_api yyjson_mut_doc *yyjson_doc_mut_copy(yyjson_doc *doc, + const yyjson_alc *alc); + +/** Copies and returns a new mutable document from input, returns NULL on error. + This makes a `deep-copy` on the mutable document. + If allocator is NULL, the default allocator will be used. + @note `mut_doc` -> `mut_doc`. */ +yyjson_api yyjson_mut_doc *yyjson_mut_doc_mut_copy(yyjson_mut_doc *doc, + const yyjson_alc *alc); + +/** Copies and returns a new mutable value from input, returns NULL on error. + This makes a `deep-copy` on the immutable value. + The memory was managed by mutable document. + @note `imut_val` -> `mut_val`. */ +yyjson_api yyjson_mut_val *yyjson_val_mut_copy(yyjson_mut_doc *doc, + yyjson_val *val); + +/** Copies and returns a new mutable value from input, returns NULL on error. + This makes a `deep-copy` on the mutable value. + The memory was managed by mutable document. + @note `mut_val` -> `mut_val`. + @warning This function is recursive and may cause a stack overflow + if the object level is too deep. */ +yyjson_api yyjson_mut_val *yyjson_mut_val_mut_copy(yyjson_mut_doc *doc, + yyjson_mut_val *val); + +/** Copies and returns a new immutable document from input, + returns NULL on error. This makes a `deep-copy` on the mutable document. + The returned document should be freed with `yyjson_doc_free()`. + @note `mut_doc` -> `imut_doc`. + @warning This function is recursive and may cause a stack overflow + if the object level is too deep. */ +yyjson_api yyjson_doc *yyjson_mut_doc_imut_copy(yyjson_mut_doc *doc, + const yyjson_alc *alc); + +/** Copies and returns a new immutable document from input, + returns NULL on error. This makes a `deep-copy` on the mutable value. + The returned document should be freed with `yyjson_doc_free()`. + @note `mut_val` -> `imut_doc`. + @warning This function is recursive and may cause a stack overflow + if the object level is too deep. */ +yyjson_api yyjson_doc *yyjson_mut_val_imut_copy(yyjson_mut_val *val, + const yyjson_alc *alc); + + + +/*============================================================================== + * Mutable JSON Value Type API + *============================================================================*/ + +/** Returns whether the JSON value is raw. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_raw(yyjson_mut_val *val); + +/** Returns whether the JSON value is `null`. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_null(yyjson_mut_val *val); + +/** Returns whether the JSON value is `true`. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_true(yyjson_mut_val *val); + +/** Returns whether the JSON value is `false`. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_false(yyjson_mut_val *val); + +/** Returns whether the JSON value is bool (true/false). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_bool(yyjson_mut_val *val); + +/** Returns whether the JSON value is unsigned integer (uint64_t). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_uint(yyjson_mut_val *val); + +/** Returns whether the JSON value is signed integer (int64_t). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_sint(yyjson_mut_val *val); + +/** Returns whether the JSON value is integer (uint64_t/int64_t). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_int(yyjson_mut_val *val); + +/** Returns whether the JSON value is real number (double). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_real(yyjson_mut_val *val); + +/** Returns whether the JSON value is number (uint/sint/real). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_num(yyjson_mut_val *val); + +/** Returns whether the JSON value is string. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_str(yyjson_mut_val *val); + +/** Returns whether the JSON value is array. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_arr(yyjson_mut_val *val); + +/** Returns whether the JSON value is object. + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_obj(yyjson_mut_val *val); + +/** Returns whether the JSON value is container (array/object). + Returns false if `val` is NULL. */ +yyjson_api_inline bool yyjson_mut_is_ctn(yyjson_mut_val *val); + + + +/*============================================================================== + * Mutable JSON Value Content API + *============================================================================*/ + +/** Returns the JSON value's type. + Returns `YYJSON_TYPE_NONE` if `val` is NULL. */ +yyjson_api_inline yyjson_type yyjson_mut_get_type(yyjson_mut_val *val); + +/** Returns the JSON value's subtype. + Returns `YYJSON_SUBTYPE_NONE` if `val` is NULL. */ +yyjson_api_inline yyjson_subtype yyjson_mut_get_subtype(yyjson_mut_val *val); + +/** Returns the JSON value's tag. + Returns 0 if `val` is NULL. */ +yyjson_api_inline uint8_t yyjson_mut_get_tag(yyjson_mut_val *val); + +/** Returns the JSON value's type description. + The return value should be one of these strings: "raw", "null", "string", + "array", "object", "true", "false", "uint", "sint", "real", "unknown". */ +yyjson_api_inline const char *yyjson_mut_get_type_desc(yyjson_mut_val *val); + +/** Returns the content if the value is raw. + Returns NULL if `val` is NULL or type is not raw. */ +yyjson_api_inline const char *yyjson_mut_get_raw(yyjson_mut_val *val); + +/** Returns the content if the value is bool. + Returns NULL if `val` is NULL or type is not bool. */ +yyjson_api_inline bool yyjson_mut_get_bool(yyjson_mut_val *val); + +/** Returns the content and cast to uint64_t. + Returns 0 if `val` is NULL or type is not integer(sint/uint). */ +yyjson_api_inline uint64_t yyjson_mut_get_uint(yyjson_mut_val *val); + +/** Returns the content and cast to int64_t. + Returns 0 if `val` is NULL or type is not integer(sint/uint). */ +yyjson_api_inline int64_t yyjson_mut_get_sint(yyjson_mut_val *val); + +/** Returns the content and cast to int. + Returns 0 if `val` is NULL or type is not integer(sint/uint). */ +yyjson_api_inline int yyjson_mut_get_int(yyjson_mut_val *val); + +/** Returns the content if the value is real number. + Returns 0.0 if `val` is NULL or type is not real(double). */ +yyjson_api_inline double yyjson_mut_get_real(yyjson_mut_val *val); + +/** Returns the content and typecast to `double` if the value is number. + Returns 0.0 if `val` is NULL or type is not number(uint/sint/real). */ +yyjson_api_inline double yyjson_mut_get_num(yyjson_mut_val *val); + +/** Returns the content if the value is string. + Returns NULL if `val` is NULL or type is not string. */ +yyjson_api_inline const char *yyjson_mut_get_str(yyjson_mut_val *val); + +/** Returns the content length (string length, array size, object size. + Returns 0 if `val` is NULL or type is not string/array/object. */ +yyjson_api_inline size_t yyjson_mut_get_len(yyjson_mut_val *val); + +/** Returns whether the JSON value is equals to a string. + The `str` should be a null-terminated UTF-8 string. + Returns false if input is NULL or type is not string. */ +yyjson_api_inline bool yyjson_mut_equals_str(yyjson_mut_val *val, + const char *str); + +/** Returns whether the JSON value is equals to a string. + The `str` should be a UTF-8 string, null-terminator is not required. + Returns false if input is NULL or type is not string. */ +yyjson_api_inline bool yyjson_mut_equals_strn(yyjson_mut_val *val, + const char *str, size_t len); + +/** Returns whether two JSON values are equal (deep compare). + Returns false if input is NULL. + @note the result may be inaccurate if object has duplicate keys. + @warning This function is recursive and may cause a stack overflow + if the object level is too deep. */ +yyjson_api_inline bool yyjson_mut_equals(yyjson_mut_val *lhs, + yyjson_mut_val *rhs); + +/** Set the value to raw. + Returns false if input is NULL. + @warning This function should not be used on an existing object or array. */ +yyjson_api_inline bool yyjson_mut_set_raw(yyjson_mut_val *val, + const char *raw, size_t len); + +/** Set the value to null. + Returns false if input is NULL. + @warning This function should not be used on an existing object or array. */ +yyjson_api_inline bool yyjson_mut_set_null(yyjson_mut_val *val); + +/** Set the value to bool. + Returns false if input is NULL. + @warning This function should not be used on an existing object or array. */ +yyjson_api_inline bool yyjson_mut_set_bool(yyjson_mut_val *val, bool num); + +/** Set the value to uint. + Returns false if input is NULL. + @warning This function should not be used on an existing object or array. */ +yyjson_api_inline bool yyjson_mut_set_uint(yyjson_mut_val *val, uint64_t num); + +/** Set the value to sint. + Returns false if input is NULL. + @warning This function should not be used on an existing object or array. */ +yyjson_api_inline bool yyjson_mut_set_sint(yyjson_mut_val *val, int64_t num); + +/** Set the value to int. + Returns false if input is NULL. + @warning This function should not be used on an existing object or array. */ +yyjson_api_inline bool yyjson_mut_set_int(yyjson_mut_val *val, int num); + +/** Set the value to real. + Returns false if input is NULL. + @warning This function should not be used on an existing object or array. */ +yyjson_api_inline bool yyjson_mut_set_real(yyjson_mut_val *val, double num); + +/** Set the value to string (null-terminated). + Returns false if input is NULL. + @warning This function should not be used on an existing object or array. */ +yyjson_api_inline bool yyjson_mut_set_str(yyjson_mut_val *val, const char *str); + +/** Set the value to string (with length). + Returns false if input is NULL. + @warning This function should not be used on an existing object or array. */ +yyjson_api_inline bool yyjson_mut_set_strn(yyjson_mut_val *val, + const char *str, size_t len); + +/** Set the value to array. + Returns false if input is NULL. + @warning This function should not be used on an existing object or array. */ +yyjson_api_inline bool yyjson_mut_set_arr(yyjson_mut_val *val); + +/** Set the value to array. + Returns false if input is NULL. + @warning This function should not be used on an existing object or array. */ +yyjson_api_inline bool yyjson_mut_set_obj(yyjson_mut_val *val); + + + +/*============================================================================== + * Mutable JSON Value Creation API + *============================================================================*/ + +/** Creates and returns a raw value, returns NULL on error. + The `str` should be a null-terminated UTF-8 string. + + @warning The input string is not copied, you should keep this string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_raw(yyjson_mut_doc *doc, + const char *str); + +/** Creates and returns a raw value, returns NULL on error. + The `str` should be a UTF-8 string, null-terminator is not required. + + @warning The input string is not copied, you should keep this string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_rawn(yyjson_mut_doc *doc, + const char *str, + size_t len); + +/** Creates and returns a raw value, returns NULL on error. + The `str` should be a null-terminated UTF-8 string. + The input string is copied and held by the document. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_rawcpy(yyjson_mut_doc *doc, + const char *str); + +/** Creates and returns a raw value, returns NULL on error. + The `str` should be a UTF-8 string, null-terminator is not required. + The input string is copied and held by the document. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_rawncpy(yyjson_mut_doc *doc, + const char *str, + size_t len); + +/** Creates and returns a null value, returns NULL on error. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_null(yyjson_mut_doc *doc); + +/** Creates and returns a true value, returns NULL on error. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_true(yyjson_mut_doc *doc); + +/** Creates and returns a false value, returns NULL on error. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_false(yyjson_mut_doc *doc); + +/** Creates and returns a bool value, returns NULL on error. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_bool(yyjson_mut_doc *doc, + bool val); + +/** Creates and returns an unsigned integer value, returns NULL on error. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_uint(yyjson_mut_doc *doc, + uint64_t num); + +/** Creates and returns a signed integer value, returns NULL on error. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_sint(yyjson_mut_doc *doc, + int64_t num); + +/** Creates and returns a signed integer value, returns NULL on error. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_int(yyjson_mut_doc *doc, + int64_t num); + +/** Creates and returns an real number value, returns NULL on error. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_real(yyjson_mut_doc *doc, + double num); + +/** Creates and returns a string value, returns NULL on error. + The `str` should be a null-terminated UTF-8 string. + @warning The input string is not copied, you should keep this string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_str(yyjson_mut_doc *doc, + const char *str); + +/** Creates and returns a string value, returns NULL on error. + The `str` should be a UTF-8 string, null-terminator is not required. + @warning The input string is not copied, you should keep this string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_strn(yyjson_mut_doc *doc, + const char *str, + size_t len); + +/** Creates and returns a string value, returns NULL on error. + The `str` should be a null-terminated UTF-8 string. + The input string is copied and held by the document. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_strcpy(yyjson_mut_doc *doc, + const char *str); + +/** Creates and returns a string value, returns NULL on error. + The `str` should be a UTF-8 string, null-terminator is not required. + The input string is copied and held by the document. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_strncpy(yyjson_mut_doc *doc, + const char *str, + size_t len); + + + +/*============================================================================== + * Mutable JSON Array API + *============================================================================*/ + +/** Returns the number of elements in this array. + Returns 0 if `arr` is NULL or type is not array. */ +yyjson_api_inline size_t yyjson_mut_arr_size(yyjson_mut_val *arr); + +/** Returns the element at the specified position in this array. + Returns NULL if array is NULL/empty or the index is out of bounds. + @warning This function takes a linear search time. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get(yyjson_mut_val *arr, + size_t idx); + +/** Returns the first element of this array. + Returns NULL if `arr` is NULL/empty or type is not array. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_first(yyjson_mut_val *arr); + +/** Returns the last element of this array. + Returns NULL if `arr` is NULL/empty or type is not array. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_last(yyjson_mut_val *arr); + + + +/*============================================================================== + * Mutable JSON Array Iterator API + *============================================================================*/ + +/** + A mutable JSON array iterator. + + @warning You should not modify the array while iterating over it, but you can + use `yyjson_mut_arr_iter_remove()` to remove current value. + + @par Example + @code + yyjson_mut_val *val; + yyjson_mut_arr_iter iter = yyjson_mut_arr_iter_with(arr); + while ((val = yyjson_mut_arr_iter_next(&iter))) { + your_func(val); + if (your_val_is_unused(val)) { + yyjson_mut_arr_iter_remove(&iter); + } + } + @endcode + */ +typedef struct yyjson_mut_arr_iter { + size_t idx; /**< next value's index */ + size_t max; /**< maximum index (arr.size) */ + yyjson_mut_val *cur; /**< current value */ + yyjson_mut_val *pre; /**< previous value */ + yyjson_mut_val *arr; /**< the array being iterated */ +} yyjson_mut_arr_iter; + +/** + Initialize an iterator for this array. + + @param arr The array to be iterated over. + If this parameter is NULL or not an array, `iter` will be set to empty. + @param iter The iterator to be initialized. + If this parameter is NULL, the function will fail and return false. + @return true if the `iter` has been successfully initialized. + + @note The iterator does not need to be destroyed. + */ +yyjson_api_inline bool yyjson_mut_arr_iter_init(yyjson_mut_val *arr, + yyjson_mut_arr_iter *iter); + +/** + Create an iterator with an array , same as `yyjson_mut_arr_iter_init()`. + + @param arr The array to be iterated over. + If this parameter is NULL or not an array, an empty iterator will returned. + @return A new iterator for the array. + + @note The iterator does not need to be destroyed. + */ +yyjson_api_inline yyjson_mut_arr_iter yyjson_mut_arr_iter_with( + yyjson_mut_val *arr); + +/** + Returns whether the iteration has more elements. + If `iter` is NULL, this function will return false. + */ +yyjson_api_inline bool yyjson_mut_arr_iter_has_next( + yyjson_mut_arr_iter *iter); + +/** + Returns the next element in the iteration, or NULL on end. + If `iter` is NULL, this function will return NULL. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_next( + yyjson_mut_arr_iter *iter); + +/** + Removes and returns current element in the iteration. + If `iter` is NULL, this function will return NULL. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_remove( + yyjson_mut_arr_iter *iter); + +/** + Macro for iterating over an array. + It works like iterator, but with a more intuitive API. + + @warning You should not modify the array while iterating over it. + + @par Example + @code + size_t idx, max; + yyjson_mut_val *val; + yyjson_mut_arr_foreach(arr, idx, max, val) { + your_func(idx, val); + } + @endcode + */ +#define yyjson_mut_arr_foreach(arr, idx, max, val) \ + for ((idx) = 0, \ + (max) = yyjson_mut_arr_size(arr), \ + (val) = yyjson_mut_arr_get_first(arr); \ + (idx) < (max); \ + (idx)++, \ + (val) = (val)->next) + + + +/*============================================================================== + * Mutable JSON Array Creation API + *============================================================================*/ + +/** + Creates and returns an empty mutable array. + @param doc A mutable document, used for memory allocation only. + @return The new array. NULL if input is NULL or memory allocation failed. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr(yyjson_mut_doc *doc); + +/** + Creates and returns a new mutable array with the given boolean values. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of boolean values. + @param count The value count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const bool vals[3] = { true, false, true }; + yyjson_mut_val *arr = yyjson_mut_arr_with_bool(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_bool( + yyjson_mut_doc *doc, const bool *vals, size_t count); + +/** + Creates and returns a new mutable array with the given sint numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of sint numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const int64_t vals[3] = { -1, 0, 1 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_sint64(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint( + yyjson_mut_doc *doc, const int64_t *vals, size_t count); + +/** + Creates and returns a new mutable array with the given uint numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of uint numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const uint64_t vals[3] = { 0, 1, 0 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_uint(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint( + yyjson_mut_doc *doc, const uint64_t *vals, size_t count); + +/** + Creates and returns a new mutable array with the given real numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of real numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const double vals[3] = { 0.1, 0.2, 0.3 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_real(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_real( + yyjson_mut_doc *doc, const double *vals, size_t count); + +/** + Creates and returns a new mutable array with the given int8 numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of int8 numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const int8_t vals[3] = { -1, 0, 1 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_sint8(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint8( + yyjson_mut_doc *doc, const int8_t *vals, size_t count); + +/** + Creates and returns a new mutable array with the given int16 numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of int16 numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const int16_t vals[3] = { -1, 0, 1 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_sint16(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint16( + yyjson_mut_doc *doc, const int16_t *vals, size_t count); + +/** + Creates and returns a new mutable array with the given int32 numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of int32 numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const int32_t vals[3] = { -1, 0, 1 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_sint32(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint32( + yyjson_mut_doc *doc, const int32_t *vals, size_t count); + +/** + Creates and returns a new mutable array with the given int64 numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of int64 numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const int64_t vals[3] = { -1, 0, 1 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_sint64(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint64( + yyjson_mut_doc *doc, const int64_t *vals, size_t count); + +/** + Creates and returns a new mutable array with the given uint8 numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of uint8 numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const uint8_t vals[3] = { 0, 1, 0 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_uint8(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint8( + yyjson_mut_doc *doc, const uint8_t *vals, size_t count); + +/** + Creates and returns a new mutable array with the given uint16 numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of uint16 numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const uint16_t vals[3] = { 0, 1, 0 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_uint16(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint16( + yyjson_mut_doc *doc, const uint16_t *vals, size_t count); + +/** + Creates and returns a new mutable array with the given uint32 numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of uint32 numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const uint32_t vals[3] = { 0, 1, 0 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_uint32(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint32( + yyjson_mut_doc *doc, const uint32_t *vals, size_t count); + +/** + Creates and returns a new mutable array with the given uint64 numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of uint64 numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const uint64_t vals[3] = { 0, 1, 0 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_uint64(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint64( + yyjson_mut_doc *doc, const uint64_t *vals, size_t count); + +/** + Creates and returns a new mutable array with the given float numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of float numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const float vals[3] = { -1.0f, 0.0f, 1.0f }; + yyjson_mut_val *arr = yyjson_mut_arr_with_float(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_float( + yyjson_mut_doc *doc, const float *vals, size_t count); + +/** + Creates and returns a new mutable array with the given double numbers. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of double numbers. + @param count The number count. If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const double vals[3] = { -1.0, 0.0, 1.0 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_double(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_double( + yyjson_mut_doc *doc, const double *vals, size_t count); + +/** + Creates and returns a new mutable array with the given strings, these strings + will not be copied. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of UTF-8 null-terminator strings. + If this array contains NULL, the function will fail and return NULL. + @param count The number of values in `vals`. + If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @warning The input strings are not copied, you should keep these strings + unmodified for the lifetime of this JSON document. If these strings will be + modified, you should use `yyjson_mut_arr_with_strcpy()` instead. + + @par Example + @code + const char *vals[3] = { "a", "b", "c" }; + yyjson_mut_val *arr = yyjson_mut_arr_with_str(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_str( + yyjson_mut_doc *doc, const char **vals, size_t count); + +/** + Creates and returns a new mutable array with the given strings and string + lengths, these strings will not be copied. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of UTF-8 strings, null-terminator is not required. + If this array contains NULL, the function will fail and return NULL. + @param lens A C array of string lengths, in bytes. + @param count The number of strings in `vals`. + If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @warning The input strings are not copied, you should keep these strings + unmodified for the lifetime of this JSON document. If these strings will be + modified, you should use `yyjson_mut_arr_with_strncpy()` instead. + + @par Example + @code + const char *vals[3] = { "a", "bb", "c" }; + const size_t lens[3] = { 1, 2, 1 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_strn(doc, vals, lens, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strn( + yyjson_mut_doc *doc, const char **vals, const size_t *lens, size_t count); + +/** + Creates and returns a new mutable array with the given strings, these strings + will be copied. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of UTF-8 null-terminator strings. + If this array contains NULL, the function will fail and return NULL. + @param count The number of values in `vals`. + If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const char *vals[3] = { "a", "b", "c" }; + yyjson_mut_val *arr = yyjson_mut_arr_with_strcpy(doc, vals, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strcpy( + yyjson_mut_doc *doc, const char **vals, size_t count); + +/** + Creates and returns a new mutable array with the given strings and string + lengths, these strings will be copied. + + @param doc A mutable document, used for memory allocation only. + If this parameter is NULL, the function will fail and return NULL. + @param vals A C array of UTF-8 strings, null-terminator is not required. + If this array contains NULL, the function will fail and return NULL. + @param lens A C array of string lengths, in bytes. + @param count The number of strings in `vals`. + If this value is 0, an empty array will return. + @return The new array. NULL if input is invalid or memory allocation failed. + + @par Example + @code + const char *vals[3] = { "a", "bb", "c" }; + const size_t lens[3] = { 1, 2, 1 }; + yyjson_mut_val *arr = yyjson_mut_arr_with_strn(doc, vals, lens, 3); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strncpy( + yyjson_mut_doc *doc, const char **vals, const size_t *lens, size_t count); + + + +/*============================================================================== + * Mutable JSON Array Modification API + *============================================================================*/ + +/** + Inserts a value into an array at a given index. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param val The value to be inserted. Returns false if it is NULL. + @param idx The index to which to insert the new value. + Returns false if the index is out of range. + @return Whether successful. + @warning This function takes a linear search time. + */ +yyjson_api_inline bool yyjson_mut_arr_insert(yyjson_mut_val *arr, + yyjson_mut_val *val, size_t idx); + +/** + Inserts a value at the end of the array. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param val The value to be inserted. Returns false if it is NULL. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_append(yyjson_mut_val *arr, + yyjson_mut_val *val); + +/** + Inserts a value at the head of the array. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param val The value to be inserted. Returns false if it is NULL. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_prepend(yyjson_mut_val *arr, + yyjson_mut_val *val); + +/** + Replaces a value at index and returns old value. + @param arr The array to which the value is to be replaced. + Returns false if it is NULL or not an array. + @param idx The index to which to replace the value. + Returns false if the index is out of range. + @param val The new value to replace. Returns false if it is NULL. + @return Old value, or NULL on error. + @warning This function takes a linear search time. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_replace(yyjson_mut_val *arr, + size_t idx, + yyjson_mut_val *val); + +/** + Removes and returns a value at index. + @param arr The array from which the value is to be removed. + Returns false if it is NULL or not an array. + @param idx The index from which to remove the value. + Returns false if the index is out of range. + @return Old value, or NULL on error. + @warning This function takes a linear search time. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove(yyjson_mut_val *arr, + size_t idx); + +/** + Removes and returns the first value in this array. + @param arr The array from which the value is to be removed. + Returns false if it is NULL or not an array. + @return The first value, or NULL on error. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove_first( + yyjson_mut_val *arr); + +/** + Removes and returns the last value in this array. + @param arr The array from which the value is to be removed. + Returns false if it is NULL or not an array. + @return The last value, or NULL on error. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove_last( + yyjson_mut_val *arr); + +/** + Removes all values within a specified range in the array. + @param arr The array from which the value is to be removed. + Returns false if it is NULL or not an array. + @param idx The start index of the range (0 is the first). + @param len The number of items in the range (can be 0). + @return Whether successful. + @warning This function takes a linear search time. + */ +yyjson_api_inline bool yyjson_mut_arr_remove_range(yyjson_mut_val *arr, + size_t idx, size_t len); + +/** + Removes all values in this array. + @param arr The array from which all of the values are to be removed. + Returns false if it is NULL or not an array. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_clear(yyjson_mut_val *arr); + +/** + Rotates values in this array for the given number of times. + For example: `[1,2,3,4,5]` rotate 2 is `[3,4,5,1,2]`. + @param arr The array to be rotated. + @param idx Index (or times) to rotate. + @warning This function takes a linear search time. + */ +yyjson_api_inline bool yyjson_mut_arr_rotate(yyjson_mut_val *arr, + size_t idx); + + + +/*============================================================================== + * Mutable JSON Array Modification Convenience API + *============================================================================*/ + +/** + Adds a value at the end of the array. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param val The value to be inserted. Returns false if it is NULL. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_add_val(yyjson_mut_val *arr, + yyjson_mut_val *val); + +/** + Adds a `null` value at the end of the array. + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_add_null(yyjson_mut_doc *doc, + yyjson_mut_val *arr); + +/** + Adds a `true` value at the end of the array. + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_add_true(yyjson_mut_doc *doc, + yyjson_mut_val *arr); + +/** + Adds a `false` value at the end of the array. + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_add_false(yyjson_mut_doc *doc, + yyjson_mut_val *arr); + +/** + Adds a bool value at the end of the array. + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param val The bool value to be added. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_add_bool(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + bool val); + +/** + Adds an unsigned integer value at the end of the array. + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param num The number to be added. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_add_uint(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + uint64_t num); + +/** + Adds a signed integer value at the end of the array. + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param num The number to be added. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_add_sint(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + int64_t num); + +/** + Adds a integer value at the end of the array. + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param num The number to be added. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_add_int(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + int64_t num); + +/** + Adds a double value at the end of the array. + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param num The number to be added. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_add_real(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + double num); + +/** + Adds a string value at the end of the array (no copy). + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param str A null-terminated UTF-8 string. + @return Whether successful. + @warning The input string is not copied, you should keep this string unmodified + for the lifetime of this JSON document. + */ +yyjson_api_inline bool yyjson_mut_arr_add_str(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + const char *str); + +/** + Adds a string value at the end of the array (no copy). + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param str A UTF-8 string, null-terminator is not required. + @param len The length of the string, in bytes. + @return Whether successful. + @warning The input string is not copied, you should keep this string unmodified + for the lifetime of this JSON document. + */ +yyjson_api_inline bool yyjson_mut_arr_add_strn(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + const char *str, + size_t len); + +/** + Adds a string value at the end of the array (copied). + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param str A null-terminated UTF-8 string. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_add_strcpy(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + const char *str); + +/** + Adds a string value at the end of the array (copied). + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @param str A UTF-8 string, null-terminator is not required. + @param len The length of the string, in bytes. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_arr_add_strncpy(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + const char *str, + size_t len); + +/** + Creates and adds a new array at the end of the array. + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @return The new array, or NULL on error. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_arr(yyjson_mut_doc *doc, + yyjson_mut_val *arr); + +/** + Creates and adds a new object at the end of the array. + @param doc The `doc` is only used for memory allocation. + @param arr The array to which the value is to be inserted. + Returns false if it is NULL or not an array. + @return The new object, or NULL on error. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_obj(yyjson_mut_doc *doc, + yyjson_mut_val *arr); + + + +/*============================================================================== + * Mutable JSON Object API + *============================================================================*/ + +/** Returns the number of key-value pairs in this object. + Returns 0 if `obj` is NULL or type is not object. */ +yyjson_api_inline size_t yyjson_mut_obj_size(yyjson_mut_val *obj); + +/** Returns the value to which the specified key is mapped. + Returns NULL if this object contains no mapping for the key. + Returns NULL if `obj/key` is NULL, or type is not object. + + The `key` should be a null-terminated UTF-8 string. + + @warning This function takes a linear search time. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_get(yyjson_mut_val *obj, + const char *key); + +/** Returns the value to which the specified key is mapped. + Returns NULL if this object contains no mapping for the key. + Returns NULL if `obj/key` is NULL, or type is not object. + + The `key` should be a UTF-8 string, null-terminator is not required. + The `key_len` should be the length of the key, in bytes. + + @warning This function takes a linear search time. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_getn(yyjson_mut_val *obj, + const char *key, + size_t key_len); + + + +/*============================================================================== + * Mutable JSON Object Iterator API + *============================================================================*/ + +/** + A mutable JSON object iterator. + + @warning You should not modify the object while iterating over it, but you can + use `yyjson_mut_obj_iter_remove()` to remove current value. + + @par Example + @code + yyjson_mut_val *key, *val; + yyjson_mut_obj_iter iter = yyjson_mut_obj_iter_with(obj); + while ((key = yyjson_mut_obj_iter_next(&iter))) { + val = yyjson_mut_obj_iter_get_val(key); + your_func(key, val); + if (your_val_is_unused(key, val)) { + yyjson_mut_obj_iter_remove(&iter); + } + } + @endcode + + If the ordering of the keys is known at compile-time, you can use this method + to speed up value lookups: + @code + // {"k1":1, "k2": 3, "k3": 3} + yyjson_mut_val *key, *val; + yyjson_mut_obj_iter iter = yyjson_mut_obj_iter_with(obj); + yyjson_mut_val *v1 = yyjson_mut_obj_iter_get(&iter, "k1"); + yyjson_mut_val *v3 = yyjson_mut_obj_iter_get(&iter, "k3"); + @endcode + @see `yyjson_mut_obj_iter_get()` and `yyjson_mut_obj_iter_getn()` + */ +typedef struct yyjson_mut_obj_iter { + size_t idx; /**< next key's index */ + size_t max; /**< maximum key index (obj.size) */ + yyjson_mut_val *cur; /**< current key */ + yyjson_mut_val *pre; /**< previous key */ + yyjson_mut_val *obj; /**< the object being iterated */ +} yyjson_mut_obj_iter; + +/** + Initialize an iterator for this object. + + @param obj The object to be iterated over. + If this parameter is NULL or not an array, `iter` will be set to empty. + @param iter The iterator to be initialized. + If this parameter is NULL, the function will fail and return false. + @return true if the `iter` has been successfully initialized. + + @note The iterator does not need to be destroyed. + */ +yyjson_api_inline bool yyjson_mut_obj_iter_init(yyjson_mut_val *obj, + yyjson_mut_obj_iter *iter); + +/** + Create an iterator with an object, same as `yyjson_obj_iter_init()`. + + @param obj The object to be iterated over. + If this parameter is NULL or not an object, an empty iterator will returned. + @return A new iterator for the object. + + @note The iterator does not need to be destroyed. + */ +yyjson_api_inline yyjson_mut_obj_iter yyjson_mut_obj_iter_with( + yyjson_mut_val *obj); + +/** + Returns whether the iteration has more elements. + If `iter` is NULL, this function will return false. + */ +yyjson_api_inline bool yyjson_mut_obj_iter_has_next( + yyjson_mut_obj_iter *iter); + +/** + Returns the next key in the iteration, or NULL on end. + If `iter` is NULL, this function will return NULL. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_next( + yyjson_mut_obj_iter *iter); + +/** + Returns the value for key inside the iteration. + If `iter` is NULL, this function will return NULL. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_get_val( + yyjson_mut_val *key); + +/** + Removes current key-value pair in the iteration, returns the removed value. + If `iter` is NULL, this function will return NULL. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_remove( + yyjson_mut_obj_iter *iter); + +/** + Iterates to a specified key and returns the value. + + This function does the same thing as `yyjson_mut_obj_get()`, but is much faster + if the ordering of the keys is known at compile-time and you are using the same + order to look up the values. If the key exists in this object, then the + iterator will stop at the next key, otherwise the iterator will not change and + NULL is returned. + + @param iter The object iterator, should not be NULL. + @param key The key, should be a UTF-8 string with null-terminator. + @return The value to which the specified key is mapped. + NULL if this object contains no mapping for the key or input is invalid. + + @warning This function takes a linear search time if the key is not nearby. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_get( + yyjson_mut_obj_iter *iter, const char *key); + +/** + Iterates to a specified key and returns the value. + + This function does the same thing as `yyjson_mut_obj_getn()` but is much faster + if the ordering of the keys is known at compile-time and you are using the same + order to look up the values. If the key exists in this object, then the + iterator will stop at the next key, otherwise the iterator will not change and + NULL is returned. + + @param iter The object iterator, should not be NULL. + @param key The key, should be a UTF-8 string, null-terminator is not required. + @param key_len The the length of `key`, in bytes. + @return The value to which the specified key is mapped. + NULL if this object contains no mapping for the key or input is invalid. + + @warning This function takes a linear search time if the key is not nearby. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_getn( + yyjson_mut_obj_iter *iter, const char *key, size_t key_len); + +/** + Macro for iterating over an object. + It works like iterator, but with a more intuitive API. + + @warning You should not modify the object while iterating over it. + + @par Example + @code + size_t idx, max; + yyjson_val *key, *val; + yyjson_obj_foreach(obj, idx, max, key, val) { + your_func(key, val); + } + @endcode + */ +#define yyjson_mut_obj_foreach(obj, idx, max, key, val) \ + for ((idx) = 0, \ + (max) = yyjson_mut_obj_size(obj), \ + (key) = (max) ? ((yyjson_mut_val *)(obj)->uni.ptr)->next->next : NULL, \ + (val) = (key) ? (key)->next : NULL; \ + (idx) < (max); \ + (idx)++, \ + (key) = (val)->next, \ + (val) = (key)->next) + + + +/*============================================================================== + * Mutable JSON Object Creation API + *============================================================================*/ + +/** Creates and returns a mutable object, returns NULL on error. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj(yyjson_mut_doc *doc); + +/** + Creates and returns a mutable object with keys and values, returns NULL on + error. The keys and values are not copied. The strings should be a + null-terminated UTF-8 string. + + @warning The input string is not copied, you should keep this string + unmodified for the lifetime of this JSON document. + + @par Example + @code + const char *keys[2] = { "id", "name" }; + const char *vals[2] = { "01", "Harry" }; + yyjson_mut_val *obj = yyjson_mut_obj_with_str(doc, keys, vals, 2); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_str(yyjson_mut_doc *doc, + const char **keys, + const char **vals, + size_t count); + +/** + Creates and returns a mutable object with key-value pairs and pair count, + returns NULL on error. The keys and values are not copied. The strings should + be a null-terminated UTF-8 string. + + @warning The input string is not copied, you should keep this string + unmodified for the lifetime of this JSON document. + + @par Example + @code + const char *kv_pairs[4] = { "id", "01", "name", "Harry" }; + yyjson_mut_val *obj = yyjson_mut_obj_with_kv(doc, kv_pairs, 2); + @endcode + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_kv(yyjson_mut_doc *doc, + const char **kv_pairs, + size_t pair_count); + + + +/*============================================================================== + * Mutable JSON Object Modification API + *============================================================================*/ + +/** + Adds a key-value pair at the end of the object. + This function allows duplicated key in one object. + @param obj The object to which the new key-value pair is to be added. + @param key The key, should be a string which is created by `yyjson_mut_str()`, + `yyjson_mut_strn()`, `yyjson_mut_strcpy()` or `yyjson_mut_strncpy()`. + @param val The value to add to the object. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_obj_add(yyjson_mut_val *obj, + yyjson_mut_val *key, + yyjson_mut_val *val); +/** + Sets a key-value pair at the end of the object. + This function may remove all key-value pairs for the given key before add. + @param obj The object to which the new key-value pair is to be added. + @param key The key, should be a string which is created by `yyjson_mut_str()`, + `yyjson_mut_strn()`, `yyjson_mut_strcpy()` or `yyjson_mut_strncpy()`. + @param val The value to add to the object. If this value is null, the behavior + is same as `yyjson_mut_obj_remove()`. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_obj_put(yyjson_mut_val *obj, + yyjson_mut_val *key, + yyjson_mut_val *val); + +/** + Inserts a key-value pair to the object at the given position. + This function allows duplicated key in one object. + @param obj The object to which the new key-value pair is to be added. + @param key The key, should be a string which is created by `yyjson_mut_str()`, + `yyjson_mut_strn()`, `yyjson_mut_strcpy()` or `yyjson_mut_strncpy()`. + @param val The value to add to the object. + @param idx The index to which to insert the new pair. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_obj_insert(yyjson_mut_val *obj, + yyjson_mut_val *key, + yyjson_mut_val *val, + size_t idx); + +/** + Removes all key-value pair from the object with given key. + @param obj The object from which the key-value pair is to be removed. + @param key The key, should be a string value. + @return The first matched value, or NULL if no matched value. + @warning This function takes a linear search time. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove(yyjson_mut_val *obj, + yyjson_mut_val *key); + +/** + Removes all key-value pair from the object with given key. + @param obj The object from which the key-value pair is to be removed. + @param key The key, should be a UTF-8 string with null-terminator. + @return The first matched value, or NULL if no matched value. + @warning This function takes a linear search time. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_key( + yyjson_mut_val *obj, const char *key); + +/** + Removes all key-value pair from the object with given key. + @param obj The object from which the key-value pair is to be removed. + @param key The key, should be a UTF-8 string, null-terminator is not required. + @param key_len The length of the key. + @return The first matched value, or NULL if no matched value. + @warning This function takes a linear search time. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_keyn( + yyjson_mut_val *obj, const char *key, size_t key_len); + +/** + Removes all key-value pairs in this object. + @param obj The object from which all of the values are to be removed. + @return Whether successful. + */ +yyjson_api_inline bool yyjson_mut_obj_clear(yyjson_mut_val *obj); + +/** + Replaces value from the object with given key. + If the key is not exist, or the value is NULL, it will fail. + @param obj The object to which the value is to be replaced. + @param key The key, should be a string value. + @param val The value to replace into the object. + @return Whether successful. + @warning This function takes a linear search time. + */ +yyjson_api_inline bool yyjson_mut_obj_replace(yyjson_mut_val *obj, + yyjson_mut_val *key, + yyjson_mut_val *val); + +/** + Rotates key-value pairs in the object for the given number of times. + For example: `{"a":1,"b":2,"c":3,"d":4}` rotate 1 is + `{"b":2,"c":3,"d":4,"a":1}`. + @param obj The object to be rotated. + @param idx Index (or times) to rotate. + @return Whether successful. + @warning This function takes a linear search time. + */ +yyjson_api_inline bool yyjson_mut_obj_rotate(yyjson_mut_val *obj, + size_t idx); + + + +/*============================================================================== + * Mutable JSON Object Modification Convenience API + *============================================================================*/ + +/** Adds a `null` value at the end of the object. + The `key` should be a null-terminated UTF-8 string. + This function allows duplicated key in one object. + + @warning The key string are not copied, you should keep the string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_null(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key); + +/** Adds a `true` value at the end of the object. + The `key` should be a null-terminated UTF-8 string. + This function allows duplicated key in one object. + + @warning The key string are not copied, you should keep the string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_true(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key); + +/** Adds a `false` value at the end of the object. + The `key` should be a null-terminated UTF-8 string. + This function allows duplicated key in one object. + + @warning The key string are not copied, you should keep the string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_false(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key); + +/** Adds a bool value at the end of the object. + The `key` should be a null-terminated UTF-8 string. + This function allows duplicated key in one object. + + @warning The key string are not copied, you should keep the string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_bool(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, bool val); + +/** Adds an unsigned integer value at the end of the object. + The `key` should be a null-terminated UTF-8 string. + This function allows duplicated key in one object. + + @warning The key string are not copied, you should keep the string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_uint(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, uint64_t val); + +/** Adds a signed integer value at the end of the object. + The `key` should be a null-terminated UTF-8 string. + This function allows duplicated key in one object. + + @warning The key string are not copied, you should keep the string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_sint(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, int64_t val); + +/** Adds an int value at the end of the object. + The `key` should be a null-terminated UTF-8 string. + This function allows duplicated key in one object. + + @warning The key string are not copied, you should keep the string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_int(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, int64_t val); + +/** Adds a double value at the end of the object. + The `key` should be a null-terminated UTF-8 string. + This function allows duplicated key in one object. + + @warning The key string are not copied, you should keep the string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_real(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, double val); + +/** Adds a string value at the end of the object. + The `key` and `val` should be null-terminated UTF-8 strings. + This function allows duplicated key in one object. + + @warning The key/value string are not copied, you should keep these strings + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_str(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, const char *val); + +/** Adds a string value at the end of the object. + The `key` should be a null-terminated UTF-8 string. + The `val` should be a UTF-8 string, null-terminator is not required. + The `len` should be the length of the `val`, in bytes. + This function allows duplicated key in one object. + + @warning The key/value string are not copied, you should keep these strings + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_strn(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, + const char *val, size_t len); + +/** Adds a string value at the end of the object. + The `key` and `val` should be null-terminated UTF-8 strings. + The value string is copied. + This function allows duplicated key in one object. + + @warning The key string are not copied, you should keep the string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_strcpy(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, + const char *val); + +/** Adds a string value at the end of the object. + The `key` should be a null-terminated UTF-8 string. + The `val` should be a UTF-8 string, null-terminator is not required. + The `len` should be the length of the `val`, in bytes. + This function allows duplicated key in one object. + + @warning The key/value string are not copied, you should keep these strings + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_strncpy(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, + const char *val, size_t len); + +/** Adds a JSON value at the end of the object. + The `key` should be a null-terminated UTF-8 string. + This function allows duplicated key in one object. + + @warning The key string are not copied, you should keep the string + unmodified for the lifetime of this JSON document. */ +yyjson_api_inline bool yyjson_mut_obj_add_val(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, + yyjson_mut_val *val); + +/** Removes all key-value pairs for the given key. + Returns the first value to which the specified key is mapped or NULL if this + object contains no mapping for the key. + The `key` should be a null-terminated UTF-8 string. + + @warning This function takes a linear search time. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_str( + yyjson_mut_val *obj, const char *key); + +/** Removes all key-value pairs for the given key. + Returns the first value to which the specified key is mapped or NULL if this + object contains no mapping for the key. + The `key` should be a UTF-8 string, null-terminator is not required. + The `len` should be the length of the key, in bytes. + + @warning This function takes a linear search time. */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_strn( + yyjson_mut_val *obj, const char *key, size_t len); + +/** Replaces all matching keys with the new key. + Returns true if at least one key was renamed. + The `key` and `new_key` should be a null-terminated UTF-8 string. + The `new_key` is copied and held by doc. + + @warning This function takes a linear search time. + If `new_key` already exists, it will cause duplicate keys. + */ +yyjson_api_inline bool yyjson_mut_obj_rename_key(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, + const char *new_key); + +/** Replaces all matching keys with the new key. + Returns true if at least one key was renamed. + The `key` and `new_key` should be a UTF-8 string, + null-terminator is not required. The `new_key` is copied and held by doc. + + @warning This function takes a linear search time. + If `new_key` already exists, it will cause duplicate keys. + */ +yyjson_api_inline bool yyjson_mut_obj_rename_keyn(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, + size_t len, + const char *new_key, + size_t new_len); + + + +/*============================================================================== + * JSON Pointer API (RFC 6901) + * https://tools.ietf.org/html/rfc6901 + *============================================================================*/ + +/** JSON Pointer error code. */ +typedef uint32_t yyjson_ptr_code; + +/** No JSON pointer error. */ +static const yyjson_ptr_code YYJSON_PTR_ERR_NONE = 0; + +/** Invalid input parameter, such as NULL input. */ +static const yyjson_ptr_code YYJSON_PTR_ERR_PARAMETER = 1; + +/** JSON pointer syntax error, such as invalid escape, token no prefix. */ +static const yyjson_ptr_code YYJSON_PTR_ERR_SYNTAX = 2; + +/** JSON pointer resolve failed, such as index out of range, key not found. */ +static const yyjson_ptr_code YYJSON_PTR_ERR_RESOLVE = 3; + +/** Document's root is NULL, but it is required for the function call. */ +static const yyjson_ptr_code YYJSON_PTR_ERR_NULL_ROOT = 4; + +/** Cannot set root as the target is not a document. */ +static const yyjson_ptr_code YYJSON_PTR_ERR_SET_ROOT = 5; + +/** The memory allocation failed and a new value could not be created. */ +static const yyjson_ptr_code YYJSON_PTR_ERR_MEMORY_ALLOCATION = 6; + +/** Error information for JSON pointer. */ +typedef struct yyjson_ptr_err { + /** Error code, see `yyjson_ptr_code` for all possible values. */ + yyjson_ptr_code code; + /** Error message, constant, no need to free (NULL if no error). */ + const char *msg; + /** Error byte position for input JSON pointer (0 if no error). */ + size_t pos; +} yyjson_ptr_err; + +/** + A context for JSON pointer operation. + + This struct stores the context of JSON Pointer operation result. The struct + can be used with three helper functions: `ctx_append()`, `ctx_replace()`, and + `ctx_remove()`, which perform the corresponding operations on the container + without re-parsing the JSON Pointer. + + For example: + @code + // doc before: {"a":[0,1,null]} + // ptr: "/a/2" + val = yyjson_mut_doc_ptr_getx(doc, ptr, strlen(ptr), &ctx, &err); + if (yyjson_is_null(val)) { + yyjson_ptr_ctx_remove(&ctx); + } + // doc after: {"a":[0,1]} + @endcode + */ +typedef struct yyjson_ptr_ctx { + /** + The container (parent) of the target value. It can be either an array or + an object. If the target location has no value, but all its parent + containers exist, and the target location can be used to insert a new + value, then `ctn` is the parent container of the target location. + Otherwise, `ctn` is NULL. + */ + yyjson_mut_val *ctn; + /** + The previous sibling of the target value. It can be either a value in an + array or a key in an object. As the container is a `circular linked list` + of elements, `pre` is the previous node of the target value. If the + operation is `add` or `set`, then `pre` is the previous node of the new + value, not the original target value. If the target value does not exist, + `pre` is NULL. + */ + yyjson_mut_val *pre; + /** + The removed value if the operation is `set`, `replace` or `remove`. It can + be used to restore the original state of the document if needed. + */ + yyjson_mut_val *old; +} yyjson_ptr_ctx; + +/** + Get value by a JSON Pointer. + @param doc The JSON document to be queried. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @return The value referenced by the JSON pointer. + NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_val *yyjson_doc_ptr_get(yyjson_doc *doc, + const char *ptr); + +/** + Get value by a JSON Pointer. + @param doc The JSON document to be queried. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @return The value referenced by the JSON pointer. + NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_val *yyjson_doc_ptr_getn(yyjson_doc *doc, + const char *ptr, size_t len); + +/** + Get value by a JSON Pointer. + @param doc The JSON document to be queried. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param err A pointer to store the error information, or NULL if not needed. + @return The value referenced by the JSON pointer. + NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_val *yyjson_doc_ptr_getx(yyjson_doc *doc, + const char *ptr, size_t len, + yyjson_ptr_err *err); + +/** + Get value by a JSON Pointer. + @param val The JSON value to be queried. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @return The value referenced by the JSON pointer. + NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_val *yyjson_ptr_get(yyjson_val *val, + const char *ptr); + +/** + Get value by a JSON Pointer. + @param val The JSON value to be queried. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @return The value referenced by the JSON pointer. + NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_val *yyjson_ptr_getn(yyjson_val *val, + const char *ptr, size_t len); + +/** + Get value by a JSON Pointer. + @param val The JSON value to be queried. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param err A pointer to store the error information, or NULL if not needed. + @return The value referenced by the JSON pointer. + NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_val *yyjson_ptr_getx(yyjson_val *val, + const char *ptr, size_t len, + yyjson_ptr_err *err); + +/** + Get value by a JSON Pointer. + @param doc The JSON document to be queried. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @return The value referenced by the JSON pointer. + NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_get(yyjson_mut_doc *doc, + const char *ptr); + +/** + Get value by a JSON Pointer. + @param doc The JSON document to be queried. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @return The value referenced by the JSON pointer. + NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_getn(yyjson_mut_doc *doc, + const char *ptr, + size_t len); + +/** + Get value by a JSON Pointer. + @param doc The JSON document to be queried. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param ctx A pointer to store the result context, or NULL if not needed. + @param err A pointer to store the error information, or NULL if not needed. + @return The value referenced by the JSON pointer. + NULL if `doc` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_getx(yyjson_mut_doc *doc, + const char *ptr, + size_t len, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err); + +/** + Get value by a JSON Pointer. + @param val The JSON value to be queried. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @return The value referenced by the JSON pointer. + NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_get(yyjson_mut_val *val, + const char *ptr); + +/** + Get value by a JSON Pointer. + @param val The JSON value to be queried. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @return The value referenced by the JSON pointer. + NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_getn(yyjson_mut_val *val, + const char *ptr, + size_t len); + +/** + Get value by a JSON Pointer. + @param val The JSON value to be queried. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param ctx A pointer to store the result context, or NULL if not needed. + @param err A pointer to store the error information, or NULL if not needed. + @return The value referenced by the JSON pointer. + NULL if `val` or `ptr` is NULL, or the JSON pointer cannot be resolved. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_getx(yyjson_mut_val *val, + const char *ptr, + size_t len, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err); + +/** + Add (insert) value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @param new_val The value to be added. + @return true if JSON pointer is valid and new value is added, false otherwise. + @note The parent nodes will be created if they do not exist. + */ +yyjson_api_inline bool yyjson_mut_doc_ptr_add(yyjson_mut_doc *doc, + const char *ptr, + yyjson_mut_val *new_val); + +/** + Add (insert) value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param new_val The value to be added. + @return true if JSON pointer is valid and new value is added, false otherwise. + @note The parent nodes will be created if they do not exist. + */ +yyjson_api_inline bool yyjson_mut_doc_ptr_addn(yyjson_mut_doc *doc, + const char *ptr, size_t len, + yyjson_mut_val *new_val); + +/** + Add (insert) value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param new_val The value to be added. + @param create_parent Whether to create parent nodes if not exist. + @param ctx A pointer to store the result context, or NULL if not needed. + @param err A pointer to store the error information, or NULL if not needed. + @return true if JSON pointer is valid and new value is added, false otherwise. + */ +yyjson_api_inline bool yyjson_mut_doc_ptr_addx(yyjson_mut_doc *doc, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + bool create_parent, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err); + +/** + Add (insert) value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @param doc Only used to create new values when needed. + @param new_val The value to be added. + @return true if JSON pointer is valid and new value is added, false otherwise. + @note The parent nodes will be created if they do not exist. + */ +yyjson_api_inline bool yyjson_mut_ptr_add(yyjson_mut_val *val, + const char *ptr, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc); + +/** + Add (insert) value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param doc Only used to create new values when needed. + @param new_val The value to be added. + @return true if JSON pointer is valid and new value is added, false otherwise. + @note The parent nodes will be created if they do not exist. + */ +yyjson_api_inline bool yyjson_mut_ptr_addn(yyjson_mut_val *val, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc); + +/** + Add (insert) value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param doc Only used to create new values when needed. + @param new_val The value to be added. + @param create_parent Whether to create parent nodes if not exist. + @param ctx A pointer to store the result context, or NULL if not needed. + @param err A pointer to store the error information, or NULL if not needed. + @return true if JSON pointer is valid and new value is added, false otherwise. + */ +yyjson_api_inline bool yyjson_mut_ptr_addx(yyjson_mut_val *val, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc, + bool create_parent, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err); + +/** + Set value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @param new_val The value to be set, pass NULL to remove. + @return true if JSON pointer is valid and new value is set, false otherwise. + @note The parent nodes will be created if they do not exist. + If the target value already exists, it will be replaced by the new value. + */ +yyjson_api_inline bool yyjson_mut_doc_ptr_set(yyjson_mut_doc *doc, + const char *ptr, + yyjson_mut_val *new_val); + +/** + Set value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param new_val The value to be set, pass NULL to remove. + @return true if JSON pointer is valid and new value is set, false otherwise. + @note The parent nodes will be created if they do not exist. + If the target value already exists, it will be replaced by the new value. + */ +yyjson_api_inline bool yyjson_mut_doc_ptr_setn(yyjson_mut_doc *doc, + const char *ptr, size_t len, + yyjson_mut_val *new_val); + +/** + Set value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param new_val The value to be set, pass NULL to remove. + @param create_parent Whether to create parent nodes if not exist. + @param ctx A pointer to store the result context, or NULL if not needed. + @param err A pointer to store the error information, or NULL if not needed. + @return true if JSON pointer is valid and new value is set, false otherwise. + @note If the target value already exists, it will be replaced by the new value. + */ +yyjson_api_inline bool yyjson_mut_doc_ptr_setx(yyjson_mut_doc *doc, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + bool create_parent, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err); + +/** + Set value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @param new_val The value to be set, pass NULL to remove. + @param doc Only used to create new values when needed. + @return true if JSON pointer is valid and new value is set, false otherwise. + @note The parent nodes will be created if they do not exist. + If the target value already exists, it will be replaced by the new value. + */ +yyjson_api_inline bool yyjson_mut_ptr_set(yyjson_mut_val *val, + const char *ptr, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc); + +/** + Set value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param new_val The value to be set, pass NULL to remove. + @param doc Only used to create new values when needed. + @return true if JSON pointer is valid and new value is set, false otherwise. + @note The parent nodes will be created if they do not exist. + If the target value already exists, it will be replaced by the new value. + */ +yyjson_api_inline bool yyjson_mut_ptr_setn(yyjson_mut_val *val, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc); + +/** + Set value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param new_val The value to be set, pass NULL to remove. + @param doc Only used to create new values when needed. + @param create_parent Whether to create parent nodes if not exist. + @param ctx A pointer to store the result context, or NULL if not needed. + @param err A pointer to store the error information, or NULL if not needed. + @return true if JSON pointer is valid and new value is set, false otherwise. + @note If the target value already exists, it will be replaced by the new value. + */ +yyjson_api_inline bool yyjson_mut_ptr_setx(yyjson_mut_val *val, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc, + bool create_parent, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err); + +/** + Replace value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @param new_val The new value to replace the old one. + @return The old value that was replaced, or NULL if not found. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replace( + yyjson_mut_doc *doc, const char *ptr, yyjson_mut_val *new_val); + +/** + Replace value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param new_val The new value to replace the old one. + @return The old value that was replaced, or NULL if not found. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replacen( + yyjson_mut_doc *doc, const char *ptr, size_t len, yyjson_mut_val *new_val); + +/** + Replace value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param new_val The new value to replace the old one. + @param ctx A pointer to store the result context, or NULL if not needed. + @param err A pointer to store the error information, or NULL if not needed. + @return The old value that was replaced, or NULL if not found. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replacex( + yyjson_mut_doc *doc, const char *ptr, size_t len, yyjson_mut_val *new_val, + yyjson_ptr_ctx *ctx, yyjson_ptr_err *err); + +/** + Replace value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @param new_val The new value to replace the old one. + @return The old value that was replaced, or NULL if not found. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replace( + yyjson_mut_val *val, const char *ptr, yyjson_mut_val *new_val); + +/** + Replace value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param new_val The new value to replace the old one. + @return The old value that was replaced, or NULL if not found. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replacen( + yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val); + +/** + Replace value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param new_val The new value to replace the old one. + @param ctx A pointer to store the result context, or NULL if not needed. + @param err A pointer to store the error information, or NULL if not needed. + @return The old value that was replaced, or NULL if not found. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replacex( + yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val, + yyjson_ptr_ctx *ctx, yyjson_ptr_err *err); + +/** + Remove value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @return The removed value, or NULL on error. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_remove( + yyjson_mut_doc *doc, const char *ptr); + +/** + Remove value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @return The removed value, or NULL on error. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_removen( + yyjson_mut_doc *doc, const char *ptr, size_t len); + +/** + Remove value by a JSON pointer. + @param doc The target JSON document. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param ctx A pointer to store the result context, or NULL if not needed. + @param err A pointer to store the error information, or NULL if not needed. + @return The removed value, or NULL on error. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_removex( + yyjson_mut_doc *doc, const char *ptr, size_t len, + yyjson_ptr_ctx *ctx, yyjson_ptr_err *err); + +/** + Remove value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8 with null-terminator). + @return The removed value, or NULL on error. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_remove(yyjson_mut_val *val, + const char *ptr); + +/** + Remove value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @return The removed value, or NULL on error. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_removen(yyjson_mut_val *val, + const char *ptr, + size_t len); + +/** + Remove value by a JSON pointer. + @param val The target JSON value. + @param ptr The JSON pointer string (UTF-8, null-terminator is not required). + @param len The length of `ptr` in bytes. + @param ctx A pointer to store the result context, or NULL if not needed. + @param err A pointer to store the error information, or NULL if not needed. + @return The removed value, or NULL on error. + */ +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_removex(yyjson_mut_val *val, + const char *ptr, + size_t len, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err); + +/** + Append value by JSON pointer context. + @param ctx The context from the `yyjson_mut_ptr_xxx()` calls. + @param key New key if `ctx->ctn` is object, or NULL if `ctx->ctn` is array. + @param val New value to be added. + @return true on success or false on fail. + */ +yyjson_api_inline bool yyjson_ptr_ctx_append(yyjson_ptr_ctx *ctx, + yyjson_mut_val *key, + yyjson_mut_val *val); + +/** + Replace value by JSON pointer context. + @param ctx The context from the `yyjson_mut_ptr_xxx()` calls. + @param val New value to be replaced. + @return true on success or false on fail. + @note If success, the old value will be returned via `ctx->old`. + */ +yyjson_api_inline bool yyjson_ptr_ctx_replace(yyjson_ptr_ctx *ctx, + yyjson_mut_val *val); + +/** + Remove value by JSON pointer context. + @param ctx The context from the `yyjson_mut_ptr_xxx()` calls. + @return true on success or false on fail. + @note If success, the old value will be returned via `ctx->old`. + */ +yyjson_api_inline bool yyjson_ptr_ctx_remove(yyjson_ptr_ctx *ctx); + + + +/*============================================================================== + * JSON Patch API (RFC 6902) + * https://tools.ietf.org/html/rfc6902 + *============================================================================*/ + +/** Result code for JSON patch. */ +typedef uint32_t yyjson_patch_code; + +/** Success, no error. */ +static const yyjson_patch_code YYJSON_PATCH_SUCCESS = 0; + +/** Invalid parameter, such as NULL input or non-array patch. */ +static const yyjson_patch_code YYJSON_PATCH_ERROR_INVALID_PARAMETER = 1; + +/** Memory allocation failure occurs. */ +static const yyjson_patch_code YYJSON_PATCH_ERROR_MEMORY_ALLOCATION = 2; + +/** JSON patch operation is not object type. */ +static const yyjson_patch_code YYJSON_PATCH_ERROR_INVALID_OPERATION = 3; + +/** JSON patch operation is missing a required key. */ +static const yyjson_patch_code YYJSON_PATCH_ERROR_MISSING_KEY = 4; + +/** JSON patch operation member is invalid. */ +static const yyjson_patch_code YYJSON_PATCH_ERROR_INVALID_MEMBER = 5; + +/** JSON patch operation `test` not equal. */ +static const yyjson_patch_code YYJSON_PATCH_ERROR_EQUAL = 6; + +/** JSON patch operation failed on JSON pointer. */ +static const yyjson_patch_code YYJSON_PATCH_ERROR_POINTER = 7; + +/** Error information for JSON patch. */ +typedef struct yyjson_patch_err { + /** Error code, see `yyjson_patch_code` for all possible values. */ + yyjson_patch_code code; + /** Index of the error operation (0 if no error). */ + size_t idx; + /** Error message, constant, no need to free (NULL if no error). */ + const char *msg; + /** JSON pointer error if `code == YYJSON_PATCH_ERROR_POINTER`. */ + yyjson_ptr_err ptr; +} yyjson_patch_err; + +/** + Creates and returns a patched JSON value (RFC 6902). + The memory of the returned value is allocated by the `doc`. + The `err` is used to receive error information, pass NULL if not needed. + Returns NULL if the patch could not be applied. + */ +yyjson_api yyjson_mut_val *yyjson_patch(yyjson_mut_doc *doc, + yyjson_val *orig, + yyjson_val *patch, + yyjson_patch_err *err); + +/** + Creates and returns a patched JSON value (RFC 6902). + The memory of the returned value is allocated by the `doc`. + The `err` is used to receive error information, pass NULL if not needed. + Returns NULL if the patch could not be applied. + */ +yyjson_api yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc, + yyjson_mut_val *orig, + yyjson_mut_val *patch, + yyjson_patch_err *err); + + + +/*============================================================================== + * JSON Merge-Patch API (RFC 7386) + * https://tools.ietf.org/html/rfc7386 + *============================================================================*/ + +/** + Creates and returns a merge-patched JSON value (RFC 7386). + The memory of the returned value is allocated by the `doc`. + Returns NULL if the patch could not be applied. + + @warning This function is recursive and may cause a stack overflow if the + object level is too deep. + */ +yyjson_api yyjson_mut_val *yyjson_merge_patch(yyjson_mut_doc *doc, + yyjson_val *orig, + yyjson_val *patch); + +/** + Creates and returns a merge-patched JSON value (RFC 7386). + The memory of the returned value is allocated by the `doc`. + Returns NULL if the patch could not be applied. + + @warning This function is recursive and may cause a stack overflow if the + object level is too deep. + */ +yyjson_api yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc, + yyjson_mut_val *orig, + yyjson_mut_val *patch); + + + +/*============================================================================== + * JSON Structure (Implementation) + *============================================================================*/ + +/** Payload of a JSON value (8 bytes). */ +typedef union yyjson_val_uni { + uint64_t u64; + int64_t i64; + double f64; + const char *str; + void *ptr; + size_t ofs; +} yyjson_val_uni; + +/** + Immutable JSON value, 16 bytes. + */ +struct yyjson_val { + uint64_t tag; /**< type, subtype and length */ + yyjson_val_uni uni; /**< payload */ +}; + +struct yyjson_doc { + /** Root value of the document (nonnull). */ + yyjson_val *root; + /** Allocator used by document (nonnull). */ + yyjson_alc alc; + /** The total number of bytes read when parsing JSON (nonzero). */ + size_t dat_read; + /** The total number of value read when parsing JSON (nonzero). */ + size_t val_read; + /** The string pool used by JSON values (nullable). */ + char *str_pool; +}; + + + +/*============================================================================== + * Unsafe JSON Value API (Implementation) + *============================================================================*/ + +yyjson_api_inline yyjson_type unsafe_yyjson_get_type(void *val) { + uint8_t tag = (uint8_t)((yyjson_val *)val)->tag; + return (yyjson_type)(tag & YYJSON_TYPE_MASK); +} + +yyjson_api_inline yyjson_subtype unsafe_yyjson_get_subtype(void *val) { + uint8_t tag = (uint8_t)((yyjson_val *)val)->tag; + return (yyjson_subtype)(tag & YYJSON_SUBTYPE_MASK); +} + +yyjson_api_inline uint8_t unsafe_yyjson_get_tag(void *val) { + uint8_t tag = (uint8_t)((yyjson_val *)val)->tag; + return (uint8_t)(tag & YYJSON_TAG_MASK); +} + +yyjson_api_inline bool unsafe_yyjson_is_raw(void *val) { + return unsafe_yyjson_get_type(val) == YYJSON_TYPE_RAW; +} + +yyjson_api_inline bool unsafe_yyjson_is_null(void *val) { + return unsafe_yyjson_get_type(val) == YYJSON_TYPE_NULL; +} + +yyjson_api_inline bool unsafe_yyjson_is_bool(void *val) { + return unsafe_yyjson_get_type(val) == YYJSON_TYPE_BOOL; +} + +yyjson_api_inline bool unsafe_yyjson_is_num(void *val) { + return unsafe_yyjson_get_type(val) == YYJSON_TYPE_NUM; +} + +yyjson_api_inline bool unsafe_yyjson_is_str(void *val) { + return unsafe_yyjson_get_type(val) == YYJSON_TYPE_STR; +} + +yyjson_api_inline bool unsafe_yyjson_is_arr(void *val) { + return unsafe_yyjson_get_type(val) == YYJSON_TYPE_ARR; +} + +yyjson_api_inline bool unsafe_yyjson_is_obj(void *val) { + return unsafe_yyjson_get_type(val) == YYJSON_TYPE_OBJ; +} + +yyjson_api_inline bool unsafe_yyjson_is_ctn(void *val) { + uint8_t mask = YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ; + return (unsafe_yyjson_get_tag(val) & mask) == mask; +} + +yyjson_api_inline bool unsafe_yyjson_is_uint(void *val) { + const uint8_t patt = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT; + return unsafe_yyjson_get_tag(val) == patt; +} + +yyjson_api_inline bool unsafe_yyjson_is_sint(void *val) { + const uint8_t patt = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT; + return unsafe_yyjson_get_tag(val) == patt; +} + +yyjson_api_inline bool unsafe_yyjson_is_int(void *val) { + const uint8_t mask = YYJSON_TAG_MASK & (~YYJSON_SUBTYPE_SINT); + const uint8_t patt = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT; + return (unsafe_yyjson_get_tag(val) & mask) == patt; +} + +yyjson_api_inline bool unsafe_yyjson_is_real(void *val) { + const uint8_t patt = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; + return unsafe_yyjson_get_tag(val) == patt; +} + +yyjson_api_inline bool unsafe_yyjson_is_true(void *val) { + const uint8_t patt = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE; + return unsafe_yyjson_get_tag(val) == patt; +} + +yyjson_api_inline bool unsafe_yyjson_is_false(void *val) { + const uint8_t patt = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE; + return unsafe_yyjson_get_tag(val) == patt; +} + +yyjson_api_inline bool unsafe_yyjson_arr_is_flat(yyjson_val *val) { + size_t ofs = val->uni.ofs; + size_t len = (size_t)(val->tag >> YYJSON_TAG_BIT); + return len * sizeof(yyjson_val) + sizeof(yyjson_val) == ofs; +} + +yyjson_api_inline const char *unsafe_yyjson_get_raw(void *val) { + return ((yyjson_val *)val)->uni.str; +} + +yyjson_api_inline bool unsafe_yyjson_get_bool(void *val) { + uint8_t tag = unsafe_yyjson_get_tag(val); + return (bool)((tag & YYJSON_SUBTYPE_MASK) >> YYJSON_TYPE_BIT); +} + +yyjson_api_inline uint64_t unsafe_yyjson_get_uint(void *val) { + return ((yyjson_val *)val)->uni.u64; +} + +yyjson_api_inline int64_t unsafe_yyjson_get_sint(void *val) { + return ((yyjson_val *)val)->uni.i64; +} + +yyjson_api_inline int unsafe_yyjson_get_int(void *val) { + return (int)((yyjson_val *)val)->uni.i64; +} + +yyjson_api_inline double unsafe_yyjson_get_real(void *val) { + return ((yyjson_val *)val)->uni.f64; +} + +yyjson_api_inline double unsafe_yyjson_get_num(void *val) { + uint8_t tag = unsafe_yyjson_get_tag(val); + if (tag == (YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL)) { + return ((yyjson_val *)val)->uni.f64; + } else if (tag == (YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT)) { + return (double)((yyjson_val *)val)->uni.i64; + } else if (tag == (YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT)) { +#if YYJSON_U64_TO_F64_NO_IMPL + uint64_t msb = ((uint64_t)1) << 63; + uint64_t num = ((yyjson_val *)val)->uni.u64; + if ((num & msb) == 0) { + return (double)(int64_t)num; + } else { + return ((double)(int64_t)((num >> 1) | (num & 1))) * (double)2.0; + } +#else + return (double)((yyjson_val *)val)->uni.u64; +#endif + } + return 0.0; +} + +yyjson_api_inline const char *unsafe_yyjson_get_str(void *val) { + return ((yyjson_val *)val)->uni.str; +} + +yyjson_api_inline size_t unsafe_yyjson_get_len(void *val) { + return (size_t)(((yyjson_val *)val)->tag >> YYJSON_TAG_BIT); +} + +yyjson_api_inline yyjson_val *unsafe_yyjson_get_first(yyjson_val *ctn) { + return ctn + 1; +} + +yyjson_api_inline yyjson_val *unsafe_yyjson_get_next(yyjson_val *val) { + bool is_ctn = unsafe_yyjson_is_ctn(val); + size_t ctn_ofs = val->uni.ofs; + size_t ofs = (is_ctn ? ctn_ofs : sizeof(yyjson_val)); + return (yyjson_val *)(void *)((uint8_t *)val + ofs); +} + +yyjson_api_inline bool unsafe_yyjson_equals_strn(void *val, const char *str, + size_t len) { + uint64_t tag = ((uint64_t)len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + return ((yyjson_val *)val)->tag == tag && + memcmp(((yyjson_val *)val)->uni.str, str, len) == 0; +} + +yyjson_api_inline bool unsafe_yyjson_equals_str(void *val, const char *str) { + return unsafe_yyjson_equals_strn(val, str, strlen(str)); +} + +yyjson_api_inline void unsafe_yyjson_set_type(void *val, yyjson_type type, + yyjson_subtype subtype) { + uint8_t tag = (type | subtype); + uint64_t new_tag = ((yyjson_val *)val)->tag; + new_tag = (new_tag & (~(uint64_t)YYJSON_TAG_MASK)) | (uint64_t)tag; + ((yyjson_val *)val)->tag = new_tag; +} + +yyjson_api_inline void unsafe_yyjson_set_len(void *val, size_t len) { + uint64_t tag = ((yyjson_val *)val)->tag & YYJSON_TAG_MASK; + tag |= (uint64_t)len << YYJSON_TAG_BIT; + ((yyjson_val *)val)->tag = tag; +} + +yyjson_api_inline void unsafe_yyjson_inc_len(void *val) { + uint64_t tag = ((yyjson_val *)val)->tag; + tag += (uint64_t)(1 << YYJSON_TAG_BIT); + ((yyjson_val *)val)->tag = tag; +} + +yyjson_api_inline void unsafe_yyjson_set_raw(void *val, const char *raw, + size_t len) { + unsafe_yyjson_set_type(val, YYJSON_TYPE_RAW, YYJSON_SUBTYPE_NONE); + unsafe_yyjson_set_len(val, len); + ((yyjson_val *)val)->uni.str = raw; +} + +yyjson_api_inline void unsafe_yyjson_set_null(void *val) { + unsafe_yyjson_set_type(val, YYJSON_TYPE_NULL, YYJSON_SUBTYPE_NONE); + unsafe_yyjson_set_len(val, 0); +} + +yyjson_api_inline void unsafe_yyjson_set_bool(void *val, bool num) { + yyjson_subtype subtype = num ? YYJSON_SUBTYPE_TRUE : YYJSON_SUBTYPE_FALSE; + unsafe_yyjson_set_type(val, YYJSON_TYPE_BOOL, subtype); + unsafe_yyjson_set_len(val, 0); +} + +yyjson_api_inline void unsafe_yyjson_set_uint(void *val, uint64_t num) { + unsafe_yyjson_set_type(val, YYJSON_TYPE_NUM, YYJSON_SUBTYPE_UINT); + unsafe_yyjson_set_len(val, 0); + ((yyjson_val *)val)->uni.u64 = num; +} + +yyjson_api_inline void unsafe_yyjson_set_sint(void *val, int64_t num) { + unsafe_yyjson_set_type(val, YYJSON_TYPE_NUM, YYJSON_SUBTYPE_SINT); + unsafe_yyjson_set_len(val, 0); + ((yyjson_val *)val)->uni.i64 = num; +} + +yyjson_api_inline void unsafe_yyjson_set_real(void *val, double num) { + unsafe_yyjson_set_type(val, YYJSON_TYPE_NUM, YYJSON_SUBTYPE_REAL); + unsafe_yyjson_set_len(val, 0); + ((yyjson_val *)val)->uni.f64 = num; +} + +yyjson_api_inline void unsafe_yyjson_set_str(void *val, const char *str) { + unsafe_yyjson_set_type(val, YYJSON_TYPE_STR, YYJSON_SUBTYPE_NONE); + unsafe_yyjson_set_len(val, strlen(str)); + ((yyjson_val *)val)->uni.str = str; +} + +yyjson_api_inline void unsafe_yyjson_set_strn(void *val, const char *str, + size_t len) { + unsafe_yyjson_set_type(val, YYJSON_TYPE_STR, YYJSON_SUBTYPE_NONE); + unsafe_yyjson_set_len(val, len); + ((yyjson_val *)val)->uni.str = str; +} + +yyjson_api_inline void unsafe_yyjson_set_arr(void *val, size_t size) { + unsafe_yyjson_set_type(val, YYJSON_TYPE_ARR, YYJSON_SUBTYPE_NONE); + unsafe_yyjson_set_len(val, size); +} + +yyjson_api_inline void unsafe_yyjson_set_obj(void *val, size_t size) { + unsafe_yyjson_set_type(val, YYJSON_TYPE_OBJ, YYJSON_SUBTYPE_NONE); + unsafe_yyjson_set_len(val, size); +} + + + +/*============================================================================== + * JSON Document API (Implementation) + *============================================================================*/ + +yyjson_api_inline yyjson_val *yyjson_doc_get_root(yyjson_doc *doc) { + return doc ? doc->root : NULL; +} + +yyjson_api_inline size_t yyjson_doc_get_read_size(yyjson_doc *doc) { + return doc ? doc->dat_read : 0; +} + +yyjson_api_inline size_t yyjson_doc_get_val_count(yyjson_doc *doc) { + return doc ? doc->val_read : 0; +} + +yyjson_api_inline void yyjson_doc_free(yyjson_doc *doc) { + if (doc) { + yyjson_alc alc = doc->alc; + if (doc->str_pool) alc.free(alc.ctx, doc->str_pool); + alc.free(alc.ctx, doc); + } +} + + + +/*============================================================================== + * JSON Value Type API (Implementation) + *============================================================================*/ + +yyjson_api_inline bool yyjson_is_raw(yyjson_val *val) { + return val ? unsafe_yyjson_is_raw(val) : false; +} + +yyjson_api_inline bool yyjson_is_null(yyjson_val *val) { + return val ? unsafe_yyjson_is_null(val) : false; +} + +yyjson_api_inline bool yyjson_is_true(yyjson_val *val) { + return val ? unsafe_yyjson_is_true(val) : false; +} + +yyjson_api_inline bool yyjson_is_false(yyjson_val *val) { + return val ? unsafe_yyjson_is_false(val) : false; +} + +yyjson_api_inline bool yyjson_is_bool(yyjson_val *val) { + return val ? unsafe_yyjson_is_bool(val) : false; +} + +yyjson_api_inline bool yyjson_is_uint(yyjson_val *val) { + return val ? unsafe_yyjson_is_uint(val) : false; +} + +yyjson_api_inline bool yyjson_is_sint(yyjson_val *val) { + return val ? unsafe_yyjson_is_sint(val) : false; +} + +yyjson_api_inline bool yyjson_is_int(yyjson_val *val) { + return val ? unsafe_yyjson_is_int(val) : false; +} + +yyjson_api_inline bool yyjson_is_real(yyjson_val *val) { + return val ? unsafe_yyjson_is_real(val) : false; +} + +yyjson_api_inline bool yyjson_is_num(yyjson_val *val) { + return val ? unsafe_yyjson_is_num(val) : false; +} + +yyjson_api_inline bool yyjson_is_str(yyjson_val *val) { + return val ? unsafe_yyjson_is_str(val) : false; +} + +yyjson_api_inline bool yyjson_is_arr(yyjson_val *val) { + return val ? unsafe_yyjson_is_arr(val) : false; +} + +yyjson_api_inline bool yyjson_is_obj(yyjson_val *val) { + return val ? unsafe_yyjson_is_obj(val) : false; +} + +yyjson_api_inline bool yyjson_is_ctn(yyjson_val *val) { + return val ? unsafe_yyjson_is_ctn(val) : false; +} + + + +/*============================================================================== + * JSON Value Content API (Implementation) + *============================================================================*/ + +yyjson_api_inline yyjson_type yyjson_get_type(yyjson_val *val) { + return val ? unsafe_yyjson_get_type(val) : YYJSON_TYPE_NONE; +} + +yyjson_api_inline yyjson_subtype yyjson_get_subtype(yyjson_val *val) { + return val ? unsafe_yyjson_get_subtype(val) : YYJSON_SUBTYPE_NONE; +} + +yyjson_api_inline uint8_t yyjson_get_tag(yyjson_val *val) { + return val ? unsafe_yyjson_get_tag(val) : 0; +} + +yyjson_api_inline const char *yyjson_get_type_desc(yyjson_val *val) { + switch (yyjson_get_tag(val)) { + case YYJSON_TYPE_RAW | YYJSON_SUBTYPE_NONE: return "raw"; + case YYJSON_TYPE_NULL | YYJSON_SUBTYPE_NONE: return "null"; + case YYJSON_TYPE_STR | YYJSON_SUBTYPE_NONE: return "string"; + case YYJSON_TYPE_ARR | YYJSON_SUBTYPE_NONE: return "array"; + case YYJSON_TYPE_OBJ | YYJSON_SUBTYPE_NONE: return "object"; + case YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE: return "true"; + case YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE: return "false"; + case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT: return "uint"; + case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT: return "sint"; + case YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL: return "real"; + default: return "unknown"; + } +} + +yyjson_api_inline const char *yyjson_get_raw(yyjson_val *val) { + return yyjson_is_raw(val) ? unsafe_yyjson_get_raw(val) : NULL; +} + +yyjson_api_inline bool yyjson_get_bool(yyjson_val *val) { + return yyjson_is_bool(val) ? unsafe_yyjson_get_bool(val) : false; +} + +yyjson_api_inline uint64_t yyjson_get_uint(yyjson_val *val) { + return yyjson_is_int(val) ? unsafe_yyjson_get_uint(val) : 0; +} + +yyjson_api_inline int64_t yyjson_get_sint(yyjson_val *val) { + return yyjson_is_int(val) ? unsafe_yyjson_get_sint(val) : 0; +} + +yyjson_api_inline int yyjson_get_int(yyjson_val *val) { + return yyjson_is_int(val) ? unsafe_yyjson_get_int(val) : 0; +} + +yyjson_api_inline double yyjson_get_real(yyjson_val *val) { + return yyjson_is_real(val) ? unsafe_yyjson_get_real(val) : 0.0; +} + +yyjson_api_inline double yyjson_get_num(yyjson_val *val) { + return val ? unsafe_yyjson_get_num(val) : 0.0; +} + +yyjson_api_inline const char *yyjson_get_str(yyjson_val *val) { + return yyjson_is_str(val) ? unsafe_yyjson_get_str(val) : NULL; +} + +yyjson_api_inline size_t yyjson_get_len(yyjson_val *val) { + return val ? unsafe_yyjson_get_len(val) : 0; +} + +yyjson_api_inline bool yyjson_equals_str(yyjson_val *val, const char *str) { + if (yyjson_likely(val && str)) { + return unsafe_yyjson_equals_str(val, str); + } + return false; +} + +yyjson_api_inline bool yyjson_equals_strn(yyjson_val *val, const char *str, + size_t len) { + if (yyjson_likely(val && str)) { + return unsafe_yyjson_equals_strn(val, str, len); + } + return false; +} + +yyjson_api bool unsafe_yyjson_equals(yyjson_val *lhs, yyjson_val *rhs); + +yyjson_api_inline bool yyjson_equals(yyjson_val *lhs, yyjson_val *rhs) { + if (yyjson_unlikely(!lhs || !rhs)) return false; + return unsafe_yyjson_equals(lhs, rhs); +} + +yyjson_api_inline bool yyjson_set_raw(yyjson_val *val, + const char *raw, size_t len) { + if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false; + unsafe_yyjson_set_raw(val, raw, len); + return true; +} + +yyjson_api_inline bool yyjson_set_null(yyjson_val *val) { + if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false; + unsafe_yyjson_set_null(val); + return true; +} + +yyjson_api_inline bool yyjson_set_bool(yyjson_val *val, bool num) { + if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false; + unsafe_yyjson_set_bool(val, num); + return true; +} + +yyjson_api_inline bool yyjson_set_uint(yyjson_val *val, uint64_t num) { + if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false; + unsafe_yyjson_set_uint(val, num); + return true; +} + +yyjson_api_inline bool yyjson_set_sint(yyjson_val *val, int64_t num) { + if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false; + unsafe_yyjson_set_sint(val, num); + return true; +} + +yyjson_api_inline bool yyjson_set_int(yyjson_val *val, int num) { + if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false; + unsafe_yyjson_set_sint(val, (int64_t)num); + return true; +} + +yyjson_api_inline bool yyjson_set_real(yyjson_val *val, double num) { + if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false; + unsafe_yyjson_set_real(val, num); + return true; +} + +yyjson_api_inline bool yyjson_set_str(yyjson_val *val, const char *str) { + if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false; + if (yyjson_unlikely(!str)) return false; + unsafe_yyjson_set_str(val, str); + return true; +} + +yyjson_api_inline bool yyjson_set_strn(yyjson_val *val, + const char *str, size_t len) { + if (yyjson_unlikely(!val || unsafe_yyjson_is_ctn(val))) return false; + if (yyjson_unlikely(!str)) return false; + unsafe_yyjson_set_strn(val, str, len); + return true; +} + + + +/*============================================================================== + * JSON Array API (Implementation) + *============================================================================*/ + +yyjson_api_inline size_t yyjson_arr_size(yyjson_val *arr) { + return yyjson_is_arr(arr) ? unsafe_yyjson_get_len(arr) : 0; +} + +yyjson_api_inline yyjson_val *yyjson_arr_get(yyjson_val *arr, size_t idx) { + if (yyjson_likely(yyjson_is_arr(arr))) { + if (yyjson_likely(unsafe_yyjson_get_len(arr) > idx)) { + yyjson_val *val = unsafe_yyjson_get_first(arr); + if (unsafe_yyjson_arr_is_flat(arr)) { + return val + idx; + } else { + while (idx-- > 0) val = unsafe_yyjson_get_next(val); + return val; + } + } + } + return NULL; +} + +yyjson_api_inline yyjson_val *yyjson_arr_get_first(yyjson_val *arr) { + if (yyjson_likely(yyjson_is_arr(arr))) { + if (yyjson_likely(unsafe_yyjson_get_len(arr) > 0)) { + return unsafe_yyjson_get_first(arr); + } + } + return NULL; +} + +yyjson_api_inline yyjson_val *yyjson_arr_get_last(yyjson_val *arr) { + if (yyjson_likely(yyjson_is_arr(arr))) { + size_t len = unsafe_yyjson_get_len(arr); + if (yyjson_likely(len > 0)) { + yyjson_val *val = unsafe_yyjson_get_first(arr); + if (unsafe_yyjson_arr_is_flat(arr)) { + return val + (len - 1); + } else { + while (len-- > 1) val = unsafe_yyjson_get_next(val); + return val; + } + } + } + return NULL; +} + + + +/*============================================================================== + * JSON Array Iterator API (Implementation) + *============================================================================*/ + +yyjson_api_inline bool yyjson_arr_iter_init(yyjson_val *arr, + yyjson_arr_iter *iter) { + if (yyjson_likely(yyjson_is_arr(arr) && iter)) { + iter->idx = 0; + iter->max = unsafe_yyjson_get_len(arr); + iter->cur = unsafe_yyjson_get_first(arr); + return true; + } + if (iter) memset(iter, 0, sizeof(yyjson_arr_iter)); + return false; +} + +yyjson_api_inline yyjson_arr_iter yyjson_arr_iter_with(yyjson_val *arr) { + yyjson_arr_iter iter; + yyjson_arr_iter_init(arr, &iter); + return iter; +} + +yyjson_api_inline bool yyjson_arr_iter_has_next(yyjson_arr_iter *iter) { + return iter ? iter->idx < iter->max : false; +} + +yyjson_api_inline yyjson_val *yyjson_arr_iter_next(yyjson_arr_iter *iter) { + yyjson_val *val; + if (iter && iter->idx < iter->max) { + val = iter->cur; + iter->cur = unsafe_yyjson_get_next(val); + iter->idx++; + return val; + } + return NULL; +} + + + +/*============================================================================== + * JSON Object API (Implementation) + *============================================================================*/ + +yyjson_api_inline size_t yyjson_obj_size(yyjson_val *obj) { + return yyjson_is_obj(obj) ? unsafe_yyjson_get_len(obj) : 0; +} + +yyjson_api_inline yyjson_val *yyjson_obj_get(yyjson_val *obj, + const char *key) { + return yyjson_obj_getn(obj, key, key ? strlen(key) : 0); +} + +yyjson_api_inline yyjson_val *yyjson_obj_getn(yyjson_val *obj, + const char *_key, + size_t key_len) { + uint64_t tag = (((uint64_t)key_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + if (yyjson_likely(yyjson_is_obj(obj) && _key)) { + size_t len = unsafe_yyjson_get_len(obj); + yyjson_val *key = unsafe_yyjson_get_first(obj); + while (len-- > 0) { + if (key->tag == tag && + memcmp(key->uni.ptr, _key, key_len) == 0) { + return key + 1; + } + key = unsafe_yyjson_get_next(key + 1); + } + } + return NULL; +} + + + +/*============================================================================== + * JSON Object Iterator API (Implementation) + *============================================================================*/ + +yyjson_api_inline bool yyjson_obj_iter_init(yyjson_val *obj, + yyjson_obj_iter *iter) { + if (yyjson_likely(yyjson_is_obj(obj) && iter)) { + iter->idx = 0; + iter->max = unsafe_yyjson_get_len(obj); + iter->cur = unsafe_yyjson_get_first(obj); + iter->obj = obj; + return true; + } + if (iter) memset(iter, 0, sizeof(yyjson_obj_iter)); + return false; +} + +yyjson_api_inline yyjson_obj_iter yyjson_obj_iter_with(yyjson_val *obj) { + yyjson_obj_iter iter; + yyjson_obj_iter_init(obj, &iter); + return iter; +} + +yyjson_api_inline bool yyjson_obj_iter_has_next(yyjson_obj_iter *iter) { + return iter ? iter->idx < iter->max : false; +} + +yyjson_api_inline yyjson_val *yyjson_obj_iter_next(yyjson_obj_iter *iter) { + if (iter && iter->idx < iter->max) { + yyjson_val *key = iter->cur; + iter->idx++; + iter->cur = unsafe_yyjson_get_next(key + 1); + return key; + } + return NULL; +} + +yyjson_api_inline yyjson_val *yyjson_obj_iter_get_val(yyjson_val *key) { + return key ? key + 1 : NULL; +} + +yyjson_api_inline yyjson_val *yyjson_obj_iter_get(yyjson_obj_iter *iter, + const char *key) { + return yyjson_obj_iter_getn(iter, key, key ? strlen(key) : 0); +} + +yyjson_api_inline yyjson_val *yyjson_obj_iter_getn(yyjson_obj_iter *iter, + const char *key, + size_t key_len) { + if (iter && key) { + size_t idx = iter->idx; + size_t max = iter->max; + yyjson_val *cur = iter->cur; + if (yyjson_unlikely(idx == max)) { + idx = 0; + cur = unsafe_yyjson_get_first(iter->obj); + } + while (idx++ < max) { + yyjson_val *next = unsafe_yyjson_get_next(cur + 1); + if (unsafe_yyjson_get_len(cur) == key_len && + memcmp(cur->uni.str, key, key_len) == 0) { + iter->idx = idx; + iter->cur = next; + return cur + 1; + } + cur = next; + if (idx == iter->max && iter->idx < iter->max) { + idx = 0; + max = iter->idx; + cur = unsafe_yyjson_get_first(iter->obj); + } + } + } + return NULL; +} + + + +/*============================================================================== + * Mutable JSON Structure (Implementation) + *============================================================================*/ + +/** + Mutable JSON value, 24 bytes. + The 'tag' and 'uni' field is same as immutable value. + The 'next' field links all elements inside the container to be a cycle. + */ +struct yyjson_mut_val { + uint64_t tag; /**< type, subtype and length */ + yyjson_val_uni uni; /**< payload */ + yyjson_mut_val *next; /**< the next value in circular linked list */ +}; + +/** + A memory chunk in string memory pool. + */ +typedef struct yyjson_str_chunk { + struct yyjson_str_chunk *next; /* next chunk linked list */ + size_t chunk_size; /* chunk size in bytes */ + /* char str[]; flexible array member */ +} yyjson_str_chunk; + +/** + A memory pool to hold all strings in a mutable document. + */ +typedef struct yyjson_str_pool { + char *cur; /* cursor inside current chunk */ + char *end; /* the end of current chunk */ + size_t chunk_size; /* chunk size in bytes while creating new chunk */ + size_t chunk_size_max; /* maximum chunk size in bytes */ + yyjson_str_chunk *chunks; /* a linked list of chunks, nullable */ +} yyjson_str_pool; + +/** + A memory chunk in value memory pool. + `sizeof(yyjson_val_chunk)` should not larger than `sizeof(yyjson_mut_val)`. + */ +typedef struct yyjson_val_chunk { + struct yyjson_val_chunk *next; /* next chunk linked list */ + size_t chunk_size; /* chunk size in bytes */ + /* char pad[sizeof(yyjson_mut_val) - sizeof(yyjson_val_chunk)]; padding */ + /* yyjson_mut_val vals[]; flexible array member */ +} yyjson_val_chunk; + +/** + A memory pool to hold all values in a mutable document. + */ +typedef struct yyjson_val_pool { + yyjson_mut_val *cur; /* cursor inside current chunk */ + yyjson_mut_val *end; /* the end of current chunk */ + size_t chunk_size; /* chunk size in bytes while creating new chunk */ + size_t chunk_size_max; /* maximum chunk size in bytes */ + yyjson_val_chunk *chunks; /* a linked list of chunks, nullable */ +} yyjson_val_pool; + +struct yyjson_mut_doc { + yyjson_mut_val *root; /**< root value of the JSON document, nullable */ + yyjson_alc alc; /**< a valid allocator, nonnull */ + yyjson_str_pool str_pool; /**< string memory pool */ + yyjson_val_pool val_pool; /**< value memory pool */ +}; + +/* Ensures the capacity to at least equal to the specified byte length. */ +yyjson_api bool unsafe_yyjson_str_pool_grow(yyjson_str_pool *pool, + const yyjson_alc *alc, + size_t len); + +/* Ensures the capacity to at least equal to the specified value count. */ +yyjson_api bool unsafe_yyjson_val_pool_grow(yyjson_val_pool *pool, + const yyjson_alc *alc, + size_t count); + +/* Allocate memory for string. */ +yyjson_api_inline char *unsafe_yyjson_mut_str_alc(yyjson_mut_doc *doc, + size_t len) { + char *mem; + const yyjson_alc *alc = &doc->alc; + yyjson_str_pool *pool = &doc->str_pool; + if (yyjson_unlikely((size_t)(pool->end - pool->cur) <= len)) { + if (yyjson_unlikely(!unsafe_yyjson_str_pool_grow(pool, alc, len + 1))) { + return NULL; + } + } + mem = pool->cur; + pool->cur = mem + len + 1; + return mem; +} + +yyjson_api_inline char *unsafe_yyjson_mut_strncpy(yyjson_mut_doc *doc, + const char *str, size_t len) { + char *mem = unsafe_yyjson_mut_str_alc(doc, len); + if (yyjson_unlikely(!mem)) return NULL; + memcpy((void *)mem, (const void *)str, len); + mem[len] = '\0'; + return mem; +} + +yyjson_api_inline yyjson_mut_val *unsafe_yyjson_mut_val(yyjson_mut_doc *doc, + size_t count) { + yyjson_mut_val *val; + yyjson_alc *alc = &doc->alc; + yyjson_val_pool *pool = &doc->val_pool; + if (yyjson_unlikely((size_t)(pool->end - pool->cur) < count)) { + if (yyjson_unlikely(!unsafe_yyjson_val_pool_grow(pool, alc, count))) { + return NULL; + } + } + val = pool->cur; + pool->cur += count; + return val; +} + + + +/*============================================================================== + * Mutable JSON Document API (Implementation) + *============================================================================*/ + +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_get_root(yyjson_mut_doc *doc) { + return doc ? doc->root : NULL; +} + +yyjson_api_inline void yyjson_mut_doc_set_root(yyjson_mut_doc *doc, + yyjson_mut_val *root) { + if (doc) doc->root = root; +} + + + +/*============================================================================== + * Mutable JSON Value Type API (Implementation) + *============================================================================*/ + +yyjson_api_inline bool yyjson_mut_is_raw(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_raw(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_null(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_null(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_true(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_true(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_false(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_false(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_bool(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_bool(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_uint(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_uint(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_sint(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_sint(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_int(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_int(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_real(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_real(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_num(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_num(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_str(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_str(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_arr(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_arr(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_obj(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_obj(val) : false; +} + +yyjson_api_inline bool yyjson_mut_is_ctn(yyjson_mut_val *val) { + return val ? unsafe_yyjson_is_ctn(val) : false; +} + + + +/*============================================================================== + * Mutable JSON Value Content API (Implementation) + *============================================================================*/ + +yyjson_api_inline yyjson_type yyjson_mut_get_type(yyjson_mut_val *val) { + return yyjson_get_type((yyjson_val *)val); +} + +yyjson_api_inline yyjson_subtype yyjson_mut_get_subtype(yyjson_mut_val *val) { + return yyjson_get_subtype((yyjson_val *)val); +} + +yyjson_api_inline uint8_t yyjson_mut_get_tag(yyjson_mut_val *val) { + return yyjson_get_tag((yyjson_val *)val); +} + +yyjson_api_inline const char *yyjson_mut_get_type_desc(yyjson_mut_val *val) { + return yyjson_get_type_desc((yyjson_val *)val); +} + +yyjson_api_inline const char *yyjson_mut_get_raw(yyjson_mut_val *val) { + return yyjson_get_raw((yyjson_val *)val); +} + +yyjson_api_inline bool yyjson_mut_get_bool(yyjson_mut_val *val) { + return yyjson_get_bool((yyjson_val *)val); +} + +yyjson_api_inline uint64_t yyjson_mut_get_uint(yyjson_mut_val *val) { + return yyjson_get_uint((yyjson_val *)val); +} + +yyjson_api_inline int64_t yyjson_mut_get_sint(yyjson_mut_val *val) { + return yyjson_get_sint((yyjson_val *)val); +} + +yyjson_api_inline int yyjson_mut_get_int(yyjson_mut_val *val) { + return yyjson_get_int((yyjson_val *)val); +} + +yyjson_api_inline double yyjson_mut_get_real(yyjson_mut_val *val) { + return yyjson_get_real((yyjson_val *)val); +} + +yyjson_api_inline double yyjson_mut_get_num(yyjson_mut_val *val) { + return yyjson_get_num((yyjson_val *)val); +} + +yyjson_api_inline const char *yyjson_mut_get_str(yyjson_mut_val *val) { + return yyjson_get_str((yyjson_val *)val); +} + +yyjson_api_inline size_t yyjson_mut_get_len(yyjson_mut_val *val) { + return yyjson_get_len((yyjson_val *)val); +} + +yyjson_api_inline bool yyjson_mut_equals_str(yyjson_mut_val *val, + const char *str) { + return yyjson_equals_str((yyjson_val *)val, str); +} + +yyjson_api_inline bool yyjson_mut_equals_strn(yyjson_mut_val *val, + const char *str, size_t len) { + return yyjson_equals_strn((yyjson_val *)val, str, len); +} + +yyjson_api bool unsafe_yyjson_mut_equals(yyjson_mut_val *lhs, + yyjson_mut_val *rhs); + +yyjson_api_inline bool yyjson_mut_equals(yyjson_mut_val *lhs, + yyjson_mut_val *rhs) { + if (yyjson_unlikely(!lhs || !rhs)) return false; + return unsafe_yyjson_mut_equals(lhs, rhs); +} + +yyjson_api_inline bool yyjson_mut_set_raw(yyjson_mut_val *val, + const char *raw, size_t len) { + if (yyjson_unlikely(!val || !raw)) return false; + unsafe_yyjson_set_raw(val, raw, len); + return true; +} + +yyjson_api_inline bool yyjson_mut_set_null(yyjson_mut_val *val) { + if (yyjson_unlikely(!val)) return false; + unsafe_yyjson_set_null(val); + return true; +} + +yyjson_api_inline bool yyjson_mut_set_bool(yyjson_mut_val *val, bool num) { + if (yyjson_unlikely(!val)) return false; + unsafe_yyjson_set_bool(val, num); + return true; +} + +yyjson_api_inline bool yyjson_mut_set_uint(yyjson_mut_val *val, uint64_t num) { + if (yyjson_unlikely(!val)) return false; + unsafe_yyjson_set_uint(val, num); + return true; +} + +yyjson_api_inline bool yyjson_mut_set_sint(yyjson_mut_val *val, int64_t num) { + if (yyjson_unlikely(!val)) return false; + unsafe_yyjson_set_sint(val, num); + return true; +} + +yyjson_api_inline bool yyjson_mut_set_int(yyjson_mut_val *val, int num) { + if (yyjson_unlikely(!val)) return false; + unsafe_yyjson_set_sint(val, (int64_t)num); + return true; +} + +yyjson_api_inline bool yyjson_mut_set_real(yyjson_mut_val *val, double num) { + if (yyjson_unlikely(!val)) return false; + unsafe_yyjson_set_real(val, num); + return true; +} + +yyjson_api_inline bool yyjson_mut_set_str(yyjson_mut_val *val, + const char *str) { + if (yyjson_unlikely(!val || !str)) return false; + unsafe_yyjson_set_str(val, str); + return true; +} + +yyjson_api_inline bool yyjson_mut_set_strn(yyjson_mut_val *val, + const char *str, size_t len) { + if (yyjson_unlikely(!val || !str)) return false; + unsafe_yyjson_set_strn(val, str, len); + return true; +} + +yyjson_api_inline bool yyjson_mut_set_arr(yyjson_mut_val *val) { + if (yyjson_unlikely(!val)) return false; + unsafe_yyjson_set_arr(val, 0); + return true; +} + +yyjson_api_inline bool yyjson_mut_set_obj(yyjson_mut_val *val) { + if (yyjson_unlikely(!val)) return false; + unsafe_yyjson_set_obj(val, 0); + return true; +} + + + +/*============================================================================== + * Mutable JSON Value Creation API (Implementation) + *============================================================================*/ + +yyjson_api_inline yyjson_mut_val *yyjson_mut_raw(yyjson_mut_doc *doc, + const char *str) { + if (yyjson_likely(str)) return yyjson_mut_rawn(doc, str, strlen(str)); + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_rawn(yyjson_mut_doc *doc, + const char *str, + size_t len) { + if (yyjson_likely(doc && str)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + if (yyjson_likely(val)) { + val->tag = ((uint64_t)len << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; + val->uni.str = str; + return val; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_rawcpy(yyjson_mut_doc *doc, + const char *str) { + if (yyjson_likely(str)) return yyjson_mut_rawncpy(doc, str, strlen(str)); + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_rawncpy(yyjson_mut_doc *doc, + const char *str, + size_t len) { + if (yyjson_likely(doc && str)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + char *new_str = unsafe_yyjson_mut_strncpy(doc, str, len); + if (yyjson_likely(val && new_str)) { + val->tag = ((uint64_t)len << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; + val->uni.str = new_str; + return val; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_null(yyjson_mut_doc *doc) { + if (yyjson_likely(doc)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + if (yyjson_likely(val)) { + val->tag = YYJSON_TYPE_NULL | YYJSON_SUBTYPE_NONE; + return val; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_true(yyjson_mut_doc *doc) { + if (yyjson_likely(doc)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + if (yyjson_likely(val)) { + val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE; + return val; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_false(yyjson_mut_doc *doc) { + if (yyjson_likely(doc)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + if (yyjson_likely(val)) { + val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE; + return val; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_bool(yyjson_mut_doc *doc, + bool _val) { + if (yyjson_likely(doc)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + if (yyjson_likely(val)) { + val->tag = YYJSON_TYPE_BOOL | (uint8_t)((uint8_t)_val << 3); + return val; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_uint(yyjson_mut_doc *doc, + uint64_t num) { + if (yyjson_likely(doc)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + if (yyjson_likely(val)) { + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT; + val->uni.u64 = num; + return val; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_sint(yyjson_mut_doc *doc, + int64_t num) { + if (yyjson_likely(doc)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + if (yyjson_likely(val)) { + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT; + val->uni.i64 = num; + return val; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_int(yyjson_mut_doc *doc, + int64_t num) { + return yyjson_mut_sint(doc, num); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_real(yyjson_mut_doc *doc, + double num) { + if (yyjson_likely(doc)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + if (yyjson_likely(val)) { + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; + val->uni.f64 = num; + return val; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_str(yyjson_mut_doc *doc, + const char *str) { + if (yyjson_likely(str)) return yyjson_mut_strn(doc, str, strlen(str)); + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_strn(yyjson_mut_doc *doc, + const char *str, + size_t len) { + if (yyjson_likely(doc && str)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + if (yyjson_likely(val)) { + val->tag = ((uint64_t)len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + val->uni.str = str; + return val; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_strcpy(yyjson_mut_doc *doc, + const char *str) { + if (yyjson_likely(str)) return yyjson_mut_strncpy(doc, str, strlen(str)); + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_strncpy(yyjson_mut_doc *doc, + const char *str, + size_t len) { + if (yyjson_likely(doc && str)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + char *new_str = unsafe_yyjson_mut_strncpy(doc, str, len); + if (yyjson_likely(val && new_str)) { + val->tag = ((uint64_t)len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + val->uni.str = new_str; + return val; + } + } + return NULL; +} + + + +/*============================================================================== + * Mutable JSON Array API (Implementation) + *============================================================================*/ + +yyjson_api_inline size_t yyjson_mut_arr_size(yyjson_mut_val *arr) { + return yyjson_mut_is_arr(arr) ? unsafe_yyjson_get_len(arr) : 0; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get(yyjson_mut_val *arr, + size_t idx) { + if (yyjson_likely(idx < yyjson_mut_arr_size(arr))) { + yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; + while (idx-- > 0) val = val->next; + return val->next; + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_first( + yyjson_mut_val *arr) { + if (yyjson_likely(yyjson_mut_arr_size(arr) > 0)) { + return ((yyjson_mut_val *)arr->uni.ptr)->next; + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_last( + yyjson_mut_val *arr) { + if (yyjson_likely(yyjson_mut_arr_size(arr) > 0)) { + return ((yyjson_mut_val *)arr->uni.ptr); + } + return NULL; +} + + + +/*============================================================================== + * Mutable JSON Array Iterator API (Implementation) + *============================================================================*/ + +yyjson_api_inline bool yyjson_mut_arr_iter_init(yyjson_mut_val *arr, + yyjson_mut_arr_iter *iter) { + if (yyjson_likely(yyjson_mut_is_arr(arr) && iter)) { + iter->idx = 0; + iter->max = unsafe_yyjson_get_len(arr); + iter->cur = iter->max ? (yyjson_mut_val *)arr->uni.ptr : NULL; + iter->pre = NULL; + iter->arr = arr; + return true; + } + if (iter) memset(iter, 0, sizeof(yyjson_mut_arr_iter)); + return false; +} + +yyjson_api_inline yyjson_mut_arr_iter yyjson_mut_arr_iter_with( + yyjson_mut_val *arr) { + yyjson_mut_arr_iter iter; + yyjson_mut_arr_iter_init(arr, &iter); + return iter; +} + +yyjson_api_inline bool yyjson_mut_arr_iter_has_next(yyjson_mut_arr_iter *iter) { + return iter ? iter->idx < iter->max : false; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_next( + yyjson_mut_arr_iter *iter) { + if (iter && iter->idx < iter->max) { + yyjson_mut_val *val = iter->cur; + iter->pre = val; + iter->cur = val->next; + iter->idx++; + return iter->cur; + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_remove( + yyjson_mut_arr_iter *iter) { + if (yyjson_likely(iter && 0 < iter->idx && iter->idx <= iter->max)) { + yyjson_mut_val *prev = iter->pre; + yyjson_mut_val *cur = iter->cur; + yyjson_mut_val *next = cur->next; + if (yyjson_unlikely(iter->idx == iter->max)) iter->arr->uni.ptr = prev; + iter->idx--; + iter->max--; + unsafe_yyjson_set_len(iter->arr, iter->max); + prev->next = next; + iter->cur = next; + return cur; + } + return NULL; +} + + + +/*============================================================================== + * Mutable JSON Array Creation API (Implementation) + *============================================================================*/ + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr(yyjson_mut_doc *doc) { + if (yyjson_likely(doc)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + if (yyjson_likely(val)) { + val->tag = YYJSON_TYPE_ARR | YYJSON_SUBTYPE_NONE; + return val; + } + } + return NULL; +} + +#define yyjson_mut_arr_with_func(func) \ + if (yyjson_likely(doc && ((0 < count && count < \ + (~(size_t)0) / sizeof(yyjson_mut_val) && vals) || count == 0))) { \ + yyjson_mut_val *arr = unsafe_yyjson_mut_val(doc, 1 + count); \ + if (yyjson_likely(arr)) { \ + arr->tag = ((uint64_t)count << YYJSON_TAG_BIT) | YYJSON_TYPE_ARR; \ + if (count > 0) { \ + size_t i; \ + for (i = 0; i < count; i++) { \ + yyjson_mut_val *val = arr + i + 1; \ + func \ + val->next = val + 1; \ + } \ + arr[count].next = arr + 1; \ + arr->uni.ptr = arr + count; \ + } \ + return arr; \ + } \ + } \ + return NULL + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_bool( + yyjson_mut_doc *doc, const bool *vals, size_t count) { + yyjson_mut_arr_with_func({ + val->tag = YYJSON_TYPE_BOOL | (uint8_t)((uint8_t)vals[i] << 3); + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint( + yyjson_mut_doc *doc, const int64_t *vals, size_t count) { + return yyjson_mut_arr_with_sint64(doc, vals, count); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint( + yyjson_mut_doc *doc, const uint64_t *vals, size_t count) { + return yyjson_mut_arr_with_uint64(doc, vals, count); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_real( + yyjson_mut_doc *doc, const double *vals, size_t count) { + return yyjson_mut_arr_with_double(doc, vals, count); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint8( + yyjson_mut_doc *doc, const int8_t *vals, size_t count) { + yyjson_mut_arr_with_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT; + val->uni.i64 = (int64_t)vals[i]; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint16( + yyjson_mut_doc *doc, const int16_t *vals, size_t count) { + yyjson_mut_arr_with_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT; + val->uni.i64 = vals[i]; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint32( + yyjson_mut_doc *doc, const int32_t *vals, size_t count) { + yyjson_mut_arr_with_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT; + val->uni.i64 = vals[i]; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_sint64( + yyjson_mut_doc *doc, const int64_t *vals, size_t count) { + yyjson_mut_arr_with_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT; + val->uni.i64 = vals[i]; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint8( + yyjson_mut_doc *doc, const uint8_t *vals, size_t count) { + yyjson_mut_arr_with_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT; + val->uni.u64 = vals[i]; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint16( + yyjson_mut_doc *doc, const uint16_t *vals, size_t count) { + yyjson_mut_arr_with_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT; + val->uni.u64 = vals[i]; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint32( + yyjson_mut_doc *doc, const uint32_t *vals, size_t count) { + yyjson_mut_arr_with_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT; + val->uni.u64 = vals[i]; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_uint64( + yyjson_mut_doc *doc, const uint64_t *vals, size_t count) { + yyjson_mut_arr_with_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT; + val->uni.u64 = vals[i]; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_float( + yyjson_mut_doc *doc, const float *vals, size_t count) { + yyjson_mut_arr_with_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; + val->uni.f64 = (double)vals[i]; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_double( + yyjson_mut_doc *doc, const double *vals, size_t count) { + yyjson_mut_arr_with_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; + val->uni.f64 = vals[i]; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_str( + yyjson_mut_doc *doc, const char **vals, size_t count) { + yyjson_mut_arr_with_func({ + uint64_t len = (uint64_t)strlen(vals[i]); + val->tag = (len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + val->uni.str = vals[i]; + if (yyjson_unlikely(!val->uni.str)) return NULL; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strn( + yyjson_mut_doc *doc, const char **vals, const size_t *lens, size_t count) { + if (yyjson_unlikely(count > 0 && !lens)) return NULL; + yyjson_mut_arr_with_func({ + val->tag = ((uint64_t)lens[i] << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + val->uni.str = vals[i]; + if (yyjson_unlikely(!val->uni.str)) return NULL; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strcpy( + yyjson_mut_doc *doc, const char **vals, size_t count) { + size_t len; + const char *str; + yyjson_mut_arr_with_func({ + str = vals[i]; + if (!str) return NULL; + len = strlen(str); + val->tag = ((uint64_t)len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + val->uni.str = unsafe_yyjson_mut_strncpy(doc, str, len); + if (yyjson_unlikely(!val->uni.str)) return NULL; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strncpy( + yyjson_mut_doc *doc, const char **vals, const size_t *lens, size_t count) { + size_t len; + const char *str; + if (yyjson_unlikely(count > 0 && !lens)) return NULL; + yyjson_mut_arr_with_func({ + str = vals[i]; + len = lens[i]; + val->tag = ((uint64_t)len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + val->uni.str = unsafe_yyjson_mut_strncpy(doc, str, len); + if (yyjson_unlikely(!val->uni.str)) return NULL; + }); +} + +#undef yyjson_mut_arr_with_func + + + +/*============================================================================== + * Mutable JSON Array Modification API (Implementation) + *============================================================================*/ + +yyjson_api_inline bool yyjson_mut_arr_insert(yyjson_mut_val *arr, + yyjson_mut_val *val, size_t idx) { + if (yyjson_likely(yyjson_mut_is_arr(arr) && val)) { + size_t len = unsafe_yyjson_get_len(arr); + if (yyjson_likely(idx <= len)) { + unsafe_yyjson_set_len(arr, len + 1); + if (len == 0) { + val->next = val; + arr->uni.ptr = val; + } else { + yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr); + yyjson_mut_val *next = prev->next; + if (idx == len) { + prev->next = val; + val->next = next; + arr->uni.ptr = val; + } else { + while (idx-- > 0) { + prev = next; + next = next->next; + } + prev->next = val; + val->next = next; + } + } + return true; + } + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_append(yyjson_mut_val *arr, + yyjson_mut_val *val) { + if (yyjson_likely(yyjson_mut_is_arr(arr) && val)) { + size_t len = unsafe_yyjson_get_len(arr); + unsafe_yyjson_set_len(arr, len + 1); + if (len == 0) { + val->next = val; + } else { + yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr); + yyjson_mut_val *next = prev->next; + prev->next = val; + val->next = next; + } + arr->uni.ptr = val; + return true; + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_prepend(yyjson_mut_val *arr, + yyjson_mut_val *val) { + if (yyjson_likely(yyjson_mut_is_arr(arr) && val)) { + size_t len = unsafe_yyjson_get_len(arr); + unsafe_yyjson_set_len(arr, len + 1); + if (len == 0) { + val->next = val; + arr->uni.ptr = val; + } else { + yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr); + yyjson_mut_val *next = prev->next; + prev->next = val; + val->next = next; + } + return true; + } + return false; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_replace(yyjson_mut_val *arr, + size_t idx, + yyjson_mut_val *val) { + if (yyjson_likely(yyjson_mut_is_arr(arr) && val)) { + size_t len = unsafe_yyjson_get_len(arr); + if (yyjson_likely(idx < len)) { + if (yyjson_likely(len > 1)) { + yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr); + yyjson_mut_val *next = prev->next; + while (idx-- > 0) { + prev = next; + next = next->next; + } + prev->next = val; + val->next = next->next; + if ((void *)next == arr->uni.ptr) arr->uni.ptr = val; + return next; + } else { + yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr); + val->next = val; + arr->uni.ptr = val; + return prev; + } + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove(yyjson_mut_val *arr, + size_t idx) { + if (yyjson_likely(yyjson_mut_is_arr(arr))) { + size_t len = unsafe_yyjson_get_len(arr); + if (yyjson_likely(idx < len)) { + unsafe_yyjson_set_len(arr, len - 1); + if (yyjson_likely(len > 1)) { + yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr); + yyjson_mut_val *next = prev->next; + while (idx-- > 0) { + prev = next; + next = next->next; + } + prev->next = next->next; + if ((void *)next == arr->uni.ptr) arr->uni.ptr = prev; + return next; + } else { + return ((yyjson_mut_val *)arr->uni.ptr); + } + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove_first( + yyjson_mut_val *arr) { + if (yyjson_likely(yyjson_mut_is_arr(arr))) { + size_t len = unsafe_yyjson_get_len(arr); + if (len > 1) { + yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr); + yyjson_mut_val *next = prev->next; + prev->next = next->next; + unsafe_yyjson_set_len(arr, len - 1); + return next; + } else if (len == 1) { + yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr); + unsafe_yyjson_set_len(arr, 0); + return prev; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_remove_last( + yyjson_mut_val *arr) { + if (yyjson_likely(yyjson_mut_is_arr(arr))) { + size_t len = unsafe_yyjson_get_len(arr); + if (yyjson_likely(len > 1)) { + yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr); + yyjson_mut_val *next = prev->next; + unsafe_yyjson_set_len(arr, len - 1); + while (--len > 0) prev = prev->next; + prev->next = next; + next = (yyjson_mut_val *)arr->uni.ptr; + arr->uni.ptr = prev; + return next; + } else if (len == 1) { + yyjson_mut_val *prev = ((yyjson_mut_val *)arr->uni.ptr); + unsafe_yyjson_set_len(arr, 0); + return prev; + } + } + return NULL; +} + +yyjson_api_inline bool yyjson_mut_arr_remove_range(yyjson_mut_val *arr, + size_t _idx, size_t _len) { + if (yyjson_likely(yyjson_mut_is_arr(arr))) { + yyjson_mut_val *prev, *next; + bool tail_removed; + size_t len = unsafe_yyjson_get_len(arr); + if (yyjson_unlikely(_idx + _len > len)) return false; + if (yyjson_unlikely(_len == 0)) return true; + unsafe_yyjson_set_len(arr, len - _len); + if (yyjson_unlikely(len == _len)) return true; + tail_removed = (_idx + _len == len); + prev = ((yyjson_mut_val *)arr->uni.ptr); + while (_idx-- > 0) prev = prev->next; + next = prev->next; + while (_len-- > 0) next = next->next; + prev->next = next; + if (yyjson_unlikely(tail_removed)) arr->uni.ptr = prev; + return true; + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_clear(yyjson_mut_val *arr) { + if (yyjson_likely(yyjson_mut_is_arr(arr))) { + unsafe_yyjson_set_len(arr, 0); + return true; + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_rotate(yyjson_mut_val *arr, + size_t idx) { + if (yyjson_likely(yyjson_mut_is_arr(arr) && + unsafe_yyjson_get_len(arr) > idx)) { + yyjson_mut_val *val = (yyjson_mut_val *)arr->uni.ptr; + while (idx-- > 0) val = val->next; + arr->uni.ptr = (void *)val; + return true; + } + return false; +} + + + +/*============================================================================== + * Mutable JSON Array Modification Convenience API (Implementation) + *============================================================================*/ + +yyjson_api_inline bool yyjson_mut_arr_add_val(yyjson_mut_val *arr, + yyjson_mut_val *val) { + return yyjson_mut_arr_append(arr, val); +} + +yyjson_api_inline bool yyjson_mut_arr_add_null(yyjson_mut_doc *doc, + yyjson_mut_val *arr) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_null(doc); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_add_true(yyjson_mut_doc *doc, + yyjson_mut_val *arr) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_true(doc); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_add_false(yyjson_mut_doc *doc, + yyjson_mut_val *arr) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_false(doc); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_add_bool(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + bool _val) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_bool(doc, _val); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_add_uint(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + uint64_t num) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_uint(doc, num); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_add_sint(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + int64_t num) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_sint(doc, num); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_add_int(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + int64_t num) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_sint(doc, num); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_add_real(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + double num) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_real(doc, num); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_add_str(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + const char *str) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_str(doc, str); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_add_strn(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + const char *str, size_t len) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_strn(doc, str, len); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_add_strcpy(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + const char *str) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_strcpy(doc, str); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_arr_add_strncpy(yyjson_mut_doc *doc, + yyjson_mut_val *arr, + const char *str, size_t len) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_strncpy(doc, str, len); + return yyjson_mut_arr_append(arr, val); + } + return false; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_arr(yyjson_mut_doc *doc, + yyjson_mut_val *arr) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_arr(doc); + return yyjson_mut_arr_append(arr, val) ? val : NULL; + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_obj(yyjson_mut_doc *doc, + yyjson_mut_val *arr) { + if (yyjson_likely(doc && yyjson_mut_is_arr(arr))) { + yyjson_mut_val *val = yyjson_mut_obj(doc); + return yyjson_mut_arr_append(arr, val) ? val : NULL; + } + return NULL; +} + + + +/*============================================================================== + * Mutable JSON Object API (Implementation) + *============================================================================*/ + +yyjson_api_inline size_t yyjson_mut_obj_size(yyjson_mut_val *obj) { + return yyjson_mut_is_obj(obj) ? unsafe_yyjson_get_len(obj) : 0; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_get(yyjson_mut_val *obj, + const char *key) { + return yyjson_mut_obj_getn(obj, key, key ? strlen(key) : 0); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_getn(yyjson_mut_val *obj, + const char *_key, + size_t key_len) { + uint64_t tag = (((uint64_t)key_len) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + size_t len = yyjson_mut_obj_size(obj); + if (yyjson_likely(len && _key)) { + yyjson_mut_val *key = ((yyjson_mut_val *)obj->uni.ptr)->next->next; + while (len-- > 0) { + if (key->tag == tag && + memcmp(key->uni.ptr, _key, key_len) == 0) { + return key->next; + } + key = key->next->next; + } + } + return NULL; +} + + + +/*============================================================================== + * Mutable JSON Object Iterator API (Implementation) + *============================================================================*/ + +yyjson_api_inline bool yyjson_mut_obj_iter_init(yyjson_mut_val *obj, + yyjson_mut_obj_iter *iter) { + if (yyjson_likely(yyjson_mut_is_obj(obj) && iter)) { + iter->idx = 0; + iter->max = unsafe_yyjson_get_len(obj); + iter->cur = iter->max ? (yyjson_mut_val *)obj->uni.ptr : NULL; + iter->pre = NULL; + iter->obj = obj; + return true; + } + if (iter) memset(iter, 0, sizeof(yyjson_mut_obj_iter)); + return false; +} + +yyjson_api_inline yyjson_mut_obj_iter yyjson_mut_obj_iter_with( + yyjson_mut_val *obj) { + yyjson_mut_obj_iter iter; + yyjson_mut_obj_iter_init(obj, &iter); + return iter; +} + +yyjson_api_inline bool yyjson_mut_obj_iter_has_next(yyjson_mut_obj_iter *iter) { + return iter ? iter->idx < iter->max : false; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_next( + yyjson_mut_obj_iter *iter) { + if (iter && iter->idx < iter->max) { + yyjson_mut_val *key = iter->cur; + iter->pre = key; + iter->cur = key->next->next; + iter->idx++; + return iter->cur; + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_get_val( + yyjson_mut_val *key) { + return key ? key->next : NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_remove( + yyjson_mut_obj_iter *iter) { + if (yyjson_likely(iter && 0 < iter->idx && iter->idx <= iter->max)) { + yyjson_mut_val *prev = iter->pre; + yyjson_mut_val *cur = iter->cur; + yyjson_mut_val *next = cur->next->next; + if (yyjson_unlikely(iter->idx == iter->max)) iter->obj->uni.ptr = prev; + iter->idx--; + iter->max--; + unsafe_yyjson_set_len(iter->obj, iter->max); + prev->next->next = next; + iter->cur = prev; + return cur->next; + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_get( + yyjson_mut_obj_iter *iter, const char *key) { + return yyjson_mut_obj_iter_getn(iter, key, key ? strlen(key) : 0); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_getn( + yyjson_mut_obj_iter *iter, const char *key, size_t key_len) { + if (iter && key) { + size_t idx = 0; + size_t max = iter->max; + yyjson_mut_val *pre, *cur = iter->cur; + while (idx++ < max) { + pre = cur; + cur = cur->next->next; + if (unsafe_yyjson_get_len(cur) == key_len && + memcmp(cur->uni.str, key, key_len) == 0) { + iter->idx += idx; + if (iter->idx > max) iter->idx -= max + 1; + iter->pre = pre; + iter->cur = cur; + return cur->next; + } + } + } + return NULL; +} + + + +/*============================================================================== + * Mutable JSON Object Creation API (Implementation) + *============================================================================*/ + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj(yyjson_mut_doc *doc) { + if (yyjson_likely(doc)) { + yyjson_mut_val *val = unsafe_yyjson_mut_val(doc, 1); + if (yyjson_likely(val)) { + val->tag = YYJSON_TYPE_OBJ | YYJSON_SUBTYPE_NONE; + return val; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_str(yyjson_mut_doc *doc, + const char **keys, + const char **vals, + size_t count) { + if (yyjson_likely(doc && ((count > 0 && keys && vals) || (count == 0)))) { + yyjson_mut_val *obj = unsafe_yyjson_mut_val(doc, 1 + count * 2); + if (yyjson_likely(obj)) { + obj->tag = ((uint64_t)count << YYJSON_TAG_BIT) | YYJSON_TYPE_OBJ; + if (count > 0) { + size_t i; + for (i = 0; i < count; i++) { + yyjson_mut_val *key = obj + (i * 2 + 1); + yyjson_mut_val *val = obj + (i * 2 + 2); + uint64_t key_len = (uint64_t)strlen(keys[i]); + uint64_t val_len = (uint64_t)strlen(vals[i]); + key->tag = (key_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + val->tag = (val_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + key->uni.str = keys[i]; + val->uni.str = vals[i]; + key->next = val; + val->next = val + 1; + } + obj[count * 2].next = obj + 1; + obj->uni.ptr = obj + (count * 2 - 1); + } + return obj; + } + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_kv(yyjson_mut_doc *doc, + const char **pairs, + size_t count) { + if (yyjson_likely(doc && ((count > 0 && pairs) || (count == 0)))) { + yyjson_mut_val *obj = unsafe_yyjson_mut_val(doc, 1 + count * 2); + if (yyjson_likely(obj)) { + obj->tag = ((uint64_t)count << YYJSON_TAG_BIT) | YYJSON_TYPE_OBJ; + if (count > 0) { + size_t i; + for (i = 0; i < count; i++) { + yyjson_mut_val *key = obj + (i * 2 + 1); + yyjson_mut_val *val = obj + (i * 2 + 2); + const char *key_str = pairs[i * 2 + 0]; + const char *val_str = pairs[i * 2 + 1]; + uint64_t key_len = (uint64_t)strlen(key_str); + uint64_t val_len = (uint64_t)strlen(val_str); + key->tag = (key_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + val->tag = (val_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + key->uni.str = key_str; + val->uni.str = val_str; + key->next = val; + val->next = val + 1; + } + obj[count * 2].next = obj + 1; + obj->uni.ptr = obj + (count * 2 - 1); + } + return obj; + } + } + return NULL; +} + + + +/*============================================================================== + * Mutable JSON Object Modification API (Implementation) + *============================================================================*/ + +yyjson_api_inline void unsafe_yyjson_mut_obj_add(yyjson_mut_val *obj, + yyjson_mut_val *key, + yyjson_mut_val *val, + size_t len) { + if (yyjson_likely(len)) { + yyjson_mut_val *prev_val = ((yyjson_mut_val *)obj->uni.ptr)->next; + yyjson_mut_val *next_key = prev_val->next; + prev_val->next = key; + val->next = next_key; + } else { + val->next = key; + } + key->next = val; + obj->uni.ptr = (void *)key; + unsafe_yyjson_set_len(obj, len + 1); +} + +yyjson_api_inline yyjson_mut_val *unsafe_yyjson_mut_obj_remove( + yyjson_mut_val *obj, const char *key, size_t key_len, uint64_t key_tag) { + size_t obj_len = unsafe_yyjson_get_len(obj); + if (obj_len) { + yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr; + yyjson_mut_val *cur_key = pre_key->next->next; + yyjson_mut_val *removed_item = NULL; + size_t i; + for (i = 0; i < obj_len; i++) { + if (key_tag == cur_key->tag && + memcmp(key, cur_key->uni.ptr, key_len) == 0) { + if (!removed_item) removed_item = cur_key->next; + cur_key = cur_key->next->next; + pre_key->next->next = cur_key; + if (i + 1 == obj_len) obj->uni.ptr = pre_key; + i--; + obj_len--; + } else { + pre_key = cur_key; + cur_key = cur_key->next->next; + } + } + unsafe_yyjson_set_len(obj, obj_len); + return removed_item; + } else { + return NULL; + } +} + +yyjson_api_inline bool unsafe_yyjson_mut_obj_replace(yyjson_mut_val *obj, + yyjson_mut_val *key, + yyjson_mut_val *val) { + size_t key_len = unsafe_yyjson_get_len(key); + size_t obj_len = unsafe_yyjson_get_len(obj); + if (obj_len) { + yyjson_mut_val *pre_key = (yyjson_mut_val *)obj->uni.ptr; + yyjson_mut_val *cur_key = pre_key->next->next; + size_t i; + for (i = 0; i < obj_len; i++) { + if (key->tag == cur_key->tag && + memcmp(key->uni.str, cur_key->uni.ptr, key_len) == 0) { + cur_key->next->tag = val->tag; + cur_key->next->uni.u64 = val->uni.u64; + return true; + } else { + cur_key = cur_key->next->next; + } + } + } + return false; +} + +yyjson_api_inline void unsafe_yyjson_mut_obj_rotate(yyjson_mut_val *obj, + size_t idx) { + yyjson_mut_val *key = (yyjson_mut_val *)obj->uni.ptr; + while (idx-- > 0) key = key->next->next; + obj->uni.ptr = (void *)key; +} + +yyjson_api_inline bool yyjson_mut_obj_add(yyjson_mut_val *obj, + yyjson_mut_val *key, + yyjson_mut_val *val) { + if (yyjson_likely(yyjson_mut_is_obj(obj) && + yyjson_mut_is_str(key) && val)) { + unsafe_yyjson_mut_obj_add(obj, key, val, unsafe_yyjson_get_len(obj)); + return true; + } + return false; +} + +yyjson_api_inline bool yyjson_mut_obj_put(yyjson_mut_val *obj, + yyjson_mut_val *key, + yyjson_mut_val *val) { + bool replaced = false; + size_t key_len; + yyjson_mut_obj_iter iter; + yyjson_mut_val *cur_key; + if (yyjson_unlikely(!yyjson_mut_is_obj(obj) || + !yyjson_mut_is_str(key))) return false; + key_len = unsafe_yyjson_get_len(key); + yyjson_mut_obj_iter_init(obj, &iter); + while ((cur_key = yyjson_mut_obj_iter_next(&iter))) { + if (key->tag == cur_key->tag && + memcmp(key->uni.str, cur_key->uni.ptr, key_len) == 0) { + if (!replaced && val) { + replaced = true; + val->next = cur_key->next->next; + cur_key->next = val; + } else { + yyjson_mut_obj_iter_remove(&iter); + } + } + } + if (!replaced && val) unsafe_yyjson_mut_obj_add(obj, key, val, iter.max); + return true; +} + +yyjson_api_inline bool yyjson_mut_obj_insert(yyjson_mut_val *obj, + yyjson_mut_val *key, + yyjson_mut_val *val, + size_t idx) { + if (yyjson_likely(yyjson_mut_is_obj(obj) && + yyjson_mut_is_str(key) && val)) { + size_t len = unsafe_yyjson_get_len(obj); + if (yyjson_likely(len >= idx)) { + if (len > idx) { + void *ptr = obj->uni.ptr; + unsafe_yyjson_mut_obj_rotate(obj, idx); + unsafe_yyjson_mut_obj_add(obj, key, val, len); + obj->uni.ptr = ptr; + } else { + unsafe_yyjson_mut_obj_add(obj, key, val, len); + } + return true; + } + } + return false; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove(yyjson_mut_val *obj, + yyjson_mut_val *key) { + if (yyjson_likely(yyjson_mut_is_obj(obj) && yyjson_mut_is_str(key))) { + return unsafe_yyjson_mut_obj_remove(obj, key->uni.str, + unsafe_yyjson_get_len(key), + key->tag); + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_key( + yyjson_mut_val *obj, const char *key) { + if (yyjson_likely(yyjson_mut_is_obj(obj) && key)) { + size_t key_len = strlen(key); + uint64_t tag = ((uint64_t)key_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + return unsafe_yyjson_mut_obj_remove(obj, key, key_len, tag); + } + return NULL; +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_keyn( + yyjson_mut_val *obj, const char *key, size_t key_len) { + if (yyjson_likely(yyjson_mut_is_obj(obj) && key)) { + uint64_t tag = ((uint64_t)key_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + return unsafe_yyjson_mut_obj_remove(obj, key, key_len, tag); + } + return NULL; +} + +yyjson_api_inline bool yyjson_mut_obj_clear(yyjson_mut_val *obj) { + if (yyjson_likely(yyjson_mut_is_obj(obj))) { + unsafe_yyjson_set_len(obj, 0); + return true; + } + return false; +} + +yyjson_api_inline bool yyjson_mut_obj_replace(yyjson_mut_val *obj, + yyjson_mut_val *key, + yyjson_mut_val *val) { + if (yyjson_likely(yyjson_mut_is_obj(obj) && + yyjson_mut_is_str(key) && val)) { + return unsafe_yyjson_mut_obj_replace(obj, key, val); + } + return false; +} + +yyjson_api_inline bool yyjson_mut_obj_rotate(yyjson_mut_val *obj, + size_t idx) { + if (yyjson_likely(yyjson_mut_is_obj(obj) && + unsafe_yyjson_get_len(obj) > idx)) { + unsafe_yyjson_mut_obj_rotate(obj, idx); + return true; + } + return false; +} + + + +/*============================================================================== + * Mutable JSON Object Modification Convenience API (Implementation) + *============================================================================*/ + +#define yyjson_mut_obj_add_func(func) \ + if (yyjson_likely(doc && yyjson_mut_is_obj(obj) && _key)) { \ + yyjson_mut_val *key = unsafe_yyjson_mut_val(doc, 2); \ + if (yyjson_likely(key)) { \ + size_t len = unsafe_yyjson_get_len(obj); \ + yyjson_mut_val *val = key + 1; \ + key->tag = YYJSON_TYPE_STR | YYJSON_SUBTYPE_NONE; \ + key->tag |= (uint64_t)strlen(_key) << YYJSON_TAG_BIT; \ + key->uni.str = _key; \ + func \ + unsafe_yyjson_mut_obj_add(obj, key, val, len); \ + return true; \ + } \ + } \ + return false + +yyjson_api_inline bool yyjson_mut_obj_add_null(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key) { + yyjson_mut_obj_add_func({ + val->tag = YYJSON_TYPE_NULL | YYJSON_SUBTYPE_NONE; + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_true(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key) { + yyjson_mut_obj_add_func({ + val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE; + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_false(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key) { + yyjson_mut_obj_add_func({ + val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE; + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_bool(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key, + bool _val) { + yyjson_mut_obj_add_func({ + val->tag = YYJSON_TYPE_BOOL | (uint8_t)((uint8_t)(_val) << 3); + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_uint(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key, + uint64_t _val) { + yyjson_mut_obj_add_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_UINT; + val->uni.u64 = _val; + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_sint(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key, + int64_t _val) { + yyjson_mut_obj_add_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT; + val->uni.i64 = _val; + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_int(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key, + int64_t _val) { + yyjson_mut_obj_add_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_SINT; + val->uni.i64 = _val; + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_real(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key, + double _val) { + yyjson_mut_obj_add_func({ + val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; + val->uni.f64 = _val; + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_str(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key, + const char *_val) { + if (yyjson_unlikely(!_val)) return false; + yyjson_mut_obj_add_func({ + val->tag = ((uint64_t)strlen(_val) << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + val->uni.str = _val; + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_strn(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key, + const char *_val, + size_t _len) { + if (yyjson_unlikely(!_val)) return false; + yyjson_mut_obj_add_func({ + val->tag = ((uint64_t)_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + val->uni.str = _val; + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_strcpy(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key, + const char *_val) { + if (yyjson_unlikely(!_val)) return false; + yyjson_mut_obj_add_func({ + size_t _len = strlen(_val); + val->uni.str = unsafe_yyjson_mut_strncpy(doc, _val, _len); + if (yyjson_unlikely(!val->uni.str)) return false; + val->tag = ((uint64_t)_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_strncpy(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key, + const char *_val, + size_t _len) { + if (yyjson_unlikely(!_val)) return false; + yyjson_mut_obj_add_func({ + val->uni.str = unsafe_yyjson_mut_strncpy(doc, _val, _len); + if (yyjson_unlikely(!val->uni.str)) return false; + val->tag = ((uint64_t)_len << YYJSON_TAG_BIT) | YYJSON_TYPE_STR; + }); +} + +yyjson_api_inline bool yyjson_mut_obj_add_val(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *_key, + yyjson_mut_val *_val) { + if (yyjson_unlikely(!_val)) return false; + yyjson_mut_obj_add_func({ + val = _val; + }); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_str(yyjson_mut_val *obj, + const char *key) { + return yyjson_mut_obj_remove_strn(obj, key, key ? strlen(key) : 0); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_remove_strn( + yyjson_mut_val *obj, const char *_key, size_t _len) { + if (yyjson_likely(yyjson_mut_is_obj(obj) && _key)) { + yyjson_mut_val *key; + yyjson_mut_obj_iter iter; + yyjson_mut_val *val_removed = NULL; + yyjson_mut_obj_iter_init(obj, &iter); + while ((key = yyjson_mut_obj_iter_next(&iter)) != NULL) { + if (unsafe_yyjson_get_len(key) == _len && + memcmp(key->uni.str, _key, _len) == 0) { + if (!val_removed) val_removed = key->next; + yyjson_mut_obj_iter_remove(&iter); + } + } + return val_removed; + } + return NULL; +} + +yyjson_api_inline bool yyjson_mut_obj_rename_key(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, + const char *new_key) { + if (!key || !new_key) return false; + return yyjson_mut_obj_rename_keyn(doc, obj, key, strlen(key), + new_key, strlen(new_key)); +} + +yyjson_api_inline bool yyjson_mut_obj_rename_keyn(yyjson_mut_doc *doc, + yyjson_mut_val *obj, + const char *key, + size_t len, + const char *new_key, + size_t new_len) { + char *cpy_key = NULL; + yyjson_mut_val *old_key; + yyjson_mut_obj_iter iter; + if (!doc || !obj || !key || !new_key) return false; + yyjson_mut_obj_iter_init(obj, &iter); + while ((old_key = yyjson_mut_obj_iter_next(&iter))) { + if (unsafe_yyjson_equals_strn((void *)old_key, key, len)) { + if (!cpy_key) { + cpy_key = unsafe_yyjson_mut_strncpy(doc, new_key, new_len); + if (!cpy_key) return false; + } + yyjson_mut_set_strn(old_key, cpy_key, new_len); + } + } + return cpy_key != NULL; +} + + + +/*============================================================================== + * JSON Pointer API (Implementation) + *============================================================================*/ + +#define yyjson_ptr_set_err(_code, _msg) do { \ + if (err) { \ + err->code = YYJSON_PTR_ERR_##_code; \ + err->msg = _msg; \ + err->pos = 0; \ + } \ +} while(false) + +/* require: val != NULL, *ptr == '/', len > 0 */ +yyjson_api yyjson_val *unsafe_yyjson_ptr_getx(yyjson_val *val, + const char *ptr, size_t len, + yyjson_ptr_err *err); + +/* require: val != NULL, *ptr == '/', len > 0 */ +yyjson_api yyjson_mut_val *unsafe_yyjson_mut_ptr_getx(yyjson_mut_val *val, + const char *ptr, + size_t len, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err); + +/* require: val/new_val/doc != NULL, *ptr == '/', len > 0 */ +yyjson_api bool unsafe_yyjson_mut_ptr_putx(yyjson_mut_val *val, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc, + bool create_parent, bool insert_new, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err); + +/* require: val/err != NULL, *ptr == '/', len > 0 */ +yyjson_api yyjson_mut_val *unsafe_yyjson_mut_ptr_replacex( + yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val, + yyjson_ptr_ctx *ctx, yyjson_ptr_err *err); + +/* require: val/err != NULL, *ptr == '/', len > 0 */ +yyjson_api yyjson_mut_val *unsafe_yyjson_mut_ptr_removex(yyjson_mut_val *val, + const char *ptr, + size_t len, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err); + +yyjson_api_inline yyjson_val *yyjson_doc_ptr_get(yyjson_doc *doc, + const char *ptr) { + if (yyjson_unlikely(!ptr)) return NULL; + return yyjson_doc_ptr_getn(doc, ptr, strlen(ptr)); +} + +yyjson_api_inline yyjson_val *yyjson_doc_ptr_getn(yyjson_doc *doc, + const char *ptr, size_t len) { + return yyjson_doc_ptr_getx(doc, ptr, len, NULL); +} + +yyjson_api_inline yyjson_val *yyjson_doc_ptr_getx(yyjson_doc *doc, + const char *ptr, size_t len, + yyjson_ptr_err *err) { + yyjson_ptr_set_err(NONE, NULL); + if (yyjson_unlikely(!doc || !ptr)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return NULL; + } + if (yyjson_unlikely(!doc->root)) { + yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL"); + return NULL; + } + if (yyjson_unlikely(len == 0)) { + return doc->root; + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return NULL; + } + return unsafe_yyjson_ptr_getx(doc->root, ptr, len, err); +} + +yyjson_api_inline yyjson_val *yyjson_ptr_get(yyjson_val *val, + const char *ptr) { + if (yyjson_unlikely(!ptr)) return NULL; + return yyjson_ptr_getn(val, ptr, strlen(ptr)); +} + +yyjson_api_inline yyjson_val *yyjson_ptr_getn(yyjson_val *val, + const char *ptr, size_t len) { + return yyjson_ptr_getx(val, ptr, len, NULL); +} + +yyjson_api_inline yyjson_val *yyjson_ptr_getx(yyjson_val *val, + const char *ptr, size_t len, + yyjson_ptr_err *err) { + yyjson_ptr_set_err(NONE, NULL); + if (yyjson_unlikely(!val || !ptr)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return NULL; + } + if (yyjson_unlikely(len == 0)) { + return val; + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return NULL; + } + return unsafe_yyjson_ptr_getx(val, ptr, len, err); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_get(yyjson_mut_doc *doc, + const char *ptr) { + if (!ptr) return NULL; + return yyjson_mut_doc_ptr_getn(doc, ptr, strlen(ptr)); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_getn(yyjson_mut_doc *doc, + const char *ptr, + size_t len) { + return yyjson_mut_doc_ptr_getx(doc, ptr, len, NULL, NULL); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_getx(yyjson_mut_doc *doc, + const char *ptr, + size_t len, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err) { + yyjson_ptr_set_err(NONE, NULL); + if (ctx) memset(ctx, 0, sizeof(*ctx)); + + if (yyjson_unlikely(!doc || !ptr)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return NULL; + } + if (yyjson_unlikely(!doc->root)) { + yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL"); + return NULL; + } + if (yyjson_unlikely(len == 0)) { + return doc->root; + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return NULL; + } + return unsafe_yyjson_mut_ptr_getx(doc->root, ptr, len, ctx, err); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_get(yyjson_mut_val *val, + const char *ptr) { + if (!ptr) return NULL; + return yyjson_mut_ptr_getn(val, ptr, strlen(ptr)); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_getn(yyjson_mut_val *val, + const char *ptr, + size_t len) { + return yyjson_mut_ptr_getx(val, ptr, len, NULL, NULL); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_getx(yyjson_mut_val *val, + const char *ptr, + size_t len, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err) { + yyjson_ptr_set_err(NONE, NULL); + if (ctx) memset(ctx, 0, sizeof(*ctx)); + + if (yyjson_unlikely(!val || !ptr)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return NULL; + } + if (yyjson_unlikely(len == 0)) { + return val; + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return NULL; + } + return unsafe_yyjson_mut_ptr_getx(val, ptr, len, ctx, err); +} + +yyjson_api_inline bool yyjson_mut_doc_ptr_add(yyjson_mut_doc *doc, + const char *ptr, + yyjson_mut_val *new_val) { + if (yyjson_unlikely(!ptr)) return false; + return yyjson_mut_doc_ptr_addn(doc, ptr, strlen(ptr), new_val); +} + +yyjson_api_inline bool yyjson_mut_doc_ptr_addn(yyjson_mut_doc *doc, + const char *ptr, + size_t len, + yyjson_mut_val *new_val) { + return yyjson_mut_doc_ptr_addx(doc, ptr, len, new_val, true, NULL, NULL); +} + +yyjson_api_inline bool yyjson_mut_doc_ptr_addx(yyjson_mut_doc *doc, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + bool create_parent, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err) { + yyjson_ptr_set_err(NONE, NULL); + if (ctx) memset(ctx, 0, sizeof(*ctx)); + + if (yyjson_unlikely(!doc || !ptr || !new_val)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return false; + } + if (yyjson_unlikely(len == 0)) { + if (doc->root) { + yyjson_ptr_set_err(SET_ROOT, "cannot set document's root"); + return false; + } else { + doc->root = new_val; + return true; + } + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return false; + } + if (yyjson_unlikely(!doc->root && !create_parent)) { + yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL"); + return false; + } + if (yyjson_unlikely(!doc->root)) { + yyjson_mut_val *root = yyjson_mut_obj(doc); + if (yyjson_unlikely(!root)) { + yyjson_ptr_set_err(MEMORY_ALLOCATION, "failed to create value"); + return false; + } + if (unsafe_yyjson_mut_ptr_putx(root, ptr, len, new_val, doc, + create_parent, true, ctx, err)) { + doc->root = root; + return true; + } + return false; + } + return unsafe_yyjson_mut_ptr_putx(doc->root, ptr, len, new_val, doc, + create_parent, true, ctx, err); +} + +yyjson_api_inline bool yyjson_mut_ptr_add(yyjson_mut_val *val, + const char *ptr, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc) { + if (yyjson_unlikely(!ptr)) return false; + return yyjson_mut_ptr_addn(val, ptr, strlen(ptr), new_val, doc); +} + +yyjson_api_inline bool yyjson_mut_ptr_addn(yyjson_mut_val *val, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc) { + return yyjson_mut_ptr_addx(val, ptr, len, new_val, doc, true, NULL, NULL); +} + +yyjson_api_inline bool yyjson_mut_ptr_addx(yyjson_mut_val *val, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc, + bool create_parent, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err) { + yyjson_ptr_set_err(NONE, NULL); + if (ctx) memset(ctx, 0, sizeof(*ctx)); + + if (yyjson_unlikely(!val || !ptr || !new_val || !doc)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return false; + } + if (yyjson_unlikely(len == 0)) { + yyjson_ptr_set_err(SET_ROOT, "cannot set root"); + return false; + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return false; + } + return unsafe_yyjson_mut_ptr_putx(val, ptr, len, new_val, + doc, create_parent, true, ctx, err); +} + +yyjson_api_inline bool yyjson_mut_doc_ptr_set(yyjson_mut_doc *doc, + const char *ptr, + yyjson_mut_val *new_val) { + if (yyjson_unlikely(!ptr)) return false; + return yyjson_mut_doc_ptr_setn(doc, ptr, strlen(ptr), new_val); +} + +yyjson_api_inline bool yyjson_mut_doc_ptr_setn(yyjson_mut_doc *doc, + const char *ptr, size_t len, + yyjson_mut_val *new_val) { + return yyjson_mut_doc_ptr_setx(doc, ptr, len, new_val, true, NULL, NULL); +} + +yyjson_api_inline bool yyjson_mut_doc_ptr_setx(yyjson_mut_doc *doc, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + bool create_parent, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err) { + yyjson_ptr_set_err(NONE, NULL); + if (ctx) memset(ctx, 0, sizeof(*ctx)); + + if (yyjson_unlikely(!doc || !ptr)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return false; + } + if (yyjson_unlikely(len == 0)) { + if (ctx) ctx->old = doc->root; + doc->root = new_val; + return true; + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return false; + } + if (!new_val) { + if (!doc->root) { + yyjson_ptr_set_err(RESOLVE, "JSON pointer cannot be resolved"); + return false; + } + return !!unsafe_yyjson_mut_ptr_removex(doc->root, ptr, len, ctx, err); + } + if (yyjson_unlikely(!doc->root && !create_parent)) { + yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL"); + return false; + } + if (yyjson_unlikely(!doc->root)) { + yyjson_mut_val *root = yyjson_mut_obj(doc); + if (yyjson_unlikely(!root)) { + yyjson_ptr_set_err(MEMORY_ALLOCATION, "failed to create value"); + return false; + } + if (unsafe_yyjson_mut_ptr_putx(root, ptr, len, new_val, doc, + create_parent, false, ctx, err)) { + doc->root = root; + return true; + } + return false; + } + return unsafe_yyjson_mut_ptr_putx(doc->root, ptr, len, new_val, doc, + create_parent, false, ctx, err); +} + +yyjson_api_inline bool yyjson_mut_ptr_set(yyjson_mut_val *val, + const char *ptr, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc) { + if (yyjson_unlikely(!ptr)) return false; + return yyjson_mut_ptr_setn(val, ptr, strlen(ptr), new_val, doc); +} + +yyjson_api_inline bool yyjson_mut_ptr_setn(yyjson_mut_val *val, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc) { + return yyjson_mut_ptr_setx(val, ptr, len, new_val, doc, true, NULL, NULL); +} + +yyjson_api_inline bool yyjson_mut_ptr_setx(yyjson_mut_val *val, + const char *ptr, size_t len, + yyjson_mut_val *new_val, + yyjson_mut_doc *doc, + bool create_parent, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err) { + yyjson_ptr_set_err(NONE, NULL); + if (ctx) memset(ctx, 0, sizeof(*ctx)); + + if (yyjson_unlikely(!val || !ptr || !doc)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return false; + } + if (yyjson_unlikely(len == 0)) { + yyjson_ptr_set_err(SET_ROOT, "cannot set root"); + return false; + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return false; + } + if (!new_val) { + return !!unsafe_yyjson_mut_ptr_removex(val, ptr, len, ctx, err); + } + return unsafe_yyjson_mut_ptr_putx(val, ptr, len, new_val, doc, + create_parent, false, ctx, err); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replace( + yyjson_mut_doc *doc, const char *ptr, yyjson_mut_val *new_val) { + if (!ptr) return NULL; + return yyjson_mut_doc_ptr_replacen(doc, ptr, strlen(ptr), new_val); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replacen( + yyjson_mut_doc *doc, const char *ptr, size_t len, yyjson_mut_val *new_val) { + return yyjson_mut_doc_ptr_replacex(doc, ptr, len, new_val, NULL, NULL); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_replacex( + yyjson_mut_doc *doc, const char *ptr, size_t len, yyjson_mut_val *new_val, + yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) { + + yyjson_ptr_set_err(NONE, NULL); + if (ctx) memset(ctx, 0, sizeof(*ctx)); + + if (yyjson_unlikely(!doc || !ptr || !new_val)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return NULL; + } + if (yyjson_unlikely(len == 0)) { + yyjson_mut_val *root = doc->root; + if (yyjson_unlikely(!root)) { + yyjson_ptr_set_err(RESOLVE, "JSON pointer cannot be resolved"); + return NULL; + } + if (ctx) ctx->old = root; + doc->root = new_val; + return root; + } + if (yyjson_unlikely(!doc->root)) { + yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL"); + return NULL; + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return NULL; + } + return unsafe_yyjson_mut_ptr_replacex(doc->root, ptr, len, new_val, + ctx, err); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replace( + yyjson_mut_val *val, const char *ptr, yyjson_mut_val *new_val) { + if (!ptr) return NULL; + return yyjson_mut_ptr_replacen(val, ptr, strlen(ptr), new_val); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replacen( + yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val) { + return yyjson_mut_ptr_replacex(val, ptr, len, new_val, NULL, NULL); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_replacex( + yyjson_mut_val *val, const char *ptr, size_t len, yyjson_mut_val *new_val, + yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) { + + yyjson_ptr_set_err(NONE, NULL); + if (ctx) memset(ctx, 0, sizeof(*ctx)); + + if (yyjson_unlikely(!val || !ptr || !new_val)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return NULL; + } + if (yyjson_unlikely(len == 0)) { + yyjson_ptr_set_err(SET_ROOT, "cannot set root"); + return NULL; + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return NULL; + } + return unsafe_yyjson_mut_ptr_replacex(val, ptr, len, new_val, ctx, err); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_remove( + yyjson_mut_doc *doc, const char *ptr) { + if (!ptr) return NULL; + return yyjson_mut_doc_ptr_removen(doc, ptr, strlen(ptr)); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_removen( + yyjson_mut_doc *doc, const char *ptr, size_t len) { + return yyjson_mut_doc_ptr_removex(doc, ptr, len, NULL, NULL); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_ptr_removex( + yyjson_mut_doc *doc, const char *ptr, size_t len, + yyjson_ptr_ctx *ctx, yyjson_ptr_err *err) { + + yyjson_ptr_set_err(NONE, NULL); + if (ctx) memset(ctx, 0, sizeof(*ctx)); + + if (yyjson_unlikely(!doc || !ptr)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return NULL; + } + if (yyjson_unlikely(!doc->root)) { + yyjson_ptr_set_err(NULL_ROOT, "document's root is NULL"); + return NULL; + } + if (yyjson_unlikely(len == 0)) { + yyjson_mut_val *root = doc->root; + if (ctx) ctx->old = root; + doc->root = NULL; + return root; + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return NULL; + } + return unsafe_yyjson_mut_ptr_removex(doc->root, ptr, len, ctx, err); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_remove(yyjson_mut_val *val, + const char *ptr) { + if (!ptr) return NULL; + return yyjson_mut_ptr_removen(val, ptr, strlen(ptr)); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_removen(yyjson_mut_val *val, + const char *ptr, + size_t len) { + return yyjson_mut_ptr_removex(val, ptr, len, NULL, NULL); +} + +yyjson_api_inline yyjson_mut_val *yyjson_mut_ptr_removex(yyjson_mut_val *val, + const char *ptr, + size_t len, + yyjson_ptr_ctx *ctx, + yyjson_ptr_err *err) { + yyjson_ptr_set_err(NONE, NULL); + if (ctx) memset(ctx, 0, sizeof(*ctx)); + + if (yyjson_unlikely(!val || !ptr)) { + yyjson_ptr_set_err(PARAMETER, "input parameter is NULL"); + return NULL; + } + if (yyjson_unlikely(len == 0)) { + yyjson_ptr_set_err(SET_ROOT, "cannot set root"); + return NULL; + } + if (yyjson_unlikely(*ptr != '/')) { + yyjson_ptr_set_err(SYNTAX, "no prefix '/'"); + return NULL; + } + return unsafe_yyjson_mut_ptr_removex(val, ptr, len, ctx, err); +} + +yyjson_api_inline bool yyjson_ptr_ctx_append(yyjson_ptr_ctx *ctx, + yyjson_mut_val *key, + yyjson_mut_val *val) { + yyjson_mut_val *ctn, *pre_key, *pre_val, *cur_key, *cur_val; + if (!ctx || !ctx->ctn || !val) return false; + ctn = ctx->ctn; + + if (yyjson_mut_is_obj(ctn)) { + if (!key) return false; + key->next = val; + pre_key = ctx->pre; + if (unsafe_yyjson_get_len(ctn) == 0) { + val->next = key; + ctn->uni.ptr = key; + ctx->pre = key; + } else if (!pre_key) { + pre_key = (yyjson_mut_val *)ctn->uni.ptr; + pre_val = pre_key->next; + val->next = pre_val->next; + pre_val->next = key; + ctn->uni.ptr = key; + ctx->pre = pre_key; + } else { + cur_key = pre_key->next->next; + cur_val = cur_key->next; + val->next = cur_val->next; + cur_val->next = key; + if (ctn->uni.ptr == cur_key) ctn->uni.ptr = key; + ctx->pre = cur_key; + } + } else { + pre_val = ctx->pre; + if (unsafe_yyjson_get_len(ctn) == 0) { + val->next = val; + ctn->uni.ptr = val; + ctx->pre = val; + } else if (!pre_val) { + pre_val = (yyjson_mut_val *)ctn->uni.ptr; + val->next = pre_val->next; + pre_val->next = val; + ctn->uni.ptr = val; + ctx->pre = pre_val; + } else { + cur_val = pre_val->next; + val->next = cur_val->next; + cur_val->next = val; + if (ctn->uni.ptr == cur_val) ctn->uni.ptr = val; + ctx->pre = cur_val; + } + } + unsafe_yyjson_inc_len(ctn); + return true; +} + +yyjson_api_inline bool yyjson_ptr_ctx_replace(yyjson_ptr_ctx *ctx, + yyjson_mut_val *val) { + yyjson_mut_val *ctn, *pre_key, *cur_key, *pre_val, *cur_val; + if (!ctx || !ctx->ctn || !ctx->pre || !val) return false; + ctn = ctx->ctn; + if (yyjson_mut_is_obj(ctn)) { + pre_key = ctx->pre; + pre_val = pre_key->next; + cur_key = pre_val->next; + cur_val = cur_key->next; + /* replace current value */ + cur_key->next = val; + val->next = cur_val->next; + ctx->old = cur_val; + } else { + pre_val = ctx->pre; + cur_val = pre_val->next; + /* replace current value */ + if (pre_val != cur_val) { + val->next = cur_val->next; + pre_val->next = val; + if (ctn->uni.ptr == cur_val) ctn->uni.ptr = val; + } else { + val->next = val; + ctn->uni.ptr = val; + ctx->pre = val; + } + ctx->old = cur_val; + } + return true; +} + +yyjson_api_inline bool yyjson_ptr_ctx_remove(yyjson_ptr_ctx *ctx) { + yyjson_mut_val *ctn, *pre_key, *pre_val, *cur_key, *cur_val; + size_t len; + if (!ctx || !ctx->ctn || !ctx->pre) return false; + ctn = ctx->ctn; + if (yyjson_mut_is_obj(ctn)) { + pre_key = ctx->pre; + pre_val = pre_key->next; + cur_key = pre_val->next; + cur_val = cur_key->next; + /* remove current key-value */ + pre_val->next = cur_val->next; + if (ctn->uni.ptr == cur_key) ctn->uni.ptr = pre_key; + ctx->pre = NULL; + ctx->old = cur_val; + } else { + pre_val = ctx->pre; + cur_val = pre_val->next; + /* remove current key-value */ + pre_val->next = cur_val->next; + if (ctn->uni.ptr == cur_val) ctn->uni.ptr = pre_val; + ctx->pre = NULL; + ctx->old = cur_val; + } + len = unsafe_yyjson_get_len(ctn) - 1; + if (len == 0) ctn->uni.ptr = NULL; + unsafe_yyjson_set_len(ctn, len); + return true; +} + +#undef yyjson_ptr_set_err + + + +/*============================================================================== + * JSON Value at Pointer API (Implementation) + *============================================================================*/ + +/** + Set provided `value` if the JSON Pointer (RFC 6901) exists and is type bool. + Returns true if value at `ptr` exists and is the correct type, otherwise false. + */ +yyjson_api_inline bool yyjson_ptr_get_bool( + yyjson_val *root, const char *ptr, bool *value) { + yyjson_val *val = yyjson_ptr_get(root, ptr); + if (value && yyjson_is_bool(val)) { + *value = unsafe_yyjson_get_bool(val); + return true; + } else { + return false; + } +} + +/** + Set provided `value` if the JSON Pointer (RFC 6901) exists and is type uint. + Returns true if value at `ptr` exists and is the correct type, otherwise false. + */ +yyjson_api_inline bool yyjson_ptr_get_uint( + yyjson_val *root, const char *ptr, uint64_t *value) { + yyjson_val *val = yyjson_ptr_get(root, ptr); + if (value && yyjson_is_uint(val)) { + *value = unsafe_yyjson_get_uint(val); + return true; + } else { + return false; + } +} + +/** + Set provided `value` if the JSON Pointer (RFC 6901) exists and is type sint. + Returns true if value at `ptr` exists and is the correct type, otherwise false. + */ +yyjson_api_inline bool yyjson_ptr_get_sint( + yyjson_val *root, const char *ptr, int64_t *value) { + yyjson_val *val = yyjson_ptr_get(root, ptr); + if (value && yyjson_is_sint(val)) { + *value = unsafe_yyjson_get_sint(val); + return true; + } else { + return false; + } +} + +/** + Set provided `value` if the JSON Pointer (RFC 6901) exists and is type real. + Returns true if value at `ptr` exists and is the correct type, otherwise false. + */ +yyjson_api_inline bool yyjson_ptr_get_real( + yyjson_val *root, const char *ptr, double *value) { + yyjson_val *val = yyjson_ptr_get(root, ptr); + if (value && yyjson_is_real(val)) { + *value = unsafe_yyjson_get_real(val); + return true; + } else { + return false; + } +} + +/** + Set provided `value` if the JSON Pointer (RFC 6901) exists and is type sint, + uint or real. + Returns true if value at `ptr` exists and is the correct type, otherwise false. + */ +yyjson_api_inline bool yyjson_ptr_get_num( + yyjson_val *root, const char *ptr, double *value) { + yyjson_val *val = yyjson_ptr_get(root, ptr); + if (value && yyjson_is_num(val)) { + *value = unsafe_yyjson_get_num(val); + return true; + } else { + return false; + } +} + +/** + Set provided `value` if the JSON Pointer (RFC 6901) exists and is type string. + Returns true if value at `ptr` exists and is the correct type, otherwise false. + */ +yyjson_api_inline bool yyjson_ptr_get_str( + yyjson_val *root, const char *ptr, const char **value) { + yyjson_val *val = yyjson_ptr_get(root, ptr); + if (value && yyjson_is_str(val)) { + *value = unsafe_yyjson_get_str(val); + return true; + } else { + return false; + } +} + + + +/*============================================================================== + * Deprecated + *============================================================================*/ + +/** @deprecated renamed to `yyjson_doc_ptr_get` */ +yyjson_deprecated("renamed to yyjson_doc_ptr_get") +yyjson_api_inline yyjson_val *yyjson_doc_get_pointer(yyjson_doc *doc, + const char *ptr) { + return yyjson_doc_ptr_get(doc, ptr); +} + +/** @deprecated renamed to `yyjson_doc_ptr_getn` */ +yyjson_deprecated("renamed to yyjson_doc_ptr_getn") +yyjson_api_inline yyjson_val *yyjson_doc_get_pointern(yyjson_doc *doc, + const char *ptr, + size_t len) { + return yyjson_doc_ptr_getn(doc, ptr, len); +} + +/** @deprecated renamed to `yyjson_mut_doc_ptr_get` */ +yyjson_deprecated("renamed to yyjson_mut_doc_ptr_get") +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_get_pointer( + yyjson_mut_doc *doc, const char *ptr) { + return yyjson_mut_doc_ptr_get(doc, ptr); +} + +/** @deprecated renamed to `yyjson_mut_doc_ptr_getn` */ +yyjson_deprecated("renamed to yyjson_mut_doc_ptr_getn") +yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_get_pointern( + yyjson_mut_doc *doc, const char *ptr, size_t len) { + return yyjson_mut_doc_ptr_getn(doc, ptr, len); +} + +/** @deprecated renamed to `yyjson_ptr_get` */ +yyjson_deprecated("renamed to yyjson_ptr_get") +yyjson_api_inline yyjson_val *yyjson_get_pointer(yyjson_val *val, + const char *ptr) { + return yyjson_ptr_get(val, ptr); +} + +/** @deprecated renamed to `yyjson_ptr_getn` */ +yyjson_deprecated("renamed to yyjson_ptr_getn") +yyjson_api_inline yyjson_val *yyjson_get_pointern(yyjson_val *val, + const char *ptr, + size_t len) { + return yyjson_ptr_getn(val, ptr, len); +} + +/** @deprecated renamed to `yyjson_mut_ptr_get` */ +yyjson_deprecated("renamed to yyjson_mut_ptr_get") +yyjson_api_inline yyjson_mut_val *yyjson_mut_get_pointer(yyjson_mut_val *val, + const char *ptr) { + return yyjson_mut_ptr_get(val, ptr); +} + +/** @deprecated renamed to `yyjson_mut_ptr_getn` */ +yyjson_deprecated("renamed to yyjson_mut_ptr_getn") +yyjson_api_inline yyjson_mut_val *yyjson_mut_get_pointern(yyjson_mut_val *val, + const char *ptr, + size_t len) { + return yyjson_mut_ptr_getn(val, ptr, len); +} + +/** @deprecated renamed to `yyjson_mut_ptr_getn` */ +yyjson_deprecated("renamed to unsafe_yyjson_ptr_getn") +yyjson_api_inline yyjson_val *unsafe_yyjson_get_pointer(yyjson_val *val, + const char *ptr, + size_t len) { + yyjson_ptr_err err; + return unsafe_yyjson_ptr_getx(val, ptr, len, &err); +} + +/** @deprecated renamed to `unsafe_yyjson_mut_ptr_getx` */ +yyjson_deprecated("renamed to unsafe_yyjson_mut_ptr_getx") +yyjson_api_inline yyjson_mut_val *unsafe_yyjson_mut_get_pointer( + yyjson_mut_val *val, const char *ptr, size_t len) { + yyjson_ptr_err err; + return unsafe_yyjson_mut_ptr_getx(val, ptr, len, NULL, &err); +} + + + +/*============================================================================== + * Compiler Hint End + *============================================================================*/ + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +# pragma GCC diagnostic pop +# endif +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif /* warning suppress end */ + +#ifdef __cplusplus +} +#endif /* extern "C" end */ + +#endif /* YYJSON_H */ diff --git a/meson.build b/meson.build index 0af687d..d8ec305 100644 --- a/meson.build +++ b/meson.build @@ -1,8 +1,10 @@ project( - 'draconis++', 'cpp', + 'draconis++', ['cpp', 'objcpp'], version: '0.1.0', default_options: [ - 'cpp_std=c++26', + 'objc_std=c++20', + 'objcpp_std=c++20', + 'cpp_std=c++20', 'default_library=static', 'warning_level=everything', 'buildtype=debugoptimized' @@ -12,6 +14,21 @@ project( clangtidy = find_program('clang-tidy', required: false) cpp = meson.get_compiler('cpp') +objcpp = meson.get_compiler('objcpp') + +add_project_arguments( + objcpp.get_supported_arguments([ + '-Wno-c++20-compat', + '-Wno-c++98-compat', + '-Wno-c++98-compat-pedantic', + '-Wno-missing-prototypes', + '-Wno-padded', + '-Wno-pre-c++20-compat-pedantic', + '-Wno-switch-default', + '-Wunused-function', + ]), + language: 'objcpp' +) add_project_arguments( cpp.get_supported_arguments([ @@ -22,7 +39,7 @@ add_project_arguments( '-Wno-padded', '-Wno-pre-c++20-compat-pedantic', '-Wno-switch-default', - '-Wunused-function' + '-Wunused-function', ]), language: 'cpp' ) @@ -40,7 +57,11 @@ if host_machine.system() == 'linux' endif if host_machine.system() == 'darwin' - source_file_names += ['src/os/macos.cpp'] + source_file_names += [ + 'src/os/macos.cpp', + 'src/os/macos/NowPlayingBridge.h', + 'src/os/macos/NowPlayingBridge.mm' + ] endif sources = [] @@ -49,16 +70,16 @@ foreach file : source_file_names sources += files(file) endforeach -quill = subproject('quill') - deps = [] deps += cpp.find_library('cpr') deps += cpp.find_library('curl') deps += cpp.find_library('tomlplusplus') -deps += dependency('boost', static: true) +deps += dependency('coost') deps += dependency('fmt') -deps += quill.get_variable('quill_dep') +deps += dependency('Foundation') +deps += dependency('MediaPlayer') + if host_machine.system() == 'linux' deps += dependency('playerctl') @@ -73,5 +94,7 @@ executable( 'draconis++', sources, dependencies: deps, - include_directories: incdir + include_directories: incdir, + objc_args: ['-fobjc-arc'], + link_args: ['-framework', 'Foundation', '-framework', 'MediaPlayer'] ) diff --git a/src/config/config.cpp b/src/config/config.cpp index 3ad95d3..04c65b0 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -1,9 +1,3 @@ -#include -#include -#include -#include -#include - #include "config.h" #define DEFINE_GETTER(class_name, type, name) \ @@ -21,9 +15,11 @@ DEFINE_GETTER(Weather, const string, ApiKey) DEFINE_GETTER(Weather, const string, Units) const Config& Config::getInstance() { - static const Config& INSTANCE = - *new Config(rfl::toml::load("./config.toml").value()); - return INSTANCE; + static const auto* INSTANCE = + new Config(rfl::toml::load("./config.toml").value()); + static std::once_flag Flag; + std::call_once(Flag, [] { std::atexit([] { delete INSTANCE; }); }); + return *INSTANCE; } Config::Config(General general, NowPlaying now_playing, Weather weather) diff --git a/src/config/config.h b/src/config/config.h index 6b9cd13..00b7121 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -1,13 +1,9 @@ -#pragma once - -#include +#include #include #include #include +#include #include -#include -#include -#include #include using std::string; @@ -29,7 +25,7 @@ class Weather { public: Weather(Location location, string api_key, string units); - [[nodiscard]] boost::json::object getWeatherInfo() const; + [[nodiscard]] co::Json getWeatherInfo() const; [[nodiscard]] const Location getLocation() const; [[nodiscard]] const string getApiKey() const; [[nodiscard]] const string getUnits() const; diff --git a/src/config/weather.cpp b/src/config/weather.cpp index 673d39a..9ad216d 100644 --- a/src/config/weather.cpp +++ b/src/config/weather.cpp @@ -1,83 +1,77 @@ -#include -#include -#include -#include - #include "config.h" -using namespace std; -using namespace chrono; -using namespace boost; - // Function to read cache from file -optional> ReadCacheFromFile() { +std::optional> +ReadCacheFromFile() { const string cacheFile = "/tmp/weather_cache.json"; - ifstream ifs(cacheFile); + std::ifstream ifs(cacheFile); if (!ifs.is_open()) { fmt::println("Cache file not found."); - return nullopt; + return std::nullopt; } fmt::println("Reading from cache file..."); - json::object cachedData; - system_clock::time_point timestamp; + co::Json val; + std::chrono::system_clock::time_point timestamp; try { - json::value val; - ifs >> val; - cachedData = val.as_object(); + std::stringstream buf; + buf << ifs.rdbuf(); - string tsStr = cachedData["timestamp"].as_string().c_str(); - timestamp = system_clock::time_point(milliseconds(stoll(tsStr))); + val.parse_from(buf.str()); - cachedData.erase("timestamp"); + string tsStr = val["timestamp"].as_string().c_str(); + timestamp = std::chrono::system_clock::time_point( + std::chrono::milliseconds(stoll(tsStr))); + + val.erase("timestamp"); } catch (...) { fmt::println(stderr, "Failed to read from cache file."); - return nullopt; + return std::nullopt; } fmt::println("Successfully read from cache file."); - return make_pair(cachedData, timestamp); + return make_pair(val, timestamp); } // Function to write cache to file -void WriteCacheToFile(const json::object& data) { +void WriteCacheToFile(const co::Json& data) { const string cacheFile = "/tmp/weather_cache.json"; fmt::println("Writing to cache file..."); - ofstream ofs(cacheFile); + std::ofstream ofs(cacheFile); if (!ofs.is_open()) { fmt::println(stderr, "Failed to open cache file for writing."); return; } - json::object dataToWrite = data; + data["timestamp"] = + std::to_string(duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count()); - dataToWrite["timestamp"] = to_string( - duration_cast(system_clock::now().time_since_epoch()) - .count()); - - ofs << json::serialize(dataToWrite); + ofs << data.as_string(); fmt::println("Successfully wrote to cache file."); } // Function to make API request -json::object MakeApiRequest(const string& url) { +co::Json MakeApiRequest(const string& url) { using namespace cpr; fmt::println("Making API request..."); const Response res = Get(Url {url}); fmt::println("Received response from API."); - json::value json = json::parse(res.text); - return json.as_object(); + co::Json json = json::parse(res.text); + + return json; } // Core function to get weather information -json::object Weather::getWeatherInfo() const { +co::Json Weather::getWeatherInfo() const { using namespace cpr; const Location loc = m_Location; @@ -86,10 +80,11 @@ json::object Weather::getWeatherInfo() const { // Check if cache is valid if (auto cachedData = ReadCacheFromFile()) { - auto [data, timestamp] = *cachedData; + auto& [data, timestamp] = *cachedData; - if (system_clock::now() - timestamp < - minutes(10)) { // Assuming cache duration is always 10 minutes + if (std::chrono::system_clock::now() - timestamp < + std::chrono::minutes( + 10)) { // Assuming cache duration is always 10 minutes fmt::println("Cache is valid. Returning cached data."); return data; } @@ -99,7 +94,7 @@ json::object Weather::getWeatherInfo() const { fmt::println("No valid cache found."); } - json::object result; + co::Json result; if (holds_alternative(loc)) { const string city = get(loc); diff --git a/src/main.cpp b/src/main.cpp index 60f5f61..2f5bd2f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,17 +1,10 @@ -#include -#include +#include #include -#include #include #include -#include -#include -#include -#include -#include -#include #include "config/config.h" +#include "os/macos/NowPlayingBridge.h" #include "os/os.h" using std::string; @@ -49,9 +42,10 @@ DateNum ParseDate(string const& input) { return Default; } -int main() { - using boost::json::object; - using std::time_t; +int main(int argc, char** argv) { + flag::parse(argc, argv); + + LOG << "hello " << 23; const Config& config = Config::getInstance(); @@ -97,12 +91,13 @@ int main() { fmt::println("{:%B} {}, {:%-I:%0M %p}", localTime, date, localTime); - object json = config.getWeather().getWeatherInfo(); + co::Json json = config.getWeather().getWeatherInfo(); + const int temp = json.get("main", "temp").as_int(); const char* townName = json["name"].is_string() ? json["name"].as_string().c_str() : "Unknown"; - fmt::println("{}", townName); + fmt::println("It is {}°F in {}", temp, townName); return 0; } diff --git a/src/os/linux.cpp b/src/os/linux.cpp index c881e69..1c3506a 100644 --- a/src/os/linux.cpp +++ b/src/os/linux.cpp @@ -1,8 +1,9 @@ #ifdef __linux__ #include -#include #include +#include + #include "os.h" using std::string; diff --git a/src/os/macos.cpp b/src/os/macos.cpp index 775f984..b788cb6 100644 --- a/src/os/macos.cpp +++ b/src/os/macos.cpp @@ -1,12 +1,14 @@ #ifdef __APPLE__ -#include #include +#include + +#include "macos/NowPlayingBridge.h" #include "os.h" uint64_t GetMemInfo() { uint64_t mem = 0; - size_t size = sizeof(mem); + size_t size = sizeof(mem); sysctlbyname("hw.memsize", &mem, &size, nullptr, 0); @@ -14,7 +16,7 @@ uint64_t GetMemInfo() { } std::string GetNowPlaying() { - return ""; + return getCurrentPlayingTitle(); } #endif diff --git a/src/os/macos/NowPlayingBridge.h b/src/os/macos/NowPlayingBridge.h new file mode 100644 index 0000000..0cbfe85 --- /dev/null +++ b/src/os/macos/NowPlayingBridge.h @@ -0,0 +1,14 @@ +// NowPlayingBridge.h + +#ifdef __OBJC__ +#import + +@interface NowPlayingBridge : NSObject ++ (NSDictionary*)currentPlayingMetadata; +@end +#else +extern "C" { +const char* getCurrentPlayingTitle(); +const char* getCurrentPlayingArtist(); +} +#endif diff --git a/src/os/macos/NowPlayingBridge.mm b/src/os/macos/NowPlayingBridge.mm new file mode 100644 index 0000000..dae0296 --- /dev/null +++ b/src/os/macos/NowPlayingBridge.mm @@ -0,0 +1,90 @@ +// NowPlayingBridge.mm + +#import "NowPlayingBridge.h" +#import +#import +#import + +typedef void (*MRMediaRemoteGetNowPlayingInfoFunction)( + dispatch_queue_t queue, void (^handler)(NSDictionary *information)); + +@implementation NowPlayingBridge + ++ (NSDictionary *)currentPlayingMetadata { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" + + CFURLRef ref = (__bridge CFURLRef) + [NSURL fileURLWithPath: + @"/System/Library/PrivateFrameworks/MediaRemote.framework"]; + +#pragma clang diagnostic pop + + CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, ref); + + if (!bundle) { + NSLog(@"Failed to load MediaRemote framework"); + return nil; + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" + + MRMediaRemoteGetNowPlayingInfoFunction MRMediaRemoteGetNowPlayingInfo = + (MRMediaRemoteGetNowPlayingInfoFunction)CFBundleGetFunctionPointerForName( + bundle, CFSTR("MRMediaRemoteGetNowPlayingInfo")); + +#pragma clang diagnostic pop + + if (!MRMediaRemoteGetNowPlayingInfo) { + NSLog(@"Failed to get function pointer for MRMediaRemoteGetNowPlayingInfo"); + CFRelease(bundle); + return nil; + } + + __block NSDictionary *nowPlayingInfo = nil; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + MRMediaRemoteGetNowPlayingInfo( + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + ^(NSDictionary *information) { + nowPlayingInfo = [information copy]; + dispatch_semaphore_signal(semaphore); + }); + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + CFRelease(bundle); + return nowPlayingInfo; +} + +@end + +extern "C" { + +const char *getCurrentPlayingTitle() { + NSDictionary *metadata = [NowPlayingBridge currentPlayingMetadata]; + if (metadata == nil) { + return nullptr; + } + NSString *title = + [metadata objectForKey:@"kMRMediaRemoteNowPlayingInfoTitle"]; + if (title) { + return strdup([title UTF8String]); + } + return nullptr; +} + +const char *getCurrentPlayingArtist() { + NSDictionary *metadata = [NowPlayingBridge currentPlayingMetadata]; + if (metadata == nil) { + return nullptr; + } + NSString *artist = + [metadata objectForKey:@"kMRMediaRemoteNowPlayingInfoArtist"]; + if (artist) { + return strdup([artist UTF8String]); + } + return nullptr; +} +} diff --git a/subprojects/packagecache/quill-4.2.0.tar.gz b/subprojects/packagecache/quill-4.2.0.tar.gz deleted file mode 100644 index ebbf9a3..0000000 Binary files a/subprojects/packagecache/quill-4.2.0.tar.gz and /dev/null differ diff --git a/subprojects/packagecache/quill_4.2.0-1_patch.zip b/subprojects/packagecache/quill_4.2.0-1_patch.zip deleted file mode 100644 index ef6ccf2..0000000 Binary files a/subprojects/packagecache/quill_4.2.0-1_patch.zip and /dev/null differ diff --git a/subprojects/quill-4.2.0/.clang-format b/subprojects/quill-4.2.0/.clang-format deleted file mode 100644 index c7016b7..0000000 --- a/subprojects/quill-4.2.0/.clang-format +++ /dev/null @@ -1,45 +0,0 @@ -AccessModifierOffset: -2 -AlignConsecutiveDeclarations: None -AlignOperands: false -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: Never -AllowShortIfStatementsOnASingleLine: Never -AllowShortLoopsOnASingleLine: false -AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: Yes -BinPackParameters: true -BreakBeforeBinaryOperators: None -BreakBeforeBraces: Allman -BreakBeforeTernaryOperators: true -BreakConstructorInitializers: BeforeColon -ColumnLimit: 100 -CommentPragmas: '' -ConstructorInitializerAllOnOneLineOrOnePerLine: true -ConstructorInitializerIndentWidth: 2 -ContinuationIndentWidth: 2 -DisableFormat: false -ExperimentalAutoDetectBinPacking: false -IndentCaseLabels: false -IndentPPDirectives: BeforeHash -IndentWidth: 2 -IndentWrappedFunctionNames: false -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -PenaltyBreakBeforeFirstCallParameter: 1 -PenaltyBreakComment: 300 -PenaltyBreakString: 1000 -PenaltyBreakFirstLessLess: 120 -PenaltyExcessCharacter: 1 -PenaltyReturnTypeOnItsOwnLine: 1000 -PointerAlignment: Left -SpaceBeforeAssignmentOperators: true -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: false -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -Cpp11BracedListStyle: true -Standard: c++20 -TabWidth: 2 -UseTab: Never diff --git a/subprojects/quill-4.2.0/.codecov.yml b/subprojects/quill-4.2.0/.codecov.yml deleted file mode 100644 index 28b117d..0000000 --- a/subprojects/quill-4.2.0/.codecov.yml +++ /dev/null @@ -1,5 +0,0 @@ -ignore: - - "examples" - - "quill/include/quill/bundled" - - "quill/src/bundled" - - "quill/test" diff --git a/subprojects/quill-4.2.0/.github/workflows/coverage.yml b/subprojects/quill-4.2.0/.github/workflows/coverage.yml deleted file mode 100644 index baa4714..0000000 --- a/subprojects/quill-4.2.0/.github/workflows/coverage.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: coverage - -on: - push: - branches: - - master - paths-ignore: - - '**.md' - - 'docs/**' - -jobs: - build: - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@v4 - - - name: Configure - run: cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_STANDARD=17 -DQUILL_BUILD_TESTS=ON -DQUILL_CODE_COVERAGE=ON -DQUILL_BUILD_EXAMPLES=ON -DQUILL_VERBOSE_MAKEFILE=ON - - - name: Build - run: cmake --build build -j4 - - - name: Test - run: | - cd build - ctest --build-config Debug - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} - verbose: true diff --git a/subprojects/quill-4.2.0/.github/workflows/linux.yml b/subprojects/quill-4.2.0/.github/workflows/linux.yml deleted file mode 100644 index 859c30d..0000000 --- a/subprojects/quill-4.2.0/.github/workflows/linux.yml +++ /dev/null @@ -1,111 +0,0 @@ -name: linux - -on: - push: - branches: - - master - paths-ignore: - - '**.md' - - 'docs/**' - - pull_request: - branches: - - master - paths-ignore: - - '**.md' - - 'docs/**' - -jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - cxx: [ g++-8, g++-10 ] - build_type: [ Debug, Release ] - std: [ 17 ] - os: [ ubuntu-20.04 ] - with_tests: [ ON ] - - include: - # Build and with g++8 - - cxx: g++-8 - std: 17 - os: ubuntu-20.04 - with_tests: ON - install: sudo apt -o Acquire::Retries=5 install g++-8 - - # Build and test as shared library - - cxx: g++-10 - build_type: Release - std: 17 - os: ubuntu-20.04 - with_tests: ON - cmake_options: -DBUILD_SHARED_LIBS=ON -DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON - - # Builds with no exceptions - - cxx: g++-10 - build_type: Release - std: 17 - os: ubuntu-20.04 - with_tests: OFF - cmake_options: -DQUILL_NO_EXCEPTIONS=ON - - # Build and test with valgrind, sanitizers - - cxx: g++-10 - build_type: Release - std: 20 - os: ubuntu-20.04 - with_tests: ON - cmake_options: -DQUILL_USE_VALGRIND=ON - ctest_options: -T memcheck - install: sudo apt -o Acquire::Retries=5 install valgrind - - # Build and test sanitizers - - cxx: clang++-12 - build_type: Release - std: 20 - os: ubuntu-20.04 - with_tests: ON - cmake_options: -DQUILL_SANITIZE_ADDRESS=ON - - # Build and test sanitizers - - cxx: clang++-12 - build_type: Release - std: 20 - os: ubuntu-20.04 - with_tests: ON - cmake_options: -DQUILL_SANITIZE_THREAD=ON - - steps: - - uses: actions/checkout@v4 - - - name: Create Build Environment - run: | - sudo apt-get update - ${{matrix.install}} - cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - working-directory: ${{runner.workspace}}/build - env: - CXX: ${{matrix.cxx}} - CXXFLAGS: ${{matrix.cxxflags}} - run: | - cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.cmake_options}} \ - -DCMAKE_CXX_STANDARD=${{matrix.std}} -DQUILL_BUILD_TESTS=${{matrix.with_tests}} \ - -DQUILL_BUILD_EXAMPLES=ON -DQUILL_VERBOSE_MAKEFILE=ON $GITHUB_WORKSPACE - - - name: Build - working-directory: ${{runner.workspace}}/build - run: | - threads=`nproc` - cmake --build . --config ${{matrix.build_type}} --parallel $threads - - - name: Test - working-directory: ${{runner.workspace}}/build - run: | - threads=`nproc` - ctest --build-config ${{matrix.build_type}} ${{matrix.ctest_options}} --parallel $threads --output-on-failure - env: - CTEST_OUTPUT_ON_FAILURE: True \ No newline at end of file diff --git a/subprojects/quill-4.2.0/.github/workflows/macos.yml b/subprojects/quill-4.2.0/.github/workflows/macos.yml deleted file mode 100644 index 0a67fec..0000000 --- a/subprojects/quill-4.2.0/.github/workflows/macos.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: macos - -on: - push: - branches: - - master - paths-ignore: - - '**.md' - - 'docs/**' - - pull_request: - branches: - - master - paths-ignore: - - '**.md' - - 'docs/**' - -jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ macos-14 ] - build_type: [ Debug, Release ] - std: [ 17, 20 ] - - steps: - - uses: actions/checkout@v4 - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: | - cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ - -DCMAKE_CXX_STANDARD=${{matrix.std}} -DQUILL_BUILD_TESTS=ON \ - -DQUILL_BUILD_EXAMPLES=ON -DQUILL_VERBOSE_MAKEFILE=ON $GITHUB_WORKSPACE - - - name: Build - working-directory: ${{runner.workspace}}/build - run: | - threads=`sysctl -n hw.logicalcpu` - cmake --build . --config ${{matrix.build_type}} --parallel $threads - - - name: Test - working-directory: ${{runner.workspace}}/build - run: | - threads=`sysctl -n hw.logicalcpu` - ctest --build-config ${{matrix.build_type}} --parallel $threads --output-on-failure diff --git a/subprojects/quill-4.2.0/.github/workflows/windows.yml b/subprojects/quill-4.2.0/.github/workflows/windows.yml deleted file mode 100644 index e61e009..0000000 --- a/subprojects/quill-4.2.0/.github/workflows/windows.yml +++ /dev/null @@ -1,78 +0,0 @@ - -name: windows - -on: - push: - branches: - - master - paths-ignore: - - '**.md' - - 'docs/**' - - pull_request: - branches: - - master - paths-ignore: - - '**.md' - - 'docs/**' - -jobs: - build: - # windows-2016 and windows-2019 have MSVC 2017 and 2019 installed - # respectively: https://github.com/actions/virtual-environments. - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ windows-2019, windows-2022 ] - platform: [ x64 ] - build_type: [ Debug, Release ] - std: [ 17, 20 ] - with_tests: [ ON ] - - include: - # Builds with no exceptions - - os: windows-2019 - platform: x64 - build_type: Release - std: 17 - with_tests: "OFF" - cmake_options: -DQUILL_NO_EXCEPTIONS=ON - - # Builds for ARM - - os: windows-2019 - platform: ARM64 - build_type: Release - std: 17 - with_tests: "OFF" - - - os: windows-2019 - platform: ARM - build_type: Release - std: 17 - with_tests: "OFF" - - steps: - - uses: actions/checkout@v4 - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - shell: bash # Use a bash shell for $GITHUB_WORKSPACE. - working-directory: ${{runner.workspace}}/build - run: | - cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.cmake_options}} \ - -A ${{matrix.platform}} -DCMAKE_CXX_STANDARD=${{matrix.std}} -DQUILL_BUILD_TESTS=${{matrix.with_tests}} \ - -DQUILL_BUILD_EXAMPLES=ON -DQUILL_VERBOSE_MAKEFILE=ON $GITHUB_WORKSPACE - - - name: Build - working-directory: ${{runner.workspace}}/build - run: | - $threads = (Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors - cmake --build . --config ${{matrix.build_type}} --parallel $threads - - - name: Test - working-directory: ${{runner.workspace}}/build - run: | - $threads = (Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors - ctest --build-config ${{matrix.build_type}} --parallel $threads --output-on-failure diff --git a/subprojects/quill-4.2.0/.gitignore b/subprojects/quill-4.2.0/.gitignore deleted file mode 100644 index 1801866..0000000 --- a/subprojects/quill-4.2.0/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Project exclude paths -/cmake-build-debug/ -/.vs -/out/build/x64-Debug -/CMakeSettings.json -/out/build/x64-Release -/out/build/Mingw64-Debug -/out/build/x64-Debug-2 diff --git a/subprojects/quill-4.2.0/.meson-subproject-wrap-hash.txt b/subprojects/quill-4.2.0/.meson-subproject-wrap-hash.txt deleted file mode 100644 index bfd1e53..0000000 --- a/subprojects/quill-4.2.0/.meson-subproject-wrap-hash.txt +++ /dev/null @@ -1 +0,0 @@ -768ccd8048e2f53838c17ea6480236bb8d89fa785fb08f378539bfb0aa61ac1f diff --git a/subprojects/quill-4.2.0/.readthedocs.yaml b/subprojects/quill-4.2.0/.readthedocs.yaml deleted file mode 100644 index c1049bf..0000000 --- a/subprojects/quill-4.2.0/.readthedocs.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# .readthedocs.yaml -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required -version: 2 - -# Set the version of Python and other tools you might need -build: - os: ubuntu-22.04 - tools: - python: "3.11" - -# Build documentation in the docs/ directory with Sphinx -sphinx: - configuration: docs/conf.py - -# We recommend specifying your dependencies to enable reproducible builds: -# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -python: - install: - - requirements: docs/requirements.txt \ No newline at end of file diff --git a/subprojects/quill-4.2.0/CHANGELOG.md b/subprojects/quill-4.2.0/CHANGELOG.md deleted file mode 100644 index 1ae4dc2..0000000 --- a/subprojects/quill-4.2.0/CHANGELOG.md +++ /dev/null @@ -1,1384 +0,0 @@ -- [v4.2.0](#v420) -- [v4.1.0](#v410) -- [v4.0.0](#v400) -- [v3.9.0](#v390) -- [v3.8.0](#v380) -- [v3.7.0](#v370) -- [v3.6.0](#v360) -- [v3.5.1](#v351) -- [v3.5.0](#v350) -- [v3.4.1](#v341) -- [v3.4.0](#v340) -- [v3.3.1](#v331) -- [v3.3.0](#v330) -- [v3.2.0](#v320) -- [v3.1.0](#v310) -- [v3.0.2](#v302) -- [v3.0.1](#v301) -- [v3.0.0](#v300) -- [v2.9.2](#v292) -- [v2.9.1](#v291) -- [v2.9.0](#v290) -- [v2.8.0](#v280) -- [v2.7.0](#v270) -- [v2.6.0](#v260) -- [v2.5.1](#v251) -- [v2.5.0](#v250) -- [v2.4.2](#v242) -- [v2.4.1](#v241) -- [v2.4.0](#v240) -- [v2.3.4](#v234) -- [v2.3.3](#v233) -- [v2.3.2](#v232) -- [v2.3.1](#v231) -- [v2.3.0](#v230) -- [v2.2.0](#v220) -- [v2.1.0](#v210) -- [v2.0.2](#v202) -- [v2.0.1](#v201) -- [v2.0.0](#v200) -- [v1.7.3](#v173) -- [v1.7.2](#v172) -- [v1.7.1](#v171) -- [v1.7.0](#v170) -- [v1.6.3](#v163) -- [v1.6.2](#v162) -- [v1.6.1](#v161) -- [v1.6.0](#v160) -- [v1.5.2](#v152) -- [v1.5.1](#v151) -- [v1.5.0](#v150) -- [v1.4.1](#v141) -- [v1.4.0](#v140) -- [v1.3.3](#v133) -- [v1.3.2](#v132) -- [v1.3.1](#v131) -- [v1.3.0](#v130) -- [v1.2.3](#v123) -- [v1.2.2](#v122) -- [v1.2.1](#v121) -- [v1.2.0](#v120) -- [v1.1.0](#v110) -- [v1.0.0](#v100) - -## v4.2.0 - -- Fixed the compile-time exclusion of log levels. Renamed the `QUILL_COMPILE_OUT_LOG_LEVEL` preprocessor - flag to `QUILL_COMPILE_ACTIVE_LOG_LEVEL`. -- Fixed build error when `UnboundedDropping` queue is used. -- Fixed a bug introduced in `v4.1.0`, which resulted in messages being logged out of order when - the `transit_events_soft_limit` was reached. Additionally, this issue affected the behavior of `flush_log()`, - prematurely unblocking the thread before all messages were flushed. -- Fixed `-Wno-unused-parameter` and `-Wdocumentation` warnings. -- Improved backend worker `_exit()` functionality and reduced code duplication in other areas of the backend worker code. -- Added `signal_handler_timeout_seconds` parameter, which controls the timeout duration for the signal handler. Only - available on Linux platforms. -- Added `sleep_duration_ns` parameter to the `flush_log(...)` function. This parameter specifies the duration in - nanoseconds to sleep between retries between checks for the flush completion and when a blocking queue is used, - and it is full. The default sleep duration is 100 nanoseconds, but users can now customize this duration according to - their needs. If a zero sleep duration is passed, the thread might yield instead. -- Removed uses of `std::this_thread::sleep_for(...)`, `std::string`, `std::vector` in the signal handler when waiting for - the log to be flushed. - -## v4.1.0 - -- Following the transition from a compiled to a header-only library, the `target_compile_options` previously applied to - the compiled library were mistakenly propagated to all programs linking against the header-only library. - This issue is now fixed by removing those flags and explicitly adding them to tests and examples. As a result, - executable targets no longer inherit flags from the library. -- Removed unnecessary template specializations and merged their logic into the primary template - for `ArgSizeCalculator`, `Encoder`, and `Decoder` using if constexpr. -- Eliminated `` header dependency in the frontend -- Replaced `%(structured_keys)` with `%(named_args)` in the `PatternFormatter`. This change now appends the - entire key-value pair of named args to the message, not just the names. -- Relocated certain classes to the `detail` namespace -- Replaced `sprintf` with `snprintf` to fix macOS warning. -- Reviewed and removed gcc cold attribute from a few functions. -- Minor backend thread optimisations when logging c style strings or char arrays -- Improved backend thread variable and function names and fixed a bug for an edge case when the transit event hard limit - is reached - -## v4.0.0 - -This version represents a major revamp of the library, aiming to simplify and modernize it, resulting in the removal -of a few features. Please read through the changes carefully before upgrading, as it is not backwards compatible with -previous versions and some effort will be required to migrate. - -I understand that these changes may inconvenience some existing users. However, they have been made with good -intentions, aiming to improve and refine the logging library. This involved significant effort and dedication. - -Bug fixes and releases for `v3` will continue to be supported under the `v3.x.x` branch. - -#### Comparison - -- This version significantly improves compile times. Taking a look at some compiler profiling for a `Release` build with - clang 15, we can see the difference. Below are the two compiler flamegraphs for building the `recommended_usage` - example from the new version and the `wrapper_lib` example from the previous version. - -The below flamegraph shows the difference in included headers between the two versions - -| Version | Compiler FlameGraph | -|---------|:--------------------------------------------------------------------------------------------------------------------------------------:| -| v4.0.0 | ![quill_v4_compiler_profile.speedscope.png](https://github.com/odygrd/quill/blob/master/docs/quill_v4_compiler_profile.speedscope.png) | -| v3.8.0 | ![quill_v3_compiler_profile.speedscope.png](https://github.com/odygrd/quill/blob/master/docs/quill_v3_compiler_profile.speedscope.png) | - -A new compiler benchmark has been introduced. A Python script generates 2000 distinct log statements with various -arguments. You can find the -benchmark [here](https://github.com/odygrd/quill/blob/master/benchmarks/compile_time/compile_time_bench.cpp). -Compilation now takes only about 30 seconds, whereas the previous version required over 4 minutes. - -| Version | Compiler FlameGraph | -|---------|:------------------------------------------------------------------------------------------------------------------------------------:| -| v4.0.0 | ![quill_v4_compiler_bench.speedscope.png](https://github.com/odygrd/quill/blob/master/docs/quill_v4_compiler_bench.speedscope.png) | -| v3.8.0 | ![quill_v3_compiler_bench.speedscope.png](https://github.com/odygrd/quill/blob/master/docs/quill_v4_compiler_profile.speedscope.png) | - -- Minor increase in backend thread throughput compared to the previous version. - -| Version | Backend Throughput | -|---------|:----------------------------------------------------------------------------------:| -| v4.0.0 | 4.56 million msgs/sec average, total time elapsed: 876 ms for 4000000 log messages | -| v3.8.0 | 4.39 million msgs/sec average, total time elapsed: 910 ms for 4000000 log messages | - -- Significant boost in hot path latency when logging complex types such as `std::vector`. - The performance remains consistent when logging only primitive types or strings in both versions. Refer - [here](https://github.com/odygrd/quill?tab=readme-ov-file#performance) for updated and detailed benchmarks. - -#### Changes - -- **Improved compile times** - -The library has been restructured to minimize the number of required headers. Refactoring efforts have focused on -decoupling the frontend from the backend, resulting in reduced dependencies. Accessing the frontend logging functions -now does not demand inclusion of any backend logic components. - - "quill/Backend.h" - It can be included once to start the backend logging thread, typically in main.cpp - or in a wrapper library. - - "quill/Frontend.h"` - Used to create or obtain a `Logger*` or a `Sink`. It can be included in limited - files, since an obtained `Logger*` has pointer stability and can be passed around. - - "quill/Logger.h", "quill/LogMacros.h" - These two files are the only ones needed for logging and will have - to be included in every file that requires logging functionality. - -- **Backend formatting for user-defined and standard library types** - -One of the significant changes lies in the support for formatting both user-defined and standard library types. -Previously, the backend thread handled the formatting of these types sent by the frontend. It involved making a copy for -any object passed to the `LOG_` macros as an argument using the copy constructor of a complex type instead of directly -serializing the data to the SPSC queue. While this method facilitated logging copy-constructible user-defined types with -ease, it also posed numerous challenges for asynchronous logging: - -- Error-Prone Asynchronous Logging: Copying and formatting user-defined types on the backend thread in an - asynchronous logging setup could lead to errors. Previous versions attempted to address this issue with type - trait checks, which incurred additional template instantiations and compile times. -- Uncertainty in Type Verification: It is challenging to confidently verify types, as some trivially copiable - types, such as `struct A { int* m; }`, could still lead to issues due to potential modifications by the user - before formatting. -- Hidden Performance Penalties: Logging non-trivially copiable types could introduce hidden cache coherence - performance penalties due to memory allocations and deallocations across threads. For instance, - consider `std::vector` passed as a log argument. The vector is emplaced into the SPSC queue by the frontend, - invoking the copy constructor dynamically allocating memory as the only members copied to SPSC queue - are `size`, `capacity`, and `data*`. The backend thread reads the object, formats it, and then invokes the destructor, - which in turn synchronizes the - freed memory back to the frontend. - -Additionally, after years of professional use and based on experience, it has been observed that user-defined types -are often logged during program initialization, with fewer occurrences on the hot path where mostly built-in types are -logged. In such scenarios, the overhead of string formatting on the frontend during initialization is not an issue. - -In this new version, the use of the copy constructor for emplacing objects in the queue has been abandoned. Only POD -types are copied, ensuring that only raw, tangible data is handled without any underlying pointers pointing to other -memory locations. The only exception to this are the pointers to `Metadata`, `LoggerBase` and `DecodeFunction` -that are passed internally for each log message. Log arguments sent from the frontend must undergo -serialization beforehand. While this approach resolves the above issues, it does introduce more complexity when -dealing with user-defined or standard library types. - -Built-in types and strings are logged by default, with the formatting being offloaded to the backend. Additionally, -there is built-in support for most standard library types, which can also be directly passed to the logger by -including the relevant header from `quill/std`. - -The recommendation for user-defined types is to format them into strings before passing them to the `LOG_` macros using -your preferred method. You can find an example of -this [here](https://github.com/odygrd/quill/blob/master/examples/user_defined_types_logging.cpp). - -It's also possible to extend the library by providing template specializations to serialize the user-defined types -and offload their formatting to the backend. However, this approach should only be pursued if you cannot tolerate the -formatting overhead in that part of your program. For further guidance, refer -to [this example](https://github.com/odygrd/quill/blob/master/examples/advanced/advanced.cpp). - -- **Header-Only library** - -The library is now header-only. This change simplifies exporting the library as a C++ module in the future. See -[here](https://github.com/odygrd/quill/blob/master/examples/recommended_usage/recommended_usage.cpp) on how to build a -wrapper static library which includes the backend and will minimise the compile times. - -- **Preprocessor flags moved to template parameters** - -Most preprocessor flags have been moved to template parameters, with only a few remaining as `CMake` options. This -change simplifies exporting the library as a C++ module in the future. - -- **Renamed Handlers to Sinks** - -To enhance clarity, handlers have been renamed to sinks. - -- **PatternFormatter moved to Logger** - -The `PatternFormatter` has been relocated from `Sink` to `Logger`, enabling a logger object to log in a specific -format. This allows for different formats within the same output file, a feature not previously possible. - -- **Split Configuration** - -The configuration settings have been divided into `FrontendOptions` and `BackendOptions`. - -- **Refactoring of backend classes** - -`MacroMetadata` and many backend classes have undergone refactoring, resulting in reduced memory requirements. - -- **Improved wide strings handling on Windows** - -The library now offers significant performance enhancements for handling wide strings on Windows platforms. -It's important to note that only wide strings containing ASCII characters are supported. Previously, wide strings were -converted to narrow strings at the frontend, impacting the critical path of the application. -With this update, the underlying wide char buffer is copied and the conversion to UTF-8 encoding is deferred to -the backend logging thread. Additionally, this update adds support for logging STL containers consisting of -wide strings - -- **Default logger removal** - -The default logger, along with the configuration inheritance feature during logger creation, has been removed. Now, when -creating a new logger instance, configurations such as the `Sink` and log pattern format must be explicitly specified -each time. This simplifies the codebase. - -- **Global logger removal** - -The static global logger* variable that was initialised during `quill::start()` used to obtain the default logger has -been removed. It is possible to add this on the user side. If you require a global logger you can have a look -at [this example](https://github.com/odygrd/quill/blob/master/examples/recommended_usage/recommended_usage.cpp) - -- **Removal of printf style formatting support** - -The support for `printf` style formatting has been removed due to its limited usage and the increased complexity. Users -requiring this feature should stay on `v3.x.x` versions to maintain compatibility. - -- **Removal of external libfmt usage** - -The option to build the library with external `libfmt` has been removed. It becomes difficult to maintain and backwards -support previous versions of `libfmt`. Instead, `libfmt` is now an internal component of the library, accessible under -the namespace `fmtquill`. You can use the bundled version of `fmtquill` by including the necessary headers from -`quill/bundled/fmt`. Alternatively, you have the freedom to integrate your own version. Since `libfmt` is encapsulated -within a distinct namespace, there are no conflicts even if you link your own `libfmt` alongside the logging library. - -#### Migration Guidance - -- Revise include files to accommodate the removal of `Quill.h` -- Update the code that starts the backend thread and the logger/sink creation. You can refer to any of the - updated examples, such as [this one](https://github.com/odygrd/quill/blob/master/examples/file_logging.cpp) -- When logging statements involving user-defined types, make sure these types are formatted into strings using - your preferred method. Refer to - [this link](https://github.com/odygrd/quill/blob/master/examples/user_defined_types_logging.cpp) for guidance. - Alternatively, if you prefer delaying the conversion to strings until the backend thread and only passing a - binary copy of the user-defined type on the hot path, you can provide the necessary class template - specializations for each user-defined type. See an example - [here](https://github.com/odygrd/quill/blob/master/examples/advanced/user_quill_codec.h) - -## v3.9.0 - -- Fix bug in `ConsoleHandler` when dynamic log level is used ([#421](https://github.com/odygrd/quill/pull/421)) -- Fix bug in `TransitEvent` when dynamic log level is used ([#427](https://github.com/odygrd/quill/pull/427)) -- Fix build error for Intel compiler classic ([#414](https://github.com/odygrd/quill/pull/414)) -- Added `JsonConsoleHandler` ([#413](https://github.com/odygrd/quill/issues/413)) -- Fix fold expression argument evaluation. This bug could occur when logging c style strings - -## v3.8.0 - -- Refactored `MacroMetadata` class to reduce its size. -- Renamed some attributes in the `PatternFormatter` class for clarity. If you are using a custom format pattern, update - the attribute names in your code to match the new names. -- Improved accuracy of log statement timestamps. Previously, the timestamp was taken after checking if the queue had - enough space to push the message, which could make it less accurate. Additionally, in the case of a blocking queue, - the timestamp could be later in time. Now, the timestamp is taken and stored right after the log statement is issued, - before checking for the queue size. -- Reduced template instantiations during logging operations on the hot path. Fold expressions are now used for - encoding/decoding arguments, minimizing template recursion overhead. -- Removed compile-time format checks due to their significant impact on template instantiations, especially considering - that only a few cases are invalid. For instance, while `fmt::format("{}", 1, 2)` is considered valid, - `fmt::format("{} {}", 1)` is deemed invalid. In cases where an invalid format string is detected, the backend worker - thread catches the generated exception and logs an error. -- The throughput of the backend worker thread has been improved by approximately 5%. This enhancement is reflected in - the new throughput value of 4.20 million msgs/sec, compared to the previous throughput of 3.98 million msgs/sec. -- Detect `tmux` as colour terminal. ([#410](https://github.com/odygrd/quill/issues/410)) - -## v3.7.0 - -- Fixed crash triggered by insufficient space in the queue upon invocation - of ``flush()``. ([#398](https://github.com/odygrd/quill/pull/398)) -- Fixed windows clang-cl build error. ([#400](https://github.com/odygrd/quill/pull/400)) -- Fixed compilation errors encountered on FreeBSD and extended ``get_thread_id()`` support to various other BSD - operating systems. ([#401](https://github.com/odygrd/quill/pull/401)) -- Fix open_file in the FileHandler to also create the parent path before opening the - file. ([#395](https://github.com/odygrd/quill/issues/395)) -- Enhance logic for backend thread's flush() invocation; it now triggers only if the handler has previously written - data. ([#395](https://github.com/odygrd/quill/issues/395)) -- Address an uncaught exception in the backend thread that could occur when a user manually removes the log file from - the terminal while the logger is running. ([#395](https://github.com/odygrd/quill/issues/395)) -- Ensure that after a logger is removed, there are no subsequent calls to the Handler's flush() or run_loop(), provided - the Handler is not shared. ([#395](https://github.com/odygrd/quill/issues/395)) -- Ignore the virtual destructor missing warning for the `CustomTags` - class. ([#402](https://github.com/odygrd/quill/pull/402)) -- Update bundled `libfmt` to `v10.2.1` - -## v3.6.0 - -- Fixed `QUILL_LOGGER_CALL_NOFN_LIMIT` macros. ([#381](https://github.com/odygrd/quill/pull/381)) -- Resolved a bug that caused reading destructed arguments when structured logging format was used. -- Modified member access from `private` to `protected` in `ConsoleHandler` for potential inheritance purposes. -- Eliminated redundant whitespaces within `JsonFileHandler`. -- Fixed `JsonFileHandler` to notify the file event notifier before log message writes. -- Implemented a new attribute called `%(structured_keys)` within the `PatternFormatter` to facilitate the inclusion - of keys in messages when using structured log formatting. This addition is useful for instances where logging occurs - in both JSON and regular log formats, enabling the display of keys within the regular log-formatted messages. - See - updated [example_json_structured_log.cpp](https://github.com/odygrd/quill/blob/master/examples/example_json_structured_log.cpp) - -## v3.5.1 - -- Resolved issue with accessing the `name()` method within the `Logger` - class. ([#378](https://github.com/odygrd/quill/pull/378)) -- Fixed a compilation error in `SignalHandler` specific to Windows when `QUILL_DISABLE_NON_PREFIXED_MACROS` is - defined. ([#380](https://github.com/odygrd/quill/pull/380)) - -## v3.5.0 - -- Fixed `LOG_TRACE_CFORMAT` macros. -- Added support for compile-time custom tags in `quill::MacroMetadata` to enhance message filtering and incorporate - static information. New log macros suffixed with `_WITH_TAGS` introduced for this feature. - Additionally, `%(custom_tags)` parameter added - to `PatternFormatter`. ([#349](https://github.com/odygrd/quill/issues/349)) - See [example_custom_tags.cpp](https://github.com/odygrd/quill/blob/master/examples/example_custom_tags.cpp) -- Improvements to reduce compilation time - -## v3.4.1 - -- Reduce backend worker unnecessary allocation. ([#368](https://github.com/odygrd/quill/issues/368)) -- Adjusted handling for empty `std::string_view` instances, addressing an issue where logging empty strings triggered an - unintended `memcpy` with zero size and a nullptr, leading to address sanitizer warnings. -- Fix clang build error when using `-DQUILL_NO_EXCEPTIONS:BOOL=ON`. ([#357](https://github.com/odygrd/quill/issues/357)) - -## v3.4.0 - -- Resolved `bad_variant_access` error occurring when using Quill as a pre-compiled library with a distinct queue - type. ([#276](https://github.com/odygrd/quill/pull/276)) - -- Resolved a bug in `RotatingFileHandler` associated with logfiles located outside the working directory, - specifically when used with open_mode `a`. ([#340](https://github.com/odygrd/quill/pull/340)) - -- Added a `name()` method to the Logger class which provides the logger - name. ([#345](https://github.com/odygrd/quill/pull/345)) - -- Fixed library and include paths in the pkg-config configuration. ([#352](https://github.com/odygrd/quill/pull/352)) - -- Move `get_root_logger()` definition from cpp to the header file ([#348](https://github.com/odygrd/quill/issues/348)) - -- Introduced support for logging character arrays. You can now log character arrays, even when they don't contain a - null-terminating character. - Additionally, character arrays with null characters in the middle are supported, and the logger will - capture the content until the null character is encountered. ([#353](https://github.com/odygrd/quill/pull/353)) - - For example - - ```c++ - union - { - char no_0[2]; - char mid_0[6]{'1', '2', '3', '4', '\0', 6}; - } char_arrays; - - // only output "12" even if there's no '\0' at the end - LOG_INFO(logger, R"(This is a log info example for char array without '\0': {})", char_arrays.no_0); - - // output "1234" until the '\0' - LOG_INFO(logger, R"(This is a log info example for char array with '\0' in middle: {})", - char_arrays.mid_0); - ``` - -- Minor improvements in the bounded queue and throughput. ([#362](https://github.com/odygrd/quill/pull/362)) - - Previous: 2.21 million msgs/sec average, total time elapsed: 1809 ms for 4000000 log messages. - - New: 2.24 million msgs/sec average, total time elapsed: 1787 ms for 4000000 log messages. - -- Disable `fmt::join(data, "")` at compile time. ([#356](https://github.com/odygrd/quill/issues/356)) -- Fix compile error in Apple Clang 12. ([#360](https://github.com/odygrd/quill/issues/360)) -- Add guards for redefined preprocessor variables. -- Fix `uint64_t` to `time_t` implicit conversion error in Clang 18. -- Update bundled `libfmt` to `v10.1.1` - -## v3.3.1 - -- Fixed `RotatingFileHandler` to prevent accidental removal of non-log files when using open mode `w` - and `set_remove_old_files(true)` - -## v3.3.0 - -- Added a `quill::get_handler(handler_name)` function that allows easy lookup of an existing `Handler` by name. This - function proves helpful when you want to retrieve a handler and pass it to a new logger. - -- Fix build failure of Intel Compiler Classic. ([#332](https://github.com/odygrd/quill/pull/332)) - -- Introduced `QUILL_BLOCKING_QUEUE_RETRY_INTERVAL_NS` option for user-configurable retry interval in the blocking queue. - Default value is 800 nanoseconds. ([#330](https://github.com/odygrd/quill/pull/330)) - -- Improved backend thread handling. Now verifies that all producer SPSC queues are empty before entering `sleep`. - -- Fixed a race condition and potential crash in `quill::remove_logger(Logger*)` when called without - prior `quill::flush()`. - -- Added protection to prevent removal of the root logger with `quill::remove_logger(Logger*)`. - -- Improved exception handling on the backend thread when calling `fmt::format()`. - - While compile-time checks ensure that the format string and arguments match, runtime errors can still occur. - Previously, such exceptions would affect and drop subsequent log records. Now, exceptions are caught and logged - in the log file and reported via the backend thread notification handler (default is `cerr`). - - For example, if a dynamic precision is used (`LOG_INFO(logger, "Support for floats {:.{}f}", 1.23456, 3.321312)`), - the log file will show the following error message: - - ``` - LOG_INFO root [format: "Support for floats {:.{}f}", error: "precision is not integer"] - ``` - - Additionally, an error message will be printed to `cerr` - - ``` - Quill ERROR: [format: "Support for floats {:.{}f}", error: "precision is not integer"] - ``` - -- Fixed a bug in timestamp formatting that occasionally displayed an hour component of 0 as - 24. ([#329](https://github.com/odygrd/quill/pull/329)) - -- Added support for specifying a runtime log level, allowing dynamic log level configuration at runtime. - The new runtime log level feature provides flexibility when needed, with a minor overhead cost. - It is recommended to continue using the existing static log level macros for optimal - performance. ([#321](https://github.com/odygrd/quill/pull/321)) - - For example - - ```c++ - std::array const runtime_log_levels = {quill::LogLevel::Debug, - quill::LogLevel::Info, - quill::LogLevel::Warning, - quill::LogLevel::Error}; - - for (auto const& log_level : runtime_log_levels) - { - LOG_DYNAMIC(logger, log_level, "Runtime {} {}", "log", "level"); - } - ``` - -- Added support for printf-style formatting with `_CFORMAT` macros. These macros use the `printf` format string syntax, - simplifying the migration of legacy codebases using `printf` statements. - - For example - - ```c++ - std::array arr = {1, 2, 3, 4}; - LOG_INFO(logger, "This is a log info example using fmt format {}", arr); - - LOG_INFO_CFORMAT(logger, "printf style %s supported %d %f", "also", 5, 2.32); - ``` - -- Added a `metadata()` member function to the `TransitEvent` class. It provides access to the `Metadata` object - associated with the log record, simplifying syntax for retrieving log record metadata in custom Handlers. - - For example - - ```c++ - void CustomHandler::write(fmt_buffer_t const& formatted_log_message, quill::TransitEvent const& log_event) - { - MacroMetadata const macro_metadata = log_event.metadata(); - } - ``` - -- Simplified file handler configuration. Now, instead of passing multiple arguments to the constructor, - you only need to provide a single `FileHandlerConfig` object. This change makes creating file handlers objects - much easier and more flexible. - - For example - - ```c++ - quill::FileHandlerConfig file_handler_cfg; - file_handler_cfg.set_open_mode('w'); - file_handler_cfg.set_append_to_filename(quill::FilenameAppend::StartDateTime); - - std::shared_ptr file_handler = quill::file_handler("application.log", file_handler_cfg); - quill::Logger* logger_foo = quill::create_logger("my_logger", std::move(file_handler)); - - LOG_INFO(my_logger, "Hello from {}", "application"); - ``` - -- Combined the functionalities of `RotatingFileHandler` (rotating based on file size) and `TimeRotatingFileHandler` - (rotating on a time interval) into a single, more versatile `RotatingFileHandler`. Users can now conveniently rotate - logs based on both file size and time intervals simultaneously. The updated `RotatingFileHandler` offers a variety of - customization options for improved flexibility. For more information on available configurations, - refer to the `RotatingFileHandlerConfig` documentation. - - For example - - ```c++ - // Create a rotating file handler which rotates daily at 18:30 or when the file size reaches 2GB - std::shared_ptr file_handler = - quill::rotating_file_handler(filename, - []() - { - quill::RotatingFileHandlerConfig cfg; - cfg.set_rotation_time_daily("18:30"); - cfg.set_rotation_max_file_size(2'000'000'000); - return cfg; - }()); - - // Create a logger using this handler - quill::Logger* logger_bar = quill::create_logger("daily_logger", std::move(file_handler)); - ``` - -- Improved compatibility with older versions of external `libfmt`. Quill now compiles for all versions - of `libfmt >= 8.0.0`. - -## v3.2.0 - -- Addition of std::is_trivially_copyable to default copy loggable - types. ([#318](https://github.com/odygrd/quill/pull/318)) -- By default, the static library now builds with '-fPIC' to generate position-independent code. - To disable this feature, you can use the CMake option 'QUILL_DISABLE_POSITION_INDEPENDENT_CODE'. -- The `LOG__LIMIT` macros now support using `std::chrono` duration types for specifying the log interval. - Instead of providing a raw number, you can use: - - ```c++ - LOG_INFO_LIMIT(std::chrono::milliseconds {100} , quill::get_logger(), "log message"); - ``` - -## v3.1.0 - -- It is now possible to set a minimum logging interval for specific logs. For example: - - ```c++ - for (uint64_t i = 0; i < 10; ++i) - { - LOG_INFO_LIMIT(2000, default_logger, "log in a loop with limit 1 message every 2000 micros for i {}", i); - std::this_thread::sleep_for(std::chrono::microseconds{1000}); - } - ``` - -- `quill::utility::to_string()` now uses `fmt::to_string()` - -- Quill now utilizes a custom namespace (`fmtquill`) for the bundled fmt library. This enables smooth integration with - your own external fmt library, even if it's a different version. - -## v3.0.2 - -- Add missing header on clang when `QUILL_X86ARCH` is defined. - -## v3.0.1 - -- Enhanced the reported message for reallocation of the unbounded queue to include the thread id. - -## v3.0.0 - -- The previous unbounded queue constantly reallocated memory, risking system memory exhaustion, especially when handling - intensive logging from multiple threads. Starting from `v3.0.0`, the default behavior has been improved to limit - the queue capacity to 2 GB. When this limit is reached, the queue blocks the hot thread instead of further - reallocation. - To modify the default behavior, there is no need to recompile the `quill` library. Recompile your application - with one of the following header-only flags. - - ```shell - # Previous behavior in v2.*.*: Reallocates new queues indefinitely when max capacity is reached - -DCMAKE_CXX_FLAGS:STRING="-DQUILL_USE_UNBOUNDED_NO_MAX_LIMIT_QUEUE" - - # Default behavior in v3.*.*: Starts small, reallocates up to 2GB, then hot thread blocks - -DCMAKE_CXX_FLAGS:STRING="-DQUILL_USE_UNBOUNDED_BLOCKING_QUEUE" - - # Starts small, reallocates up to 2GB, then hot thread drops log messages - -DCMAKE_CXX_FLAGS:STRING="-DQUILL_USE_UNBOUNDED_DROPPING_QUEUE" - - # Fixed queue size, no reallocations, hot thread drops log messages - -DCMAKE_CXX_FLAGS:STRING="-DQUILL_USE_BOUNDED_QUEUE" - - # Fixed queue size, no reallocations, hot thread blocks - -DCMAKE_CXX_FLAGS:STRING="-DQUILL_USE_BOUNDED_BLOCKING_QUEUE" - ``` - -- Added support for huge pages on Linux. Enabling this feature allows bounded or unbounded queues to utilize huge pages, - resulting in optimized memory allocation. - - ```c++ - quill::Config cfg; - cfg.enable_huge_pages_hot_path = true; - - quill::configure(cfg); - quill::start(); - ``` - -- Added support for logging `std::optional`, which is also now supported in `libfmt` `v10.0.0`. - - ```c++ - LOG_INFO(default_logger, "some optionals [{}, {}]", std::optional{}, - std::optional{"hello"}); - ``` - -- Introduced a new function `run_loop` in the `Handler` base class, which allows users to override and execute periodic - tasks. This enhancement provides users with the flexibility to perform various actions at regular intervals, - such as batch committing data to a database. -- In scenarios where a hot thread is blocked and unable to push messages to the queue in blocking mode, this situation - will now be reported through the `backend_thread_notifications_handler` to the standard error stream `cerr`. - -## v2.9.2 - -- Fix increased compile times due to `x86intrin` headers. ([#298](https://github.com/odygrd/quill/pull/298)) -- Fix compile error when using `QUILL_X86ARCH` on windows. -- Fix bugs when quill is build as a shared library on windows. ([#302](https://github.com/odygrd/quill/pull/302)) - -## v2.9.1 - -- Removed `CMAKE_INSTALL_RPATH` from cmake. ([#284](https://github.com/odygrd/quill/pull/284)) -- Fix compile warning on Apple M1. ([#291](https://github.com/odygrd/quill/pull/291)) -- Update bundled `libfmt` to `v10.0.0` -- Fix for `CMAKE_MODULE_PATH` ([#295](https://github.com/odygrd/quill/pull/295)) -- Fixed a bug in `TimeRotatingFileHandler` when `quill::FilenameAppend::None` is - used. ([#296](https://github.com/odygrd/quill/pull/296)) -- Fixed `TimeRotatingFileHandler` and `RotatingFileHandler` to work when `/dev/null` is used as a - filename ([#297](https://github.com/odygrd/quill/pull/297)) -- Added `NullHandler` that can be used to discard the logs. For example: - - ```c++ - int main() - { - quill::start(); - - std::shared_ptr file_handler = - quill::null_handler(); - - quill::Logger* logger_bar = quill::create_logger("nullhandler", std::move(file_handler)); - - for (uint32_t i = 0; i < 150; ++i) - { - LOG_INFO(logger_bar, "Hello"); - } - ``` - -## v2.9.0 - -**Fixes** - -- Fixed a bug in TimeRotatingFileHandler. ([#287](https://github.com/odygrd/quill/pull/287)) - -**Improvements** - -- Renamed `backend_thread_error_handler` to `backend_thread_notifications_handler` in `Config.h`. Previously this - handler was used only to report errors from the backend worker thread to the user. This callback will also now report - info messages to the user. -- Report unbounded spsc queue reallocation via - the `backend_thread_notifications_handler`. ([#286](https://github.com/odygrd/quill/pull/286)) -- Report bounded spsc queue dropped messages via the `backend_thread_notifications_handler`. - -## v2.8.0 - -**Breaking Changes** -(see `improvements` section for more details) - -- If you were previously compiling with `-DQUILL_USE_BOUNDED_QUEUE` or `QUILL_X86ARCH` you should now pass the - flag to you target as it is not propagated by CMake anymore. -- There is a change in the API in `Quill.h` instead of `quill::Handler*` you should now use - `std::shared_ptr< quill::Handler >` and also move it to the created logger. - -**Improvements** - -- Add `append_to_filename` parameter when creating `quill::time_rotating_file_handler` - and `quill::rotating_file_handler` -- Fix `Handlers` failing to find the file when the working directory of the application is changed in - runtime. ([#247](https://github.com/odygrd/quill/pull/247)) -- When the given output directory of a log file passed to a `Handler` does not exist, it will now get automatically - created. -- Support Windows 10 LTSB 2016, 1607 and Server 2016. ([#251](https://github.com/odygrd/quill/pull/251)) -- Add back `backend_thread_sleep_duration` in `Config.h` ([#256](https://github.com/odygrd/quill/pull/256)) -- For `quill::rotating_file_handler(...)` and `quill::time_rotating_file_handler(...)` the `backup_count` argument is - now default to `std::numeric_limits::max()` -- When the logging file is deleted from the command line while the logger is still using it, then a new file will be - reopened for writing. -- Added `quill::Clock` which enables taking and converting TSC timestamps to system clock timestamps. - When `TimestampClockType::Tsc` is used as the default clock type in `Config.h` this class - can also be used to generate timestamps that are in sync with the timestamps in the log - file. ([#264](https://github.com/odygrd/quill/pull/264)) -- Both `Unbounded` and `Bounded` queue modes can now be used without having to recompile `quill` library. This is still - not a runtime option, you still need to recompile your target and pass `QUILL_USE_BOUNDED_QUEUE` as a flag. - See [example_bounded_queue_message_dropping.cpp](https://github.com/odygrd/quill/blob/master/examples/example_bounded_queue_message_dropping.cpp) -- Added `QUILL_USE_BOUNDED_BLOCKING_QUEUE` option that makes possible to use a bounded queue which blocks the hot - thread rather than dropping messages ([#270](https://github.com/odygrd/quill/pull/270)) - See [example_bounded_queue_blocking.cpp](https://github.com/odygrd/quill/blob/master/examples/example_bounded_queue_blocking.cpp) -- Renamed `backend_thread_max_transit_events` to `backend_thread_transit_events_soft_limit` in - Config.h ([#270](https://github.com/odygrd/quill/pull/270)) -- Added `backend_thread_transit_events_hard_limit` in Config.h ([#270](https://github.com/odygrd/quill/pull/270)) -- Added `backend_thread_use_transit_buffer` in Config.h ([#270](https://github.com/odygrd/quill/pull/270)) -- CMake: `QUILL_X86ARCH` and `QUILL_USE_BOUNDED_QUEUE` options have been removed. The users can decide on enabling these - options on their side and quill doesn't need to be recompiled as a library. For example : - ```cmake - target_compile_definitions( PUBLIC QUILL_X86ARCH QUILL_USE_BOUNDED_QUEUE) - ``` -- Added `quill::remove_logger(Logger* logger)` in `Quill.h`. This makes it possible to remove a logger in a thread safe - way. When a logger is removed any associated `FileHandlers` with that logger will also be removed and the files will - also be closed as long as they are not being used by another logger. The logger is asynchronously removed by the - logging - thread after all the messages are written. To achieve this the API had to change to return a - `std::shared_ptr< quill::Handler >` instead of `quill::Handler*`. See - [example_file_callbacks.cpp](https://github.com/odygrd/quill/blob/master/examples/example_file_callbacks.cpp) -- Added `quill::wake_up_logging_thread()` in `Quill.h`. This thread safe function can be used to wake up the backend - logging thread on demand. ([#280](https://github.com/odygrd/quill/pull/280)) -- Round up queue capacity to the nearest power of 2. ([#282](https://github.com/odygrd/quill/pull/282)) - -## v2.7.0 - -**Fixes** - -- Remove references to build directory path from the compiled library's - symbols. ([#221](https://github.com/odygrd/quill/pull/221)) -- Fix when compiled as shared library with hidden visibility. ([#222](https://github.com/odygrd/quill/pull/222)) -- Fix equal timestamp log messages appearing out of order. ([#223](https://github.com/odygrd/quill/pull/223)) -- Reduce padding in some structs. -- Fix 'rename_file' throwing an exception while being marked - as `noexcept`. ([#230](https://github.com/odygrd/quill/pull/230)) -- Fix crash with `std::bad_alloc` and compiler warnings in - gcc `7.3.1`. ([#235](https://github.com/odygrd/quill/pull/235)) -- The additional compiler definitions will now be propagated to the parent targets when enabling options in - CMake. ([#235](https://github.com/odygrd/quill/pull/235)) - -**Improvements** - -- Improved performance and throughput of the backend logging thread by approximately ~25% -- Add missing `quill::json_file_handler(...)` that creates a `JsonFileHandler` in `Quill.h`. -- Simplified and refactored the logic in `BoundedQueue`. -- Added the option `do_fsync` which also calls `fsync()` during the handler flush to all file handlers. -- Replace `backend_thread_sleep_duration` with `backend_thread_yield` in `Config.h` -- Remove trailing spaces in log levels strings. ([#237](https://github.com/odygrd/quill/pull/237)) -- The default log pattern has changed - to `"%(ascii_time) [%(thread)] %(fileline:<28) LOG_%(level_name:<9) %(logger_name:<12) %(message)")` -- Added file event notifiers, to get callbacks from quill before/after log file has been opened or - closed. ([#193](https://github.com/odygrd/quill/pull/193)) - This is useful for cleanup procedures or for adding something to the start/end of the log files. - for example - - ```c++ - int main() - { - quill::start(); - - quill::FileEventNotifier fen; - - fen.before_open = [](quill::fs::path const& filename) - { std::cout << "before opening " << filename << std::endl; }; - - fen.after_open = [](quill::fs::path const& filename, FILE* f) - { std::cout << "after opening " << filename << std::endl; }; - - fen.before_close = [](quill::fs::path const& filename, FILE* f) - { std::cout << "before closing " << filename << std::endl; }; - - fen.after_close = [](quill::fs::path const& filename) - { std::cout << "after closing " << filename << std::endl; }; - - quill::Handler* file_handler = - quill::file_handler("myfile.log", "w", quill::FilenameAppend::None, std::move(fen)); - - quill::Logger* mylogger = quill::create_logger("mylogger", file_handler); - - LOG_INFO(mylogger, "Hello world"); - } - ``` - -- Added `QUILL_X86ARCH` in `Tweakme.h`. When enabled it will attempt to minimize the cache pollution on x86 cpus that - support the instructions `_mm_prefetch `, `_mm_clflush` and `_mm_clflushopt`. - - To compile when this flag is enabled you should also pass `-march` to the compiler which is required, - you can set this to your oldest cpu architecture among your systems. - - To enable this option, `DQUILL_X86ARCH` must always be defined in quill library and also in your executable, - for example - - ```shell - cmake -DCMAKE_CXX_FLAGS:STRING="-DQUILL_X86ARCH -march=native" - ``` - -- Added `quill:get_root_logger()` which gives quick access to the root logger object and can be used directly in the hot - path. - This gives applications that only wish to use the root logger the convenience of not having to store and - pass `Logger*` objects anymore. - for example quill existing log macros can be overwritten to not require a `Logger*` anymore - - ```c++ - #define MY_LOG_INFO(fmt, ...) QUILL_LOG_INFO(quill::get_root_logger(), fmt, ##__VA_ARGS__) - `````` - -- Added `QUILL_ROOT_LOGGER_ONLY` in `Tweakme.h`. Define ths if you only plan to use the single `root` logger object, - When this is defined it will replace the LOG_ macros with the equivalent LOG_ macros but without the need of - passing `Logger*` objects anymore. - for example - - ```c++ - #define QUILL_ROOT_LOGGER_ONLY - #include "quill/Quill.h" - - int main() - { - quill::start(); - - // because we defined QUILL_ROOT_LOGGER_ONLY we do not have to pass a logger* anymore, the root logger is always used - LOG_INFO("Hello {}", "world"); - LOG_ERROR("This is a log error example {}", 7); - } - ``` - -## v2.6.0 - -**Fixes** - -- Fix filepath on Windows when MinGW is used. ([#212](https://github.com/odygrd/quill/pull/212)) - -**Improvements** - -- Removed the creation of `static Metadata` objects during initialisation time. -- `#define QUILL_QUEUE_CAPACITY` has been removed. -- Added Config option `default_queue_capacity` that can be used to specify the initial capacity of the queue. -- When Unbounded queue is used the newly allocated queue will now have enough space to fit any - object. ([#215](https://github.com/odygrd/quill/pull/215)) - -## v2.5.1 - -**Improvements** - -- Reduced the allocations performed by the backend worker thread as the same objects are now being reused rather than - destroyed. - -**Summary of changes since v2.3.2** - -In version `2.3.2` when multiple threads performed heavy logging, the backend logging thread incorrectly gave -priority to the logs of the same threads. That made logs from the remaining threads to appear much later or sometimes -never in the log files. - -There was a series of fixes and releases to address this. - -Below is the summary of the changes from `v2.3.2` - -- Previously when multiple threads were logging, the backend logging thread would first try to read the log messages of - the same thread until its queue was completely empty before reading the log messages of the next thread. - When one of the threads was logging a lot, it could result in only displaying the log of that thread, hiding the - logs of the other threads. This has now been fixed and all log messages from all threads are read fairly. - -- Optimise the backend logging thread to read all log messages from each queue. Ensure all queues - from all active threads are fairly read. - -- `fmt::basic_memory_buffer` buffer stack size has been reduced. The backend thread shows better performance with - a reduced stack size. This also reduces the risk of a stack overflow when too many log messages are cached.lllllllllll - -- Reduced the allocations performed by the backend worker thread as the same objects are now being reused rather than - destroyed. - -- Added a config option `backend_thread_strict_log_timestamp_order`. This option enables an extra timestamp - check on the backend logging thread when each message is popped from the queues. It prevents a rare - situation where log messages from different threads could appear in the log file in the wrong order. This flag - is now enabled by default. - -- Added a config option `backend_thread_empty_all_queues_before_exit`. This option makes the backend logging thread - to wait until all the queues are empty before exiting. This ensures no log messages are lost when the application - exists. This flag is now enabled by default. - -## v2.5.0 - -**Improvements** - -- Performance improvements for the backend logging thread - -## v2.4.2 - -**Fixes** - -- Fixes an assertion that was triggered in debug mode due to changes in v2.4.1 - -## v2.4.1 - -**Improvements** - -- Previously the backend worker thread would read all the log messages from the queue but not read the log messages when - the buffer had wrapped around. It will now read all the messages. -- Removed the `min_available_bytes` cache from the SPSC queue as an optimisation. It is not needed anymore as we now - read all messages at once instead of reading message by message. - -## v2.4.0 - -**Improvements** - -- Added a config option `backend_thread_strict_log_timestamp_order`. This option enables an extra timestamp - check on the backend logging thread when each message is popped from the queues. It prevents a rare - situation where log messages from different threads could appear in the log file in the wrong order. This flag - is now enabled by default. - -- Added a config option `backend_thread_empty_all_queues_before_exit`. This option makes the backend logging thread - to wait until all the queues are empty before exiting. This ensures no log messages are lost when the application - exists. This flag is now enabled by default. - -## v2.3.4 - -**Improvements** - -- Optimise the backend logging thread to read multiple log messages from the same queue, but still fairly read each - queue from all active threads. - -## v2.3.3 - -**Fixes** - -- Previously when multiple threads were logging, Quill backend logging thread would first try reading the log messages - of - one thread until the queue was completely empty before reading the log messages of the next thread. - When one of the threads was logging a lot, it could result in only displaying the log of that thread, hiding the - logs of the other threads. This has now been fixed and all log messages from all threads are read fairly. - -## v2.3.2 - -**Fixes** - -- Fix code not compiling with treat warnings as errors set on - Windows. ([#198](https://github.com/odygrd/quill/pull/198)) - -## v2.3.1 - -**Fixes** - -- Optimise logging queue cache alignment of variables. It seems that v2.3.0 made the hot path slower by ~5 ns per - message. This has been fixed in this version and the performance is now the same as in the previous versions. - -## v2.3.0 - -**Improvements** - -- Cache the available bytes for reading in the logging queue. This is meant to offer some minor performance - improvement to the backend logging thread. [#185](https://github.com/odygrd/quill/issues/185) - -- Fixed static code analysis and clang '-Wdocumentation' warnings. - -- The `Handler.h` API has changed in this version to support structured logs. If you have implemented your own custom - `Handler` you will have to change it to follow the new API. - -- This version adds support for writing structured logs. Structured logs provide easier search through events. - Structured logging is automatically enabled when named arguments are provided to the format string. Structured logs - are only supported by the new `quill::JsonFileHandler` handler. The already existing `FileHandler` and - `ConsoleHandler` are compatible with named arguments, but they will ignore them and output the log in its - original format, as defined by the pattern formatter. - Structured logs are not supported for wide characters at the moment. - See [example_json_structured_log.cpp](https://github.com/odygrd/quill/blob/master/examples/example_json_structured_log.cpp) - -For example : - -```c++ - quill::start(); - - quill::Handler* json_handler = - quill::create_handler("json_output.log", "w"); - - // create another logger tha logs e.g. to stdout and to the json file at the same time - quill::Logger* logger = quill::create_logger("dual_logger", {quill::stdout_handler(), json_handler}); - for (int i = 2; i < 4; ++i) - { - LOG_INFO(logger, "{method} to {endpoint} took {elapsed} ms", "POST", "http://", 10 * i); - } -``` - -1) Will write to stdout (stdout_handler) : - -```` -23:37:19.850432433 [11811] example_json_structured_log.cpp:39 LOG_INFO dual_logger - POST to http:// took 20 ms -23:37:19.850440154 [11811] example_json_structured_log.cpp:39 LOG_INFO dual_logger - POST to http:// took 30 ms -```` - -2) Will produce a JSON file (json_handler) : - -``` -{ "timestamp": "23:37:19.850432433", "file": "example_json_structured_log.cpp", "line": "39", "thread_id": "11811", "logger": "dual_logger", "level": "Info", "message": "{method} to {endpoint} took {elapsed} ms", "method": "POST", "endpoint": "http://", "elapsed": "20" } -{ "timestamp": "23:37:19.850440154", "file": "example_json_structured_log.cpp", "line": "39", "thread_id": "11811", "logger": "dual_logger", "level": "Info", "message": "{method} to {endpoint} took {elapsed} ms", "method": "POST", "endpoint": "http://", "elapsed": "30" } -``` - -## v2.2.0 - -**Improvements** - -- Previously storing the default root logger by calling `quill::get_logger()` followed by `quill::configure(cfg)` - would invalidate the pointer to the default root logger returned by the former function. This has now been fixed and - the obtained `Logger*` pointer is still valid. -- Disable `fmt::streamed()`. ([#189](https://github.com/odygrd/quill/issues/189)) -- Update bundled fmt to 9.1.0 -- `logger->should_log(level)` is removed. A compile time check was added to `logger->should_log()` - . ([#187](https://github.com/odygrd/quill/issues/187)) - -## v2.1.0 - -**Improvements** - -This version includes breaking changes to the API. Those changes are related to how quill is configured, -before calling `quill::start()` to start the backend thread. - -Check the updated [examples](https://github.com/odygrd/quill/blob/master/examples). - -[Config.h](https://github.com/odygrd/quill/blob/master/quill/include/quill/Config.h) - contains runtime configuration -options - -[TweakMe.h](https://github.com/odygrd/quill/blob/master/quill/include/quill/TweakMe.h) - contains compile time -configuration - -For example `quill::set_default_logger_handler(...)` has been removed. To set a default filehandler : - -```cpp - // create a handler - quill::Handler* file_handler = quill::file_handler("test.log", "w"); - - file_handler->set_pattern( - "%(ascii_time) [%(thread)] %(fileline:<28) %(level_name) %(logger_name:<12) - %(message)", - "%Y-%m-%d %H:%M:%S.%Qms", quill::Timezone::GmtTime); - - // set the handler as the default handler for any newly created logger in the config - quill::Config cfg; - cfg.default_handlers.emplace_back(file_handler); - - // configure must always be called prior to `start()` - quill::configure(cfg); - quill::start(); -``` - -- Removed some API functions from `Quill.h` that were previously used for configuration. Instead, `quill::Config` object - has to be created. For example `quill::config::set_backend_thread_cpu_affinity(1);` has been removed and instead the - following code is needed : - -```cpp - quill::Config cfg; - cfg.backend_thread_cpu_affinity = 1; - quill::configure(cfg); -``` - -- `QUILL_CHRONO_CLOCK` has been moved from `TweakMe.h` to `Config.h`. It is now possible to switch between `rdtsc` - and `system` - clocks without re-compiling. - See [example_trivial_system_clock.cpp](https://github.com/odygrd/quill/blob/master/examples/example_trivial_system_clock.cpp) -- `QUILL_RDTSC_RESYNC_INTERVAL` has been moved from `TweakMe.h` to `Config.h`. -- It is now possible to log user timestamps rather than the system's. This feature is useful for time simulations. - See [example_custom_clock.cpp](https://github.com/odygrd/quill/blob/master/examples/example_custom_clock.cpp) - and [example_custom_clock_advanced.cpp](https://github.com/odygrd/quill/blob/master/examples/example_custom_clock_advanced.cpp) -- Previously the logger names were limited to a maximum of 22 characters. This limitation has been removed. -- Added support for gcc 7.5.0. ([#178](https://github.com/odygrd/quill/issues/178)) -- Updated bundled fmt to 9.0.0 - -## v2.0.2 - -**Fixes** - -- Fix crash when a `std::string` containing null-terminated characters is passed to the - logger. ([#176](https://github.com/odygrd/quill/issues/176)) - -## v2.0.1 - -**Improvements** - -- Add a flag to RotatingFileHandler to disable removing the old files when `w` mode is used. - -## v2.0.0 - -From version `v2` and onwards only c++17 is supported. - -This version is a major refactor. - -**Fixes** - -- RotatingFileHandler will now correctly rotate the files when append mode is - used ([#123](https://github.com/odygrd/quill/issues/123)) - -**Improvements** - -- Reduced and simplified codebase. -- Improved backend worker thread performance. -- `QUILL_DUAL_QUEUE_MODE` has been removed. A single queue now handles every case. -- `QUILL_STRING` has been removed. That macro is no longer required when passing a format string to the - PatternFormatter. - -**Differences** - -- `v1.7` compiles with c++14, `v2` only compiles for c++17. -- `v1.7` on Windows supports wide character logging, `v2` has limited wide character support such as logging `wchar_t` - , `std::wstring`, `std::wstring_view`. For example, logging `std::vector` is not supported. -- `v1.7` on Windows requires the filepath used for the handlers as a wide strings, `v2` supports only filenames as - narrow strings. - -## v1.7.3 - -**Improvements/Fixes** - -- Fix crash on windows when a long wstring (>500 chars) is logged ([#173](https://github.com/odygrd/quill/issues/173)) -- Fix compiler error when trying to compile with - -DQUILL_DISABLE_NON_PREFIXED_MACROS ([#174](https://github.com/odygrd/quill/issues/174)) -- Fix a compile warning in clang ([#175](https://github.com/odygrd/quill/issues/175)) - -## v1.7.2 - -**Improvements/Fixes** - -- Fix compile error when C++20 is used on windows ([#162](https://github.com/odygrd/quill/issues/162)) - -## v1.7.1 - -**Improvements/Fixes** - -- Fix support for wide characters on Windows ([#168](https://github.com/odygrd/quill/issues/168)) -- Fix compilation error when `Quill::Logger*` is stored as a class member in templated classes -- Add `FilenameAppend::DateTime` as an option when creating a file handler - -## v1.7.0 - -**New Features** - -- Add a new function `quill::get_all_loggers()` that returns all the existing - loggers. ([#114](https://github.com/odygrd/quill/issues/114)) -- Add `%(level_id)` to pattern formatter. ([#136](https://github.com/odygrd/quill/issues/136)) -- Users can now specialise `copy_loggable` to mark user defined types as safe to - copy. ([#132](https://github.com/odygrd/quill/issues/132)) - -**Improvements/Fixes** - -- Fix initializations for C++17. -- Fix compiler warning in `check_format()` function. -- Replace `QUILL_DUAL_QUEUE_MODE` with `QUILL_DISABLE_DUAL_QUEUE_MODE`. -- Update bundled fmt to 8.1.1 -- Minor performance and accuracy improvements to rdtsc clock used by the backend thread. -- Fix compile error when C++20 is used. ([#162](https://github.com/odygrd/quill/issues/162)) -- Fix `get_page_size()` to only call sysconf once. ([#160](https://github.com/odygrd/quill/issues/160)) -- Fix incorrect timestamps in the log file when the system clock is - updated. ([#127](https://github.com/odygrd/quill/issues/127)) -- Previously if `quill:start(true)` was called more than once in the application, the signal handlers would get - initialised again. Now any subsequent calls to `quill:start(true)` will now have no effect - ([#167](https://github.com/odygrd/quill/issues/167)) -- Previously when the max limit of rotated files in `RotatingFileHandler` was reached, quill would stop rotating and - instead keep logging everything into the last log file. Now when the maximum limit of files is reached, - quill will now keep rotating by replacing the oldest logs. ([#157](https://github.com/odygrd/quill/issues/157)) -- Improve the backend logging thread responsiveness when variables are logged in loops without any delay - from multiple threads. ([#116](https://github.com/odygrd/quill/issues/116)) -- Fix some undefined behaviour issues reported via the AddressSantizer on the backend logging - thread. ([#166](https://github.com/odygrd/quill/issues/166)) - -## v1.6.3 - -**Improvements/Fixes** - -- Add support for `%(thread_name)` in PatternFormatter. ([#97](https://github.com/odygrd/quill/issues/97)) -- Add missing header needed for recent versions of fmt. ([#95](https://github.com/odygrd/quill/issues/95)) -- Force flush all active handlers on application exit. -- Update bundled fmt to 8.0.1 - -## v1.6.2 - -**Fixes** - -- Fix WIN32 compilation error when `NOMINMAX` is already defined. -- Fix `string` to `wstring` MinGW conversion. ([#92](https://github.com/odygrd/quill/issues/92)) -- Log enums via the main queue. ([#90](https://github.com/odygrd/quill/issues/90)) -- Fix windows compiler error when `min/max` macros are defined. ([#94](https://github.com/odygrd/quill/issues/94)) - -## v1.6.1 - -**Improvements/Fixes** - -- Fix windows C++20 build. ([#83](https://github.com/odygrd/quill/issues/83)) -- Fix ARM build on windows. -- Fix `example_backtrace` and minor bug when destructing with empty backtrace. - -## v1.6.0 - -**New Features** - -- Dual queue mode offering even lower latencies on hot paths. - See [Dual Queue Mode](https://github.com/odygrd/quill/wiki/9.-Dual-Queue-Mode). -- Added a signal handler for linux and windows. The signal handler flushes the log when the app crashes or - exits. ([#1](https://github.com/odygrd/quill/issues/1)) -- Added support for custom handlers. ([#75](https://github.com/odygrd/quill/issues/75)) -- Quill now compiles and runs on Cygwin. - -**Improvements/Fixes** - -- The queue from the caller to the backend worker thread has been reworked. The new queue generates slightly better - assembly than the previous one. Quill does no longer depend on mapping the same region of physical memory twice. -- Replaced an assertion check that could trigger incorrectly. ([#68](https://github.com/odygrd/quill/issues/68)) -- Fixed build on `ARM_ARCH < 6`. ([#78](https://github.com/odygrd/quill/issues/78)) -- Fixed compile errors when `QUILL_NOEXCEPTIONS`, `CMAKE_CXX_STANDARD 20`, `QUILL_USE_BOUNDED_QUEUE` are set. -- The unit tests have been moved to a separate binary with their own `main()`. This increased build times when building - the tests, but the failures are now easier to debug on different CI platforms and the tests can also run faster in - parallel. -- Fixed minor compiler warnings on windows. -- Upgraded bundled libfmt to `7.1.3` - -**Note** - -- If a custom queue capacity is defined using `#define QUILL_QUEUE_CAPACITY` after `1.6.0` the whole library needs to be - recompiled. - -## v1.5.2 - -- Removed the use of `fmt::format()` in `FileUtilities.cpp` as a workaround to the link errors in fmt v7. Use the header - only version of libfmt when external libfmt is defiend is no longer required. - -## v1.5.1 - -- When QUILL_FMT_EXTERNAL is defined, `quill` will use the header only version of `libfmt`. This is a workaround to the - link errors after libftm v7 - -## v1.5.0 - -- Upgraded bundled libfmt to `7.1.2` -- Added `Filters`. The filter class can be used for filtering log records. Filters can be added to handler instances. - See [example_filters.cpp](https://github.com/odygrd/quill/blob/master/examples/example_filters.cpp) -- It is now possible to set the log level severity on the handler objects. - See [example_filters.cpp](https://github.com/odygrd/quill/blob/master/examples/example_handler_log_levels.cpp) ([#49](https://github.com/odygrd/quill/issues/49)) -- Timestamp formatting optimisation for the backend worker thread. -- Free list allocator optimisation for the backend worker thread. -- Fixed PatternFormatter ignoring a portion of the pattern was ignored, when no format specifiers were - present. ([#56](https://github.com/odygrd/quill/issues/56)) -- When `%(function_name)` is used in PatternFormatter the namespace delimiter is replaced from `::` to `.` (Windows - only). ([#61](https://github.com/odygrd/quill/issues/61)) -- Arguments passed to the logger are no longer being evaluated when the log statement is not - logged. ([#67](https://github.com/odygrd/quill/issues/67)) -- PatternFormatter enhancement. It is now possible to pass [{fmt} string syntax](https://fmt.dev/latest/syntax.html) - to `QUILL_STRING`. The default PatternFormatter string has been changed - to: `"%(ascii_time) [%(thread)] %(fileline:<28) LOG_%(level_name) %(logger_name:<12) - %(message)"`. This results to - the following log being properly aligned despite the different lengths of each filename and logger name. - -``` -22:31:07.995438465 [2666041] file1.h:11 LOG_INFO logger1 - Log from file. -22:31:07.995445699 [2666041] long_file2.h:11 LOG_INFO logger_fl2 - Log from other file. -22:31:07.995457144 [2666041] a_longer_file_3.hpp:11 LOG_INFO logger_fl2_l - Log from other file. -22:31:07.995462471 [2666041] example_trivial.cpp:30 LOG_TRACE_L3 root - This is a log trace l3 example 1 -``` - -## v1.4.1 - -- Do not force `quill` to always build as `static` library in cmake. -- Minor fix when `quill` is compiled with no exceptions. -- Add the option to disable the non prefixed macro definitions if `QUILL_DISABLE_NON_PREFIXED_MACROS` is - defined. ([#40](https://github.com/odygrd/quill/issues/40)) - -## v1.4.0 - -- Added support for printing colour codes in the terminal. - See [ConsoleHandler](https://github.com/odygrd/quill/wiki/2.-Handlers#consolehandler) -- RotatingFileHandler improvements and minor change in API. - See [RotatingFileHandler](https://github.com/odygrd/quill/wiki/2.-Handlers#rotatingfilehandler) -- DailyFileHandler is removed and replaced by TimeRotatingFileHandler. - See [TimeRotatingFileHandler](https://github.com/odygrd/quill/wiki/2.-Handlers#timerotatingfilehandler) -- Added backtrace logging. Log messages can be stored in a buffer and flushed later on demand. - See [Backtrace Logging](https://github.com/odygrd/quill/wiki/6.-Backtrace-Logging) -- Added bundled `doctest` `2.4.0` -- Migrated all tests from `gtest` to `doctest`. -- Upgraded bundled libfmt to `7.0.3` - -## v1.3.3 - -- Upgraded bundled libfmt to `7.0.2` -- Fixed compile error with libfmt versions > `7.0.0` - -## v1.3.2 - -- Add a CMake option `QUILL_USE_BOUNDED_QUEUE` for bounded queue. -- Fixed a clang 10 warning -- Fixed MinGw build - -## v1.3.1 - -- Minor CMake fixes when `QUILL_FMT_EXTERNAL` option is used. - -## v1.3.0 - -**New Features** - -- Added option `QUILL_NO_EXCEPTIONS` to disable exceptions, std::abort() is called instead of an - exception. ([#16](https://github.com/odygrd/quill/issues/16)) -- Exceptions thrown in the backend worker thread, will now call a user provided error handler callback to handle the - error. ([#21](https://github.com/odygrd/quill/issues/21)) -- Compile time checks for unsafe to copy user defined types. Non trivial user defined types must be explicitly tagged as - safe to copy with the use of `QUILL_COPY_LOGGABLE;`. Otherwise they have to be formatted and passed as a string to the - logger by the user. The old unsafe mode is still usable - by `#define QUILL_MODE_UNSAFE` ([#20](https://github.com/odygrd/quill/issues/20)) -- Added `QUILL_USE_BOUNDED_QUEUE`. In this mode no new queues get allocated but instead log messages get lost. Number of - lost messages is reported to stderr. -- Minor hot path optimisation. The pointer to the metadata for each log message is no logger copied to the queue but - passed as a template argument instead. -- Added a latency benchmark, easily extendable for any logger - -**Improvements/Fixes** - -- `QUILL_RDTSC_CLOCK` option is replaced by `QUILL_CHRONO_CLOCK` which is by OFF by default. -- Improve compiler error message when trying to log a non copy constructible user defined type -- Fix buffer reallocation bug on TimestampFormatter. In previous versions any timestamp format set to 'set_pattern' - expanding to a string longer than 32 bytes would cause a crash. ([#24](https://github.com/odygrd/quill/issues/24)) -- The backend logging thread will now copy all messages from the SPSC queue to a local priority queue. This keeps the - SPSC less empty avoiding a potential allocation on the hot path. -- `std::string_view` is now promoted to `std::string` to take a deep copy -- The queue capacity has been moved from `config` to `Tweakme.h`. -- Multiple formats patterns support for `stdout` and `stderr` handlers. - See [example_stdout_multiple_formatters.cpp](https://github.com/odygrd/quill/blob/master/examples/example_custom_formatter.cpp) -- `quill::start()` will now block until the backend worker has started. -- Upgraded bundled libfmt to `6.2.1` - -## v1.2.3 - -- CMake changes to support package installation in conan. - -## v1.2.2 - -- Support for `arm/arm64`. ([#19](https://github.com/odygrd/quill/issues/19)) -- Add a cmake option `QUILL_ENABLE_INSTALL` to enable cpack. - -## v1.2.1 - -- Improved `QUILL_RDTSC_CLOCK` tweak option. It is now possible to switch between using `rdtsc` or `std::chrono` clock - without having to recompile quill as library. - -## v1.2.0 - -- Linking and including an external version of `fmt` is now supported. See `TweakMe.h` -- Fixed compiler warnings when using clang's `-Wdocumentation`. ([#12](https://github.com/odygrd/quill/issues/12)) -- Fixed a bug that wouldn't report a compile-time error for invalid format - strings. ([#13](https://github.com/odygrd/quill/issues/13)) -- Added process ID to Formatter. ([#14](https://github.com/odygrd/quill/issues/14)) -- Enhanced timestamp formatting. The `timestamp_format` string passed - in `handler->set_pattern(format_pattern, timestamp_format, timezone)` now accepts three additional specifiers `%Qms` - , `%Qus`, `%Qus` that can be used to format the fractional seconds. - See [here](https://github.com/odygrd/quill/wiki/3.-Formatters). ([#15](https://github.com/odygrd/quill/issues/15)) - -## v1.1.0 - -- Daily file handler. The file handler rollover every 24 hours -- Rotating file handler. The file handler will rollover based on the size of the file -- MinGW compatibility -- Added a CMake option `QUILL_VERBOSE_MAKEFILE`. Building Quill as a master project now defaults to non verbose makefile - output unless `-DQUILL_VERBOSE_MAKEFILE=ON` is passed to CMake. ([#6](https://github.com/odygrd/quill/issues/6)) -- Flush policy improvement. Previously Quill backend worker thread would never `flush`. This made watching the live log - of the application harder because the user has to wait for the operating system to flush or `quill::flush()` had to be - called on the caller threads. This has now been fixed, when the backend thread worker has no more log messages to - process it will automatically `flush`. ([#8](https://github.com/odygrd/quill/issues/8)) -- The log level names have been changed from `"LOG_INFO"`, `"LOG_DEBUG"`, etc to `"INFO"`, `"DEBUG"`, etc .. The default - formatter string is now using `"LOG_"%(level_name)` instead of `%(level_name)` therefore there is now change in the - behaviour. This change gives a lot of more flexibility to users who prefer to see e.g. `INFO` instead of `LOG_INFO` in - the logs. ([#7](https://github.com/odygrd/quill/issues/7)) -- An option has been added to append the date to the filename when using a - FileHandler `quill::file_handler(filename, mode, FilenameAppend);`. ([#7](https://github.com/odygrd/quill/issues/7)) -- It is now possible to specify the timezone of each handler timestamp. A new parameter is added - to `file_handler->set_pattern(...)`. See `PatternFormatter::Timezone` - . ([#7](https://github.com/odygrd/quill/issues/7)) -- Rename `emit` as it can conflict with Qt macros. ([#4](https://github.com/odygrd/quill/issues/4)) -- Upgraded `libfmt` to `6.2.0`. - -## v1.0.0 - -- Initial release. -- Using `libfmt` to `6.1.2`. diff --git a/subprojects/quill-4.2.0/CMakeLists.txt b/subprojects/quill-4.2.0/CMakeLists.txt deleted file mode 100644 index d8e771e..0000000 --- a/subprojects/quill-4.2.0/CMakeLists.txt +++ /dev/null @@ -1,166 +0,0 @@ -cmake_minimum_required(VERSION 3.8) -project(quill) - -#------------------------------------------------------------------------------------------------------- -# Options -#------------------------------------------------------------------------------------------------------- - -# Builds Quill without exceptions by adding the -fno-exceptions flag to the compiler. -option(QUILL_NO_EXCEPTIONS "Build without exceptions using -fno-exceptions flag" OFF) - -# Disables features that rely on retrieving the thread name, which is not supported in older versions of Windows (e.g., Windows Server 2012/2016). -# Enabling this option ensures compatibility with older Windows versions. -option(QUILL_NO_THREAD_NAME_SUPPORT "Disable features not supported on Windows Server 2012/2016" OFF) - -# Enables the use of _mm_prefetch, _mm_clflush, and _mm_clflushopt instructions to enhance cache coherence performance on x86 architectures. -# When enabled, Quill will utilize these instructions on the frontend's queue operations. -# Ensure to specify the target architecture with -march="..." when compiling to maximize compatibility and performance. -option(QUILL_X86ARCH "Enable optimizations for cache coherence on x86 architectures using specific CPU instructions" OFF) - -# When enabled, removes the non-prefixed `LOG_*` macros, leaving only `QUILL_LOG_*` macros available. -# This is useful in scenarios where the original macro names conflict with those of an existing logging library. -option(QUILL_DISABLE_NON_PREFIXED_MACROS "Disable non-prefixed macros" OFF) - -option(QUILL_DISABLE_POSITION_INDEPENDENT_CODE "Disable position-independent code" OFF) - -option(QUILL_BUILD_EXAMPLES "Build the examples" OFF) - -option(QUILL_BUILD_TESTS "Build the tests (Requires https://github.com/google/googletest to be installed)" OFF) - -option(QUILL_BUILD_BENCHMARKS "Build the benchmarks" OFF) - -option(QUILL_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF) - -option(QUILL_SANITIZE_THREAD "Enable thread sanitizer in tests (Using this option with any other compiler except clang may result to false positives)" OFF) - -option(QUILL_CODE_COVERAGE "Enable code coverage" OFF) - -option(QUILL_USE_VALGRIND "Use valgrind as the default memcheck tool in CTest (Requires Valgrind)" OFF) - -option(QUILL_ENABLE_INSTALL "Enable CMake Install when Quill is not a master project" OFF) - -option(QUILL_DOCS_GEN "Generate documentation" OFF) - -#------------------------------------------------------------------------------------------------------- -# Use newer policies if possible, up to most recent tested version of CMake. -#------------------------------------------------------------------------------------------------------- -cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) - -#------------------------------------------------------------------------------------------------------- -# Include common compiler options -#------------------------------------------------------------------------------------------------------- -include(${PROJECT_SOURCE_DIR}/cmake/SetCommonCompileOptions.cmake) - -#------------------------------------------------------------------------------------------------------- -# Determine if quill is built as a subproject (using add_subdirectory) or if it is the master project. -#------------------------------------------------------------------------------------------------------- -set(QUILL_MASTER_PROJECT FALSE CACHE BOOL "Master Project" FORCE) -if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) - set(QUILL_MASTER_PROJECT TRUE CACHE BOOL "Master Project" FORCE) -endif () - -#------------------------------------------------------------------------------------------------------- -# Custom cmake functions -#------------------------------------------------------------------------------------------------------- -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/quill/cmake") -include(Utility) - -#------------------------------------------------------------------------------------------------------- -# Resolve version -#------------------------------------------------------------------------------------------------------- -quill_extract_version() - -project(quill VERSION ${QUILL_VERSION} LANGUAGES CXX) - -#------------------------------------------------------------------------------------------------------- -# Set default build to release -#------------------------------------------------------------------------------------------------------- -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build" FORCE) -endif () - -#--------------------------------------------------------------------------------------- -# Compiler config -#--------------------------------------------------------------------------------------- -if (NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 17) - set(CMAKE_CXX_STANDARD_REQUIRED ON) -endif () - -#------------------------------------------------------------------------------------------------------- -# Required Packages -#------------------------------------------------------------------------------------------------------- -find_package(Threads REQUIRED) - -if (QUILL_BUILD_TESTS) - enable_testing() - - if (QUILL_USE_VALGRIND) - # find valgrind - find_program(MEMORYCHECK_COMMAND NAMES valgrind) - if (NOT MEMORYCHECK_COMMAND) - message(WARNING "Valgrind not found") - endif () - - # set valgrind params - set(MEMORYCHECK_COMMAND_OPTIONS "--tool=memcheck --leak-check=full --leak-resolution=med --show-leak-kinds=all --track-origins=yes --vgdb=no --fair-sched=yes") - - # add memcheck test action to ctest - include(CTest) - endif () -endif () - -#------------------------------------------------------------------------------------------------------- -# Log Info -#------------------------------------------------------------------------------------------------------- -if (QUILL_MASTER_PROJECT) - option(QUILL_VERBOSE_MAKEFILE "Verbose make output" OFF) - - message(STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE}) - message(STATUS "QUILL_VERSION: ${QUILL_VERSION}") -endif () - -message(STATUS "QUILL_NO_EXCEPTIONS: " ${QUILL_NO_EXCEPTIONS}) -message(STATUS "QUILL_NO_THREAD_NAME_SUPPORT: " ${QUILL_NO_THREAD_NAME_SUPPORT}) -message(STATUS "QUILL_X86ARCH: " ${QUILL_X86ARCH}) -message(STATUS "QUILL_DISABLE_NON_PREFIXED_MACROS: " ${QUILL_DISABLE_NON_PREFIXED_MACROS}) - -#--------------------------------------------------------------------------------------- -# Verbose make file option -#--------------------------------------------------------------------------------------- -if (QUILL_VERBOSE_MAKEFILE) - set(CMAKE_VERBOSE_MAKEFILE TRUE CACHE BOOL "Verbose output" FORCE) -endif () - -# address sanitizer flags -if (QUILL_SANITIZE_ADDRESS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer -g") -endif () - -# thread sanitizer flags -if (QUILL_SANITIZE_THREAD) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") -endif () - -# Append extra options for coverage -if (QUILL_CODE_COVERAGE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -fprofile-arcs -ftest-coverage") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") -endif () - -# Build Examples -if (QUILL_BUILD_EXAMPLES) - add_subdirectory(examples) -endif () - -if (QUILL_BUILD_BENCHMARKS) - add_subdirectory(benchmarks) -endif () - -add_subdirectory(quill) - -if (QUILL_DOCS_GEN) - # Add the cmake folder so the FindSphinx module is found - set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) - add_subdirectory(docs) -endif () \ No newline at end of file diff --git a/subprojects/quill-4.2.0/LICENSE b/subprojects/quill-4.2.0/LICENSE deleted file mode 100644 index 7cc1c04..0000000 --- a/subprojects/quill-4.2.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 - present, Odysseas Georgoudis - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/subprojects/quill-4.2.0/LICENSE.build b/subprojects/quill-4.2.0/LICENSE.build deleted file mode 100644 index b59833d..0000000 --- a/subprojects/quill-4.2.0/LICENSE.build +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2021 The Meson development team - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/subprojects/quill-4.2.0/README.md b/subprojects/quill-4.2.0/README.md deleted file mode 100644 index 6d09ff9..0000000 --- a/subprojects/quill-4.2.0/README.md +++ /dev/null @@ -1,511 +0,0 @@ -
- - Quill logo - -

Quill

- - - - - - - -

Asynchronous Low Latency C++ Logging Library

- -
- - -
- -- [Introduction](#introduction) -- [Documentation](#documentation) -- [Features](#features) -- [Caveats](#caveats) -- [Performance](#performance) -- [Quick Start](#quick-start) -- [CMake Integration](#cmake-integration) -- [Design](#design) -- [License](#license) - -| homebrew | vcpkg | conan | -|:--------------------:|:---------------------:|:-----------------:| -| `brew install quill` | `vcpkg install quill` | `quill/[>=1.2.3]` | - -## Introduction - -Quill is a high-performance, cross-platform logging library designed for C++17 and onwards. -Quill is a production-ready logging library that has undergone extensive unit testing. It has been successfully utilized -in production environments, including financial trading applications, providing high-performance and reliable logging -capabilities. - -## Documentation - -For detailed documentation and usage instructions, please visit -the [Quill Documentation on Read the Docs](http://quillcpp.readthedocs.io/). It provides comprehensive information on -how to integrate and utilize Quill in your C++ applications. - -Additionally, you can explore the [examples](http://github.com/odygrd/quill/tree/master/examples) folder in the Quill -repository on GitHub. These examples serve as valuable resources to understand different usage scenarios and demonstrate -the capabilities of the library. - -## Features - -- **Low Latency Logging**: Achieve fast logging performance with low latency. Refer to - the [Benchmarks](http://github.com/odygrd/quill#performance) for more details. -- **Asynchronous logging**: Log arguments and messages are formatted in a backend logging thread, effectively offloading - the formatting overhead from the critical path. -- **Custom Formatters**: Customize log formatting based on user-defined patterns. - Explore [Formatters](http://quillcpp.readthedocs.io/en/latest/tutorial.html#formatters) for further details. -- **Flexible Timestamp Generation**: Choose between rdtsc, chrono, or custom clocks (useful for simulations) for - log message timestamp generation. -- **Log Stack Traces**: Store log messages in a ring buffer and display them later in response to a higher severity log - statement or on demand. Refer - to [Backtrace Logging](http://quillcpp.readthedocs.io/en/latest/tutorial.html#backtrace-logging) for more information. -- **Multiple Logging Sinks**: Utilize various logging targets, including: - - Console logging with color support. - - File logging. - - Rotating log files based on time or size. - - JSON logging. - - Custom sinks. -- **Log Message Filtering**: Apply filters to selectively process log messages. Learn more - about [Filters](http://quillcpp.readthedocs.io/en/latest/tutorial.html#filters). -- **Structured Logging**: Generate JSON structured logs. - See [Structured-Log](http://quillcpp.readthedocs.io/en/latest/tutorial.html#json-log) for details. -- **Blocking or Dropping Message Modes**: Choose between `blocking` or `dropping` message modes in the library. - In `blocking` mode, the hot threads pause and wait when the queue is full until space becomes available, ensuring no - message loss but introducing potential latency. In `dropping` mode, log messages beyond the queue's capacity may be - dropped to prioritize low latency. The library provides reports on dropped messages, queue reallocations, and blocked - hot threads for monitoring purposes. -- **Queue Types**: The library supports different types of queues for transferring logs from the hot path to the backend - thread: bounded queues with a fixed capacity and unbounded queues that start small and can dynamically grow. -- **Wide Character Support**: Wide strings compatible with ASCII encoding are supported, applicable to Windows only. - Additionally, there is support for logging STL containers consisting of wide strings. Note that chaining STL types, - such as `std::vector>` is not supported for wide strings. -- **Ordered Log Statements**: Log statements are ordered by timestamp even when produced by different threads, - facilitating easier debugging of multithreaded applications. -- **Compile-Time Log Level Stripping**: Completely strip out log levels at compile time, reducing `if` branches. -- **Clean and Warning-Free Codebase**: Ensure a clean and warning-free codebase, even with high compiler warning levels. -- **Crash-Safe Behavior**: Benefit from crash-safe behavior with a built-in signal handler. -- **Type-Safe API**: Type safe api using the excellent [{fmt}](http://github.com/fmtlib/fmt) library. -- **Huge Pages**: Benefit from support for huge pages on the hot path. This feature allows for improved performance and - efficiency. - -## Caveats - -Quill may not work well with `fork()` since it spawns a background thread and `fork()` doesn't work well -with multithreading. - -If your application uses `fork()` and you want to log in the child processes as well, you should call -`quill::start()` after the `fork()` call. Additionally, you should ensure that you write to different -files in the parent and child processes to avoid conflicts. - -For example : - -```c++ -#include "quill/Backend.h" -#include "quill/Frontend.h" -#include "quill/LogMacros.h" -#include "quill/Logger.h" -#include "quill/sinks/FileSink.h" - -int main() -{ - // DO NOT CALL THIS BEFORE FORK - // quill::Backend::start(); - - if (fork() == 0) - { - quill::Backend::start(); - - // Get or create a handler to the file - Write to a different file - auto file_sink = quill::Frontend::create_or_get_sink( - "child.log"); - - quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(file_sink)); - - QUILL_LOG_INFO(logger, "Hello from Child {}", 123); - } - else - { - quill::Backend::start(); - - // Get or create a handler to the file - Write to a different file - auto file_sink = quill::Frontend::create_or_get_sink( - "parent.log"); - - quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(file_sink)); - - QUILL_LOG_INFO(logger, "Hello from Parent {}", 123); - } -} -``` - -## Performance - -### Latency - -The results presented in the tables below are measured in `nanoseconds (ns)`. - -#### Logging Numbers - -The following message is logged 100'000 times for each thread: - -`LOG_INFO(logger, "Logging int: {}, int: {}, double: {}", i, j, d)`. - -##### 1 Thread Logging - -| Library | 50th | 75th | 90th | 95th | 99th | 99.9th | -|---------------------------------------------------------------------|:----:|:----:|:----:|:----:|:----:|:------:| -| [Quill v4.1 Bounded Dropping Queue](http://github.com/odygrd/quill) | 7 | 7 | 8 | 8 | 9 | 10 | -| [fmtlog](http://github.com/MengRao/fmtlog) | 8 | 8 | 9 | 9 | 10 | 13 | -| [Quill v4.1 Unbounded Queue](http://github.com/odygrd/quill) | 8 | 8 | 9 | 9 | 10 | 13 | -| [Quill v3.8 Unbounded Queue](http://github.com/odygrd/quill) | 8 | 8 | 9 | 9 | 10 | 13 | -| [PlatformLab NanoLog](http://github.com/PlatformLab/NanoLog) | 11 | 12 | 13 | 14 | 15 | 20 | -| [MS BinLog](http://github.com/Morgan-Stanley/binlog) | 21 | 21 | 22 | 24 | 28 | 57 | -| [Reckless](http://github.com/mattiasflodin/reckless) | 41 | 45 | 47 | 48 | 49 | 69 | -| [Iyengar NanoLog](http://github.com/Iyengar111/NanoLog) | 51 | 54 | 63 | 81 | 113 | 160 | -| [spdlog](http://github.com/gabime/spdlog) | 148 | 153 | 159 | 163 | 169 | 176 | -| [g3log](http://github.com/KjellKod/g3log) | 1192 | 1282 | 1363 | 1440 | 1624 | 1802 | - -##### 4 Threads Logging Simultaneously - -| Library | 50th | 75th | 90th | 95th | 99th | 99.9th | -|---------------------------------------------------------------------|:----:|:----:|:----:|:----:|:----:|:------:| -| [Quill v4.1 Bounded Dropping Queue](http://github.com/odygrd/quill) | 7 | 8 | 9 | 9 | 10 | 13 | -| [fmtlog](http://github.com/MengRao/fmtlog) | 8 | 8 | 9 | 9 | 11 | 13 | -| [Quill v3.8 Unbounded Queue](http://github.com/odygrd/quill) | 8 | 9 | 10 | 10 | 11 | 13 | -| [Quill v4.1 Unbounded Queue](http://github.com/odygrd/quill) | 9 | 9 | 10 | 11 | 12 | 15 | -| [PlatformLab NanoLog](http://github.com/PlatformLab/NanoLog) | 12 | 13 | 13 | 14 | 15 | 19 | -| [MS BinLog](http://github.com/Morgan-Stanley/binlog) | 21 | 21 | 22 | 22 | 29 | 62 | -| [Reckless](http://github.com/mattiasflodin/reckless) | 42 | 46 | 47 | 48 | 54 | 78 | -| [Iyengar NanoLog](http://github.com/Iyengar111/NanoLog) | 53 | 62 | 93 | 122 | 150 | 216 | -| [spdlog](http://github.com/gabime/spdlog) | 209 | 236 | 276 | 304 | 409 | 700 | -| [g3log](http://github.com/KjellKod/g3log) | 1344 | 1415 | 1489 | 1557 | 1815 | 5855 | - -#### Logging Large Strings - -The following message is logged 100'000 times for each thread: - -`LOG_INFO(logger, "Logging int: {}, int: {}, string: {}", i, j, large_string)`. - -The large string used in the log message is over 35 characters to prevent the short string optimization -of `std::string`. - -##### 1 Thread Logging - -| Library | 50th | 75th | 90th | 95th | 99th | 99.9th | -|---------------------------------------------------------------------|:----:|:----:|:----:|:----:|:----:|:------:| -| [Quill v3.8 Unbounded Queue](http://github.com/odygrd/quill) | 10 | 12 | 13 | 13 | 14 | 16 | -| [Quill v4.1 Bounded Dropping Queue](http://github.com/odygrd/quill) | 11 | 12 | 13 | 14 | 15 | 17 | -| [fmtlog](http://github.com/MengRao/fmtlog) | 11 | 12 | 13 | 14 | 15 | 17 | -| [PlatformLab NanoLog](http://github.com/PlatformLab/NanoLog) | 13 | 14 | 15 | 15 | 17 | 19 | -| [Quill v4.1 Unbounded Queue](http://github.com/odygrd/quill) | 13 | 14 | 16 | 16 | 17 | 21 | -| [MS BinLog](http://github.com/Morgan-Stanley/binlog) | 22 | 23 | 23 | 25 | 30 | 59 | -| [Iyengar NanoLog](http://github.com/Iyengar111/NanoLog) | 52 | 55 | 64 | 83 | 114 | 160 | -| [Reckless](http://github.com/mattiasflodin/reckless) | 102 | 122 | 134 | 137 | 143 | 153 | -| [spdlog](http://github.com/gabime/spdlog) | 120 | 123 | 127 | 130 | 138 | 145 | -| [g3log](http://github.com/KjellKod/g3log) | 955 | 1049 | 1129 | 1190 | 1351 | 1539 | - -##### 4 Threads Logging Simultaneously - -| Library | 50th | 75th | 90th | 95th | 99th | 99.9th | -|---------------------------------------------------------------------|:----:|:----:|:----:|:----:|:----:|:------:| -| [Quill v4.1 Bounded Dropping Queue](http://github.com/odygrd/quill) | 11 | 12 | 13 | 15 | 16 | 18 | -| [fmtlog](http://github.com/MengRao/fmtlog) | 11 | 12 | 13 | 15 | 16 | 18 | -| [Quill v3.8 Unbounded Queue](http://github.com/odygrd/quill) | 12 | 13 | 14 | 15 | 16 | 19 | -| [PlatformLab NanoLog](http://github.com/PlatformLab/NanoLog) | 13 | 15 | 15 | 16 | 17 | 20 | -| [Quill v4.1 Unbounded Queue](http://github.com/odygrd/quill) | 14 | 16 | 17 | 18 | 19 | 22 | -| [MS BinLog](http://github.com/Morgan-Stanley/binlog) | 23 | 24 | 24 | 25 | 31 | 62 | -| [Iyengar NanoLog](http://github.com/Iyengar111/NanoLog) | 53 | 60 | 92 | 121 | 149 | 212 | -| [Reckless](http://github.com/mattiasflodin/reckless) | 101 | 121 | 133 | 136 | 143 | 160 | -| [spdlog](http://github.com/gabime/spdlog) | 186 | 215 | 266 | 297 | 381 | 641 | -| [g3log](http://github.com/KjellKod/g3log) | 1089 | 1164 | 1252 | 1328 | 1578 | 5563 | - -#### Logging Complex Types - -The following message is logged 100'000 times for each thread: - -`LOG_INFO(logger, "Logging int: {}, int: {}, vector: {}", i, j, v)`. - -Logging `std::vector v` containing 16 large strings, each ranging from 50 to 60 characters. -The strings used in the log message are over 35 characters to prevent the short string optimization of `std::string`. - -##### 1 Thread Logging - -| Library | 50th | 75th | 90th | 95th | 99th | 99.9th | -|---------------------------------------------------------------------|:----:|:----:|:----:|:----:|:----:|:------:| -| [Quill v4.1 Unbounded Queue](http://github.com/odygrd/quill) | 52 | 54 | 56 | 58 | 60 | 63 | -| [Quill v4.1 Bounded Dropping Queue](http://github.com/odygrd/quill) | 53 | 55 | 57 | 59 | 62 | 103 | -| [MS BinLog](http://github.com/Morgan-Stanley/binlog) | 66 | 70 | 79 | 81 | 84 | 91 | -| [Quill v3.8 Unbounded Queue](http://github.com/odygrd/quill) | 632 | 651 | 676 | 698 | 737 | 1049 | -| [fmtlog](http://github.com/MengRao/fmtlog) | 724 | 752 | 776 | 789 | 814 | 857 | -| [spdlog](http://github.com/gabime/spdlog) | 6242 | 6331 | 6438 | 6523 | 6782 | 7341 | - -##### 4 Threads Logging Simultaneously - -| Library | 50th | 75th | 90th | 95th | 99th | 99.9th | -|---------------------------------------------------------------------|:----:|:----:|:----:|:----:|:----:|:------:| -| [Quill v4.1 Bounded Dropping Queue](http://github.com/odygrd/quill) | 55 | 57 | 59 | 61 | 64 | 77 | -| [MS BinLog](http://github.com/Morgan-Stanley/binlog) | 70 | 74 | 83 | 85 | 88 | 102 | -| [Quill v4.1 Unbounded Queue](http://github.com/odygrd/quill) | 92 | 100 | 110 | 118 | 135 | 157 | -| [Quill v3.8 Unbounded Queue](http://github.com/odygrd/quill) | 674 | 694 | 736 | 762 | 805 | 884 | -| [fmtlog](http://github.com/MengRao/fmtlog) | 789 | 813 | 833 | 845 | 872 | 908 | -| [spdlog](http://github.com/gabime/spdlog) | 6500 | 6596 | 6724 | 6848 | 7560 | 9036 | - -The benchmark was conducted on `Linux RHEL 9` with an `Intel Core i5-12600` at 4.8 GHz. -The cpus are isolated on this system and each thread was pinned to a different CPU. `GCC 13.1` was used as the compiler. - -The benchmark methodology involved logging 20 messages in a loop, calculating and storing the average latency for those -20 messages, then waiting around ~2 milliseconds, and repeating this process for a specified number of iterations. - -_In the `Quill Bounded Dropping` benchmarks, the dropping queue size is set to `262,144` bytes, which is double the -default size of `131,072` bytes._ - -You can find the benchmark code on the [logger_benchmarks](http://github.com/odygrd/logger_benchmarks) repository. - -### Throughput - -The maximum throughput is measured by determining the maximum number of log messages the backend logging thread can -write to the log file per second. - -When measured on the same system as the latency benchmarks mentioned above the average throughput of the backend -logging thread is `4.56 million msgs/sec` - -While the primary focus of the library is not on throughput, it does provide efficient handling of log messages across -multiple threads. The backend logging thread, responsible for formatting and ordering log messages from hot threads, -ensures that all queues are emptied on a high priority basis. The backend thread internally buffers the log messages -and then writes them later when the caller thread queues are empty or when a predefined limit, -`backend_thread_transit_events_soft_limit`, is reached. This approach prevents the need for allocating new queues -or dropping messages on the hot path. - -Comparing throughput with other logging libraries in an asynchronous logging scenario has proven challenging. Some -libraries may drop log messages, resulting in smaller log files than expected, while others only offer asynchronous -flush, making it difficult to determine when the logging thread has finished processing all messages. -In contrast, Quill provides a blocking flush log guarantee, ensuring that every log message from the hot threads up to -that point is flushed to the file. - -For benchmarking purposes, you can find the -code [here](https://github.com/odygrd/quill/blob/master/benchmarks/backend_throughput/quill_backend_throughput.cpp). - -### Compilation Time - -Compile times are measured using `clang 15` and for `Release` build. - -Below, you can find the additional headers that the library will include when you need to log, following -the [recommended_usage](https://github.com/odygrd/quill/blob/master/examples/recommended_usage/recommended_usage.cpp) -example - -![quill_v4_1_compiler_profile.speedscope.png](docs%2Fquill_v4_1_compiler_profile.speedscope.png) - -There is also a compile-time benchmark measuring the compilation time of 2000 auto-generated log statements with -various arguments. You can find -it [here](https://github.com/odygrd/quill/blob/master/benchmarks/compile_time/compile_time_bench.cpp). It takes approximately 30 -seconds to compile. - -![quill_v4_compiler_bench.speedscope.png](docs%2Fquill_v4_compiler_bench.speedscope.png) - -## Quick Start - -```c++ -#include "quill/Backend.h" -#include "quill/Frontend.h" -#include "quill/LogMacros.h" -#include "quill/Logger.h" -#include "quill/sinks/FileSink.h" - -int main() -{ - // Start the backend thread - quill::Backend::start(); - - // Log to file - auto file_sink = quill::Frontend::create_or_get_sink( - "example_file_logging.log"); - - quill::Logger* logger = - quill::Frontend::create_or_get_logger("root", std::move(file_sink)); - - // set the log level of the logger to trace_l3 (default is info) - logger->set_log_level(quill::LogLevel::TraceL3); - - LOG_INFO(logger, "Welcome to Quill!"); - LOG_ERROR(logger, "An error message. error code {}", 123); - LOG_WARNING(logger, "A warning message."); - LOG_CRITICAL(logger, "A critical error."); - LOG_DEBUG(logger, "Debugging foo {}", 1234); - LOG_TRACE_L1(logger, "{:>30}", "right aligned"); - LOG_TRACE_L2(logger, "Positional arguments are {1} {0} ", "too", "supported"); - LOG_TRACE_L3(logger, "Support for floats {:03.2f}", 1.23456); -} -``` - -```c++ -#include "quill/Backend.h" -#include "quill/Frontend.h" -#include "quill/LogMacros.h" -#include "quill/Logger.h" -#include "quill/sinks/ConsoleSink.h" - -int main() -{ - // Start the backend thread - quill::Backend::start(); - - // Frontend - auto console_sink = quill::Frontend::create_or_get_sink("sink_id_1"); - quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(console_sink)); - - // Change the LogLevel to print everything - logger->set_log_level(quill::LogLevel::TraceL3); - - LOG_INFO(logger, "Welcome to Quill!"); - LOG_ERROR(logger, "An error message. error code {}", 123); - LOG_WARNING(logger, "A warning message."); - LOG_CRITICAL(logger, "A critical error."); - LOG_DEBUG(logger, "Debugging foo {}", 1234); - LOG_TRACE_L1(logger, "{:>30}", "right aligned"); - LOG_TRACE_L2(logger, "Positional arguments are {1} {0} ", "too", "supported"); - LOG_TRACE_L3(logger, "Support for floats {:03.2f}", 1.23456); -} -``` - -### Output - -[![Screenshot-2020-08-14-at-01-09-43.png](http://i.postimg.cc/02Vbt8LH/Screenshot-2020-08-14-at-01-09-43.png)](http://postimg.cc/LnZ95M4z) - -## CMake-Integration - -#### External - -##### Building and Installing Quill - -``` -git clone http://github.com/odygrd/quill.git -mkdir cmake_build -cd cmake_build -cmake .. -make install -``` - -Note: To install in custom directory invoke cmake with `-DCMAKE_INSTALL_PREFIX=/quill/install-dir/` - -Then use the library from a CMake project, you can locate it directly with `find_package()` - -##### Directory Structure - -``` -my_project/ -├── CMakeLists.txt -├── main.cpp -``` - -##### CMakeLists.txt - -```cmake -# Set only if needed - quill was installed under a custom non-standard directory -set(CMAKE_PREFIX_PATH /test_quill/usr/local/) - -find_package(quill REQUIRED) - -# Linking your project against quill -add_executable(example main.cpp) -target_link_libraries(example PUBLIC quill::quill) -``` - -#### Embedded - -To embed the library directly, copy the source [folder](http://github.com/odygrd/quill/tree/master/quill/quill) to your -project and call `add_subdirectory()` in your `CMakeLists.txt` file - -##### Directory Structure - -``` -my_project/ -├── quill/ (source folder) -├── CMakeLists.txt -├── main.cpp -``` - -##### CMakeLists.txt - -```cmake -cmake_minimum_required(VERSION 3.1.0) -project(my_project) - -set(CMAKE_CXX_STANDARD 17) - -add_subdirectory(quill) - -add_executable(my_project main.cpp) -target_link_libraries(my_project PUBLIC quill::quill) -``` - -#### Building Quill for Android NDK - -To build Quill for Android NDK add the following `CMake` flags when configuring the build: - - ``` - -DQUILL_NO_THREAD_NAME_SUPPORT:BOOL=ON - ``` - -## Design - -### Frontend (caller-thread) - -When invoking a `LOG_` macro: - -1. Creates a static constexpr metadata object to store `Metadata` such as the format string and source location. - -2. Pushes the data SPSC lock-free queue. For each log message, the following variables are pushed - -| Variable | Description | -|------------|:--------------------------------------------------------------------------------------------------------------:| -| timestamp | Current timestamp | -| Metadata* | Pointer to metadata information | -| Logger* | Pointer to the logger instance | -| DecodeFunc | A pointer to a templated function containing all the log message argument types, used for decoding the message | -| Args... | A serialized binary copy of each log message argument that was passed to the `LOG_` macro | - -### Backend - -Consumes each message from the SPSC queue, retrieves all the necessary information and then formats the message. -Subsequently, forwards the log message to all Sinks associated with the Logger. - -![design.jpg](docs%2Fdesign.jpg) - -## License - -Quill is licensed under the [MIT License](http://opensource.org/licenses/MIT) - -Quill depends on third party libraries with separate copyright notices and license terms. -Your use of the source code for these subcomponents is subject to the terms and conditions of the following licenses. - -- ([MIT License](http://opensource.org/licenses/MIT)) {fmt} (http://github.com/fmtlib/fmt/blob/master/LICENSE.rst) -- ([MIT License](http://opensource.org/licenses/MIT)) doctest (http://github.com/onqtam/doctest/blob/master/LICENSE.txt) diff --git a/subprojects/quill-4.2.0/benchmarks/CMakeLists.txt b/subprojects/quill-4.2.0/benchmarks/CMakeLists.txt deleted file mode 100644 index 81fe064..0000000 --- a/subprojects/quill-4.2.0/benchmarks/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_subdirectory(hot_path_latency) -add_subdirectory(backend_throughput) -add_subdirectory(compile_time) \ No newline at end of file diff --git a/subprojects/quill-4.2.0/benchmarks/backend_throughput/CMakeLists.txt b/subprojects/quill-4.2.0/benchmarks/backend_throughput/CMakeLists.txt deleted file mode 100644 index 33ae268..0000000 --- a/subprojects/quill-4.2.0/benchmarks/backend_throughput/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -add_executable(BENCHMARK_quill_backend_throughput quill_backend_throughput.cpp) -set_common_compile_options(BENCHMARK_quill_backend_throughput) -target_link_libraries(BENCHMARK_quill_backend_throughput quill) - -add_executable(BENCHMARK_quill_backend_throughput_no_buffering quill_backend_throughput_no_buffering.cpp) -set_common_compile_options(BENCHMARK_quill_backend_throughput_no_buffering) -target_link_libraries(BENCHMARK_quill_backend_throughput_no_buffering quill) \ No newline at end of file diff --git a/subprojects/quill-4.2.0/benchmarks/backend_throughput/quill_backend_throughput.cpp b/subprojects/quill-4.2.0/benchmarks/backend_throughput/quill_backend_throughput.cpp deleted file mode 100644 index 87eac80..0000000 --- a/subprojects/quill-4.2.0/benchmarks/backend_throughput/quill_backend_throughput.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -#include "quill/Backend.h" -#include "quill/Frontend.h" -#include "quill/LogMacros.h" -#include "quill/sinks/FileSink.h" - -static constexpr size_t total_iterations = 4'000'000; - -/** - * The backend worker just spins, so we just measure the total time elapsed for total_iterations - */ -int main() -{ - // main thread affinity - quill::detail::set_cpu_affinity(0); - - quill::BackendOptions backend_options; - backend_options.backend_cpu_affinity = 5; - - // Start the logging backend thread and give it some tiem to init - quill::Backend::start(backend_options); - - std::this_thread::sleep_for(std::chrono::milliseconds{100}); - - // Create a file sink to write to a file - std::shared_ptr file_sink = quill::Frontend::create_or_get_sink( - "quill_backend_total_time.log", - []() - { - quill::FileSinkConfig cfg; - cfg.set_open_mode('w'); - return cfg; - }(), - quill::FileEventNotifier{}); - - quill::Logger* logger = quill::Frontend::create_or_get_logger( - "bench_logger", std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)"); - - quill::Frontend::preallocate(); - - // start counting the time until backend worker finishes - auto const start_time = std::chrono::steady_clock::now(); - for (size_t iteration = 0; iteration < total_iterations; ++iteration) - { - LOG_INFO(logger, "Iteration: {} int: {} double: {}", iteration, iteration * 2, - static_cast(iteration) / 2); - } - - // block until all messages are flushed - logger->flush_log(); - - auto const end_time = std::chrono::steady_clock::now(); - auto const delta = end_time - start_time; - auto delta_d = std::chrono::duration_cast>(delta).count(); - - std::cout << fmtquill::format( - "Throughput is {:.2f} million msgs/sec average, total time elapsed: {} ms for {} " - "log messages \n", - total_iterations / delta_d / 1e6, - std::chrono::duration_cast(delta).count(), total_iterations) - << std::endl; -} \ No newline at end of file diff --git a/subprojects/quill-4.2.0/benchmarks/backend_throughput/quill_backend_throughput_no_buffering.cpp b/subprojects/quill-4.2.0/benchmarks/backend_throughput/quill_backend_throughput_no_buffering.cpp deleted file mode 100644 index 6bbf1bf..0000000 --- a/subprojects/quill-4.2.0/benchmarks/backend_throughput/quill_backend_throughput_no_buffering.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include - -#include "quill/Backend.h" -#include "quill/Frontend.h" -#include "quill/LogMacros.h" -#include "quill/sinks/FileSink.h" - -static constexpr size_t total_iterations = 4'000'000; - -/** - * The backend worker just spins, so we just measure the total time elapsed for total_iterations - */ -int main() -{ - // main thread affinity - quill::detail::set_cpu_affinity(0); - - quill::BackendOptions backend_options; - backend_options.backend_cpu_affinity = 5; - backend_options.transit_events_hard_limit = 1; - - // Start the logging backend thread and give it some tiem to init - quill::Backend::start(backend_options); - - std::this_thread::sleep_for(std::chrono::milliseconds{100}); - - // Create a file sink to write to a file - std::shared_ptr file_sink = quill::Frontend::create_or_get_sink( - "quill_backend_total_time.log", - []() - { - quill::FileSinkConfig cfg; - cfg.set_open_mode('w'); - return cfg; - }(), - quill::FileEventNotifier{}); - - quill::Logger* logger = quill::Frontend::create_or_get_logger( - "bench_logger", std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)"); - - quill::Frontend::preallocate(); - - // start counting the time until backend worker finishes - auto const start_time = std::chrono::steady_clock::now(); - for (size_t iteration = 0; iteration < total_iterations; ++iteration) - { - LOG_INFO(logger, "Iteration: {} int: {} double: {}", iteration, iteration * 2, - static_cast(iteration) / 2); - } - - // block until all messages are flushed - logger->flush_log(); - - auto const end_time = std::chrono::steady_clock::now(); - auto const delta = end_time - start_time; - auto delta_d = std::chrono::duration_cast>(delta).count(); - - std::cout << fmtquill::format( - "Throughput is {:.2f} million msgs/sec average, total time elapsed: {} ms for {} " - "log messages \n", - total_iterations / delta_d / 1e6, - std::chrono::duration_cast(delta).count(), total_iterations) - << std::endl; -} \ No newline at end of file diff --git a/subprojects/quill-4.2.0/benchmarks/compile_time/CMakeLists.txt b/subprojects/quill-4.2.0/benchmarks/compile_time/CMakeLists.txt deleted file mode 100644 index 34fba58..0000000 --- a/subprojects/quill-4.2.0/benchmarks/compile_time/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_subdirectory(qwrapper) - -add_executable(BENCHMARK_quill_compile_time compile_time_bench.cpp) -set_common_compile_options(BENCHMARK_quill_compile_time) -target_link_libraries(BENCHMARK_quill_compile_time qwrapper_compile_time_bench) diff --git a/subprojects/quill-4.2.0/benchmarks/compile_time/compile_time_bench.cpp b/subprojects/quill-4.2.0/benchmarks/compile_time/compile_time_bench.cpp deleted file mode 100644 index 6363df0..0000000 --- a/subprojects/quill-4.2.0/benchmarks/compile_time/compile_time_bench.cpp +++ /dev/null @@ -1,3365 +0,0 @@ -#include "qwrapper/qwrapper.h" - -#include "quill/Frontend.h" -#include "quill/LogMacros.h" -#include "quill/Logger.h" - -int main() -{ - setup_quill("recommended_usage.log"); - auto logger = quill::Frontend::get_logger("root"); - - LOG_INFO(logger, "example lazy brown {} {} {}", "example2", 4.0f, "example3"); - LOG_INFO(logger, "jumps brown example lazy {} {} {} {} {}", std::string("str1"), - static_cast(9), 6LL, "example1", static_cast(10)); - LOG_INFO(logger, "brown test jumps fox {} {} {} {} {} {} {} {} {}", false, std::string("str1"), - 3.0, "example3", 6LL, "example2", static_cast(10), 1, true); - LOG_INFO(logger, "dog test example lazy {} {} {} {} {} {} {} {} {} {}", std::string_view("view1"), 7UL, - static_cast(9), false, 6LL, 5L, true, "example3", "example2", std::string("str1")); - LOG_INFO(logger, "example fox lazy {} {} {} {} {} {} {} {} {} {}", "example1", 4.0f, 7UL, 5L, - true, 2, 3.0, 6LL, false, "example3"); - LOG_INFO(logger, "quick test over fox {} {} {} {}", true, static_cast(9), "example3", 6LL); - LOG_INFO(logger, "lazy logging test {} {} {} {} {}", 8ULL, 4.0f, std::string_view("view2"), - "example1", "example3"); - LOG_INFO(logger, "lazy over fox {} {}", std::string_view("view1"), 8ULL); - LOG_INFO(logger, "lazy fox brown {} {} {}", 5L, static_cast(9), static_cast(10)); - LOG_INFO(logger, "logging brown over dog {} {} {} {} {} {} {} {}", std::string_view("view1"), - "example2", std::string("str2"), std::string("str1"), 8ULL, std::string_view("view2"), false, 2); - LOG_INFO(logger, "brown fox test example {} {} {} {}", static_cast(10), 6LL, - static_cast(9), 7UL); - LOG_INFO(logger, "fox logging brown {} {} {} {} {} {} {} {}", 2, std::string("str2"), - static_cast(9), "example2", false, 7UL, "example3", 4.0f); - LOG_INFO(logger, "over quick logging lazy {} {} {} {}", std::string("str2"), "example3", 7UL, 5L); - LOG_INFO(logger, "dog over test jumps {} {} {} {} {}", 1, std::string_view("view2"), 8ULL, - "example3", 4.0f); - LOG_INFO(logger, "fox example dog {}", 5L); - LOG_INFO(logger, "example test fox dog {} {} {} {} {} {} {} {}", static_cast(10), 6LL, - 3.0, static_cast(9), 2, false, std::string_view("view2"), std::string_view("view1")); - LOG_INFO(logger, "test lazy jumps fox {} {} {} {} {} {}", 4.0f, std::string_view("view1"), - static_cast(10), std::string("str2"), 3.0, true); - LOG_INFO(logger, "over jumps brown {}", 4.0f); - LOG_INFO(logger, "dog brown over {} {} {} {} {} {} {} {}", "example1", - static_cast(10), false, 1, 6LL, std::string_view("view1"), 2, 8ULL); - LOG_INFO(logger, "over test jumps {} {} {} {} {} {} {} {}", true, std::string("str1"), 6LL, - "example3", 1, 7UL, 2, "example1"); - LOG_INFO(logger, "over dog example fox {} {} {} {} {} {} {} {} {} {}", 8ULL, 2, 5L, std::string("str1"), - std::string_view("view1"), std::string_view("view2"), 1, "example1", 7UL, std::string("str2")); - LOG_INFO(logger, "logging lazy fox {} {} {} {} {} {} {} {} {} {}", 8ULL, std::string("str2"), 7UL, - false, std::string("str1"), "example3", 3.0, std::string_view("view1"), "example1", 6LL); - LOG_INFO(logger, "logging example quick dog {} {} {} {} {} {} {} {} {}", 6LL, 1, 5L, 3.0, - "example3", 4.0f, 8ULL, std::string("str1"), false); - LOG_INFO(logger, "example jumps over {} {} {} {} {} {}", 6LL, static_cast(9), - static_cast(10), "example3", true, 7UL); - LOG_INFO(logger, "dog fox brown quick {} {} {}", 1, 5L, 6LL); - LOG_INFO(logger, "brown example dog {} {} {} {}", std::string("str2"), 6LL, true, std::string_view("view1")); - LOG_INFO(logger, "jumps example fox test {} {}", 6LL, std::string("str1")); - LOG_INFO(logger, "brown over dog fox {} {} {} {} {} {} {}", std::string("str1"), - std::string("str2"), 4.0f, false, 8ULL, "example2", true); - LOG_INFO(logger, "example over fox dog {} {} {} {} {} {} {} {} {} {}", "example1", 1, - static_cast(9), static_cast(10), "example2", std::string("str1"), - false, std::string_view("view1"), 4.0f, 7UL); - LOG_INFO(logger, "brown example test quick {} {} {} {} {} {}", std::string("str2"), 3.0, - static_cast(9), "example2", std::string("str1"), 8ULL); - LOG_INFO(logger, "fox brown jumps {} {} {} {} {} {} {} {} {} {}", "example3", std::string("str2"), - "example2", 7UL, false, 6LL, 5L, 4.0f, 2, std::string("str1")); - LOG_INFO(logger, "brown quick dog over {} {} {} {} {} {} {} {}", 1, 4.0f, std::string_view("view1"), - false, true, "example2", static_cast(10), std::string("str2")); - LOG_INFO(logger, "lazy jumps brown {} {} {}", 8ULL, 5L, "example1"); - LOG_INFO(logger, "example dog over {} {} {} {} {} {}", static_cast(9), "example2", 3.0, - std::string("str1"), 5L, std::string_view("view2")); - LOG_INFO(logger, "fox example dog {} {} {} {} {} {}", true, "example2", 3.0, 5L, 6LL, 1); - LOG_INFO(logger, "example lazy dog {} {} {} {} {} {} {}", 6LL, std::string("str2"), 4.0f, - "example2", std::string("str1"), static_cast(10), 8ULL); - LOG_INFO(logger, "fox logging brown {} {} {} {} {} {}", 2, true, "example1", 6LL, - std::string_view("view1"), 7UL); - LOG_INFO(logger, "example brown over test {} {}", 5L, std::string_view("view1")); - LOG_INFO(logger, "over test dog {} {} {} {} {}", std::string("str1"), std::string_view("view1"), - "example2", "example1", 6LL); - LOG_INFO(logger, "logging test example {} {} {} {} {} {} {} {} {} {}", 6LL, "example3", - static_cast(9), true, 7UL, 5L, std::string_view("view2"), 2, 1, std::string_view("view1")); - LOG_INFO(logger, "example test lazy quick {} {} {} {} {} {} {} {}", std::string("str1"), 6LL, 7UL, - std::string_view("view2"), static_cast(9), 5L, std::string("str2"), "example1"); - LOG_INFO(logger, "over lazy logging {} {} {} {} {}", "example3", std::string_view("view1"), 6LL, - false, "example2"); - LOG_INFO(logger, "lazy example jumps over {} {} {} {} {} {} {} {}", 3.0, "example3", 2, - "example2", 4.0f, 6LL, true, static_cast(10)); - LOG_INFO(logger, "fox brown example {}", 5L); - LOG_INFO(logger, "jumps lazy test over {} {}", false, std::string_view("view2")); - LOG_INFO(logger, "lazy over quick {} {} {} {} {} {} {}", true, 7UL, std::string("str1"), - "example1", 5L, 4.0f, static_cast(9)); - LOG_INFO(logger, "fox brown over jumps {} {} {} {} {} {} {}", 1, 3.0, true, std::string("str2"), - 4.0f, 6LL, "example3"); - LOG_INFO(logger, "example logging test quick {} {} {} {} {} {} {}", 1, "example2", - static_cast(9), 6LL, static_cast(10), 5L, std::string_view("view1")); - LOG_INFO(logger, "brown logging quick test {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - 5L, true, 8ULL, "example1", 2, 3.0, "example3", std::string("str2")); - LOG_INFO(logger, "logging dog over fox {} {} {}", false, std::string_view("view2"), 7UL); - LOG_INFO(logger, "quick fox test {} {} {} {} {} {} {} {}", std::string("str2"), 4.0f, 8ULL, - "example3", 5L, false, 7UL, std::string_view("view1")); - LOG_INFO(logger, "over logging lazy {} {} {} {} {} {} {} {}", 7UL, "example1", 3.0, "example2", - std::string_view("view2"), static_cast(9), std::string_view("view1"), 1); - LOG_INFO(logger, "brown dog example fox {} {} {} {} {} {} {} {} {}", std::string("str2"), - std::string_view("view1"), 1, 4.0f, 2, "example1", "example2", 7UL, 5L); - LOG_INFO(logger, "jumps brown dog test {} {} {} {} {} {} {} {} {}", "example2", - std::string("str2"), 7UL, 2, static_cast(9), false, 6LL, 5L, 3.0); - LOG_INFO(logger, "quick lazy logging {} {} {}", 4.0f, "example1", static_cast(10)); - LOG_INFO(logger, "jumps test quick fox {} {} {} {} {} {} {} {}", false, 4.0f, 1, - static_cast(9), "example1", 2, 6LL, "example3"); - LOG_INFO(logger, "over example dog {} {} {} {} {}", 6LL, 5L, "example1", 1, 4.0f); - LOG_INFO(logger, "brown fox logging {} {} {} {}", 5L, 3.0, 7UL, static_cast(9)); - LOG_INFO(logger, "over example brown {} {} {} {} {} {} {} {} {}", 2, std::string("str1"), 7UL, - true, false, 1, 5L, std::string("str2"), "example3"); - LOG_INFO(logger, "lazy test over jumps {} {} {} {} {} {} {} {} {} {}", false, "example3", - std::string_view("view2"), static_cast(9), 2, 4.0f, std::string("str2"), - std::string_view("view1"), std::string("str1"), "example2"); - LOG_INFO(logger, "test quick brown {} {}", std::string_view("view2"), std::string("str2")); - LOG_INFO(logger, "dog example over lazy {} {} {}", "example3", static_cast(10), true); - LOG_INFO(logger, "over test brown lazy {} {}", 3.0, 4.0f); - LOG_INFO(logger, "lazy jumps example {} {} {} {} {} {} {}", std::string_view("view1"), false, 6LL, - "example2", true, "example1", static_cast(9)); - LOG_INFO(logger, "fox example jumps over {} {} {} {} {} {} {} {} {}", 4.0f, 7UL, "example2", 8ULL, - std::string("str2"), 6LL, false, "example3", static_cast(9)); - LOG_INFO(logger, "dog example lazy jumps {} {} {} {} {} {} {} {}", 3.0, std::string_view("view2"), - 2, 6LL, std::string_view("view1"), std::string("str1"), 4.0f, std::string("str2")); - LOG_INFO(logger, "quick lazy test dog {} {}", "example1", std::string("str1")); - LOG_INFO(logger, "fox example quick dog {} {} {} {} {} {} {} {}", 2, 6LL, - static_cast(10), 7UL, std::string_view("view1"), 1, "example2", false); - LOG_INFO(logger, "jumps test quick fox {} {} {} {} {} {} {} {} {}", 8ULL, 2, std::string_view("view2"), - false, 6LL, 3.0, static_cast(9), "example1", "example2"); - LOG_INFO(logger, "dog jumps quick lazy {} {} {}", 2, 4.0f, "example2"); - LOG_INFO(logger, "dog over brown logging {} {} {} {}", std::string("str1"), 1, "example2", false); - LOG_INFO(logger, "dog lazy over example {} {} {} {}", 2, std::string("str2"), std::string("str1"), - "example1"); - LOG_INFO(logger, "logging jumps brown fox {} {} {} {} {} {} {} {} {} {}", std::string("str2"), - std::string_view("view2"), 7UL, std::string("str1"), 3.0, true, false, 6LL, 2, - static_cast(10)); - LOG_INFO(logger, "example over jumps brown {} {} {} {} {}", std::string_view("view2"), - std::string("str2"), 3.0, 2, 4.0f); - LOG_INFO(logger, "example dog jumps lazy {} {} {} {} {} {}", 8ULL, "example3", "example2", 6LL, true, false); - LOG_INFO(logger, "example dog fox {} {} {} {} {} {} {} {} {}", "example2", 1, 3.0, - std::string("str1"), "example1", 8ULL, std::string_view("view2"), false, 2); - LOG_INFO(logger, "example fox over {} {} {} {} {} {} {}", 7UL, 6LL, - static_cast(10), true, 4.0f, "example2", 5L); - LOG_INFO(logger, "lazy example jumps logging {} {} {} {} {} {} {}", false, "example3", 4.0f, - "example1", 8ULL, 3.0, std::string_view("view2")); - LOG_INFO(logger, "test dog lazy {} {} {}", std::string_view("view2"), 3.0, 5L); - LOG_INFO(logger, "jumps example over logging {} {} {}", 7UL, 4.0f, static_cast(9)); - LOG_INFO(logger, "dog example jumps quick {} {} {} {}", 2, 5L, 1, static_cast(9)); - LOG_INFO(logger, "test quick fox over {} {} {} {} {}", "example3", 1, 7UL, "example2", - std::string_view("view1")); - LOG_INFO(logger, "brown jumps over {} {} {} {} {} {} {} {} {}", "example2", false, std::string_view("view1"), - std::string("str2"), true, "example3", 3.0, 5L, static_cast(9)); - LOG_INFO(logger, "dog over fox {} {} {} {}", std::string("str2"), std::string("str1"), 1, - "example2"); - LOG_INFO(logger, "brown lazy dog over {} {} {} {} {}", std::string_view("view2"), 3.0, 4.0f, true, - std::string_view("view1")); - LOG_INFO(logger, "jumps lazy example {} {} {} {} {} {} {} {} {}", static_cast(9), - "example3", std::string_view("view2"), std::string("str1"), true, 7UL, - static_cast(10), 6LL, 5L); - LOG_INFO(logger, "dog quick jumps {} {} {} {} {} {} {} {} {} {}", "example3", 5L, true, - std::string("str1"), 8ULL, "example2", std::string_view("view1"), 1, 7UL, "example1"); - LOG_INFO(logger, "jumps quick example {} {} {} {} {} {} {}", 7UL, 5L, 2, static_cast(9), - std::string_view("view2"), 6LL, std::string("str1")); - LOG_INFO(logger, "quick logging brown {} {} {} {} {} {} {}", 3.0, "example1", - static_cast(10), 6LL, static_cast(9), 2, "example2"); - LOG_INFO(logger, "example test dog quick {}", static_cast(9)); - LOG_INFO(logger, "lazy jumps dog {}", 7UL); - LOG_INFO(logger, "example fox quick {} {} {} {} {} {} {}", std::string_view("view2"), 7UL, 2, - 8ULL, std::string("str1"), 6LL, 4.0f); - LOG_INFO(logger, "brown over dog test {} {}", 7UL, "example3"); - LOG_INFO(logger, "logging dog fox test {} {} {} {} {} {}", 4.0f, static_cast(9), true, - std::string_view("view2"), static_cast(10), std::string("str1")); - LOG_INFO(logger, "quick dog test {} {} {} {} {} {} {}", 6LL, 8ULL, "example2", - std::string("str1"), "example1", true, false); - LOG_INFO(logger, "jumps dog logging over {} {} {} {}", "example1", static_cast(10), 4.0f, false); - LOG_INFO(logger, "lazy dog example {} {} {} {} {} {} {} {} {}", true, 1, 2, 5L, - static_cast(10), "example1", 3.0, 8ULL, "example3"); - LOG_INFO(logger, "fox dog lazy jumps {} {} {}", std::string_view("view1"), 3.0, 8ULL); - LOG_INFO(logger, "lazy logging test quick {} {} {}", 5L, std::string_view("view2"), std::string("str1")); - LOG_INFO(logger, "jumps logging quick {}", false); - LOG_INFO(logger, "quick logging over {} {} {} {} {} {} {} {}", 5L, std::string_view("view1"), 1, - std::string_view("view2"), true, "example3", static_cast(10), false); - LOG_INFO(logger, "fox lazy test {} {} {} {} {} {} {}", std::string("str2"), "example3", 6LL, 1, - true, false, 4.0f); - LOG_INFO(logger, "fox over quick dog {} {} {} {}", "example2", true, - static_cast(10), std::string("str1")); - LOG_INFO(logger, "brown fox dog logging {} {} {} {} {} {} {} {}", 3.0, static_cast(10), - std::string_view("view1"), 7UL, 4.0f, false, 1, "example1"); - LOG_INFO(logger, "fox logging quick lazy {} {} {} {} {} {} {}", 5L, true, "example1", 6LL, - std::string_view("view2"), "example2", static_cast(10)); - LOG_INFO(logger, "quick dog jumps example {} {} {} {}", 6LL, std::string_view("view1"), - static_cast(10), std::string("str1")); - LOG_INFO(logger, "quick brown fox {} {} {} {} {} {} {} {} {} {}", std::string("str1"), 2, - std::string_view("view1"), 4.0f, false, "example1", 5L, static_cast(10), - static_cast(9), std::string("str2")); - LOG_INFO(logger, "dog quick brown {} {} {} {} {} {} {} {}", true, static_cast(9), 8ULL, - std::string("str2"), static_cast(10), 6LL, "example2", 2); - LOG_INFO(logger, "jumps dog logging over {} {} {} {} {} {} {} {}", 8ULL, true, - std::string("str2"), "example2", 4.0f, 5L, 6LL, static_cast(10)); - LOG_INFO(logger, "dog lazy example {}", static_cast(9)); - LOG_INFO(logger, "brown logging lazy {} {} {} {} {} {}", std::string_view("view2"), 5L, 2, - static_cast(10), true, "example1"); - LOG_INFO(logger, "jumps over brown {} {} {} {} {} {}", false, true, static_cast(9), 2, - std::string("str2"), "example3"); - LOG_INFO(logger, "lazy example quick {} {} {} {} {}", true, 3.0, 7UL, 4.0f, std::string_view("view1")); - LOG_INFO(logger, "logging dog over {} {} {} {} {} {}", std::string_view("view1"), 7UL, "example3", - true, static_cast(10), 5L); - LOG_INFO(logger, "jumps quick logging {} {}", 2, 7UL); - LOG_INFO(logger, "test lazy brown jumps {} {} {} {} {} {} {} {}", "example1", std::string("str1"), - 4.0f, 3.0, static_cast(10), std::string_view("view1"), 6LL, 7UL); - LOG_INFO(logger, "jumps example lazy test {} {}", 1, true); - LOG_INFO(logger, "jumps over dog {} {} {} {} {} {} {}", "example3", std::string_view("view1"), - static_cast(9), static_cast(10), std::string_view("view2"), true, 1); - LOG_INFO(logger, "logging dog example {} {} {} {}", false, 5L, std::string("str2"), - static_cast(10)); - LOG_INFO(logger, "logging quick brown {} {} {} {} {} {} {} {} {} {}", 8ULL, "example3", - std::string("str1"), "example1", "example2", 1, 3.0, 4.0f, 7UL, std::string_view("view2")); - LOG_INFO(logger, "logging over test {} {} {} {} {} {} {} {} {}", 2, std::string_view("view2"), - "example1", 6LL, true, 7UL, static_cast(9), static_cast(10), 3.0); - LOG_INFO(logger, "over example fox dog {} {}", std::string_view("view1"), 1); - LOG_INFO(logger, "quick logging lazy dog {} {}", "example2", std::string("str2")); - LOG_INFO(logger, "lazy over quick example {} {} {} {} {} {} {}", std::string("str2"), false, 4.0f, - std::string_view("view2"), 3.0, 6LL, std::string("str1")); - LOG_INFO(logger, "test dog brown {} {} {} {} {} {} {} {} {}", std::string("str1"), "example2", - 4.0f, 3.0, 8ULL, static_cast(10), false, 7UL, 5L); - LOG_INFO(logger, "brown quick logging jumps {} {} {} {} {} {}", static_cast(10), - "example2", true, false, 2, std::string_view("view1")); - LOG_INFO(logger, "quick over example {} {} {} {} {} {} {}", 5L, 1, 4.0f, - std::string_view("view2"), std::string("str2"), "example1", 3.0); - LOG_INFO(logger, "fox quick over test {} {}", std::string_view("view1"), 3.0); - LOG_INFO(logger, "dog lazy fox jumps {} {} {} {} {} {} {} {} {} {}", "example3", 1, 7UL, - static_cast(10), std::string("str2"), "example2", "example1", - static_cast(9), 6LL, 4.0f); - LOG_INFO(logger, "dog fox jumps example {} {} {} {} {} {} {} {}", static_cast(9), - "example3", 5L, 7UL, 2, std::string_view("view2"), false, static_cast(10)); - LOG_INFO(logger, "dog quick example lazy {} {} {} {} {} {} {} {}", 8ULL, 2, "example3", 4.0f, - std::string_view("view2"), static_cast(9), static_cast(10), 6LL); - LOG_INFO(logger, "over example brown {}", 6LL); - LOG_INFO(logger, "logging test jumps quick {} {} {} {} {}", true, std::string("str2"), 2, - std::string_view("view1"), 7UL); - LOG_INFO(logger, "brown fox over {} {} {} {} {} {} {} {} {} {}", static_cast(10), - std::string_view("view2"), false, std::string("str1"), "example1", 7UL, - std::string("str2"), true, 6LL, 1); - LOG_INFO(logger, "logging test dog fox {}", 3.0); - LOG_INFO(logger, "over brown dog {} {} {} {} {} {} {}", "example1", "example2", 6LL, - std::string("str1"), 7UL, std::string_view("view1"), false); - LOG_INFO(logger, "fox over lazy {} {} {} {} {} {} {} {} {} {}", static_cast(9), 8ULL, 5L, 6LL, - std::string_view("view2"), std::string_view("view1"), 1, std::string("str1"), "example2", 3.0); - LOG_INFO(logger, "lazy quick fox {} {} {} {}", std::string("str2"), "example3", 1, std::string_view("view2")); - LOG_INFO(logger, "brown fox logging lazy {} {} {} {} {}", std::string_view("view2"), - std::string("str1"), 5L, std::string_view("view1"), "example3"); - LOG_INFO(logger, "brown over fox {} {} {}", 2, 6LL, 4.0f); - LOG_INFO(logger, "logging fox jumps over {} {} {} {} {} {} {} {}", 7UL, 4.0f, "example1", 8ULL, - "example2", 5L, false, std::string("str2")); - LOG_INFO(logger, "over test logging jumps {} {} {} {} {} {}", true, 4.0f, "example1", 7UL, - std::string_view("view1"), "example3"); - LOG_INFO(logger, "example quick test {} {} {} {} {} {} {} {}", std::string("str1"), 7UL, 6LL, 3.0, - 2, 8ULL, 1, static_cast(10)); - LOG_INFO(logger, "example brown quick test {} {} {} {} {} {} {} {}", 2, false, 6LL, 4.0f, - std::string_view("view1"), 8ULL, "example3", "example2"); - LOG_INFO(logger, "brown example quick test {} {}", std::string("str1"), 8ULL); - LOG_INFO(logger, "logging example brown {} {} {} {} {}", std::string("str1"), 5L, 4.0f, - static_cast(9), "example1"); - LOG_INFO(logger, "quick logging lazy {} {}", static_cast(9), "example3"); - LOG_INFO(logger, "dog jumps over fox {} {} {} {} {} {} {}", 3.0, static_cast(9), 6LL, - false, 7UL, std::string_view("view1"), true); - LOG_INFO(logger, "brown dog example {} {} {} {} {} {} {} {} {}", "example1", std::string("str2"), true, - static_cast(10), 7UL, 8ULL, 1, std::string("str1"), std::string_view("view1")); - LOG_INFO(logger, "example test quick logging {} {} {} {} {} {} {} {} {}", 6LL, "example1", - "example3", 1, false, static_cast(10), 2, std::string("str2"), std::string("str1")); - LOG_INFO(logger, "quick lazy jumps example {} {} {} {} {} {} {} {}", "example2", 6LL, 4.0f, 7UL, - 2, 5L, std::string_view("view2"), static_cast(9)); - LOG_INFO(logger, "dog test logging quick {} {}", false, "example2"); - LOG_INFO(logger, "example dog over lazy {} {} {} {} {} {} {} {} {} {}", 6LL, 2, 3.0, - std::string_view("view2"), "example3", 4.0f, 8ULL, true, std::string("str2"), std::string("str1")); - LOG_INFO(logger, "test example logging {} {} {} {}", 1, std::string("str1"), 6LL, false); - LOG_INFO(logger, "logging over jumps lazy {} {} {} {} {} {} {} {} {}", true, 7UL, "example2", - static_cast(9), "example3", std::string_view("view2"), 5L, - std::string_view("view1"), std::string("str2")); - LOG_INFO(logger, "fox logging brown {} {} {} {} {} {} {} {} {} {}", std::string_view("view1"), 2, - false, static_cast(9), 3.0, "example2", std::string_view("view2"), - static_cast(10), true, "example1"); - LOG_INFO(logger, "over jumps logging {} {} {}", 5L, std::string("str2"), true); - LOG_INFO(logger, "lazy fox example brown {}", std::string_view("view1")); - LOG_INFO(logger, "test over quick {} {}", 8ULL, 5L); - LOG_INFO(logger, "example jumps quick fox {}", 6LL); - LOG_INFO(logger, "fox dog example quick {} {} {} {} {} {} {} {} {} {}", 5L, 7UL, "example2", 8ULL, - 3.0, static_cast(9), 6LL, true, static_cast(10), "example1"); - LOG_INFO(logger, "over test example dog {} {} {} {} {} {} {} {}", 2, 8ULL, 4.0f, "example1", - static_cast(9), std::string("str2"), 5L, std::string_view("view1")); - LOG_INFO(logger, "over dog test {} {}", 7UL, 2); - LOG_INFO(logger, "brown fox logging {}", 7UL); - LOG_INFO(logger, "fox jumps logging dog {} {} {} {} {} {} {} {}", 3.0, "example1", "example3", - std::string_view("view2"), false, 4.0f, 5L, true); - LOG_INFO(logger, "brown example logging {}", static_cast(10)); - LOG_INFO(logger, "brown jumps logging over {} {} {} {} {} {}", 6LL, 1, 8ULL, "example2", - std::string_view("view2"), "example3"); - LOG_INFO(logger, "logging fox brown {} {} {} {} {}", 2, 8ULL, static_cast(9), 6LL, 3.0); - LOG_INFO(logger, "lazy dog jumps fox {} {} {} {} {} {} {}", std::string_view("view2"), - std::string("str2"), std::string_view("view1"), "example1", 1, false, 4.0f); - LOG_INFO(logger, "brown quick dog {}", static_cast(10)); - LOG_INFO(logger, "brown dog lazy {} {} {} {} {}", static_cast(10), 3.0, - std::string_view("view2"), static_cast(9), 2); - LOG_INFO(logger, "lazy fox quick {} {} {}", 5L, "example1", static_cast(10)); - LOG_INFO(logger, "fox over quick {} {} {} {} {} {}", 4.0f, 6LL, std::string_view("view1"), - "example2", 1, std::string_view("view2")); - LOG_INFO(logger, "fox brown dog {} {} {} {} {} {} {}", false, 3.0, 4.0f, - std::string_view("view2"), 1, 6LL, 5L); - LOG_INFO(logger, "test brown jumps {} {} {} {} {}", true, 4.0f, static_cast(10), - "example1", std::string("str1")); - LOG_INFO(logger, "example fox test dog {} {}", std::string_view("view2"), static_cast(10)); - LOG_INFO(logger, "brown example quick {} {} {} {} {} {} {} {} {} {}", 2, 6LL, "example3", - static_cast(9), std::string_view("view1"), false, 4.0f, std::string("str1"), 7UL, 1); - LOG_INFO(logger, "example lazy over {} {} {} {} {} {}", static_cast(9), 5L, "example3", - std::string("str1"), 7UL, std::string("str2")); - LOG_INFO(logger, "quick logging fox {} {} {} {} {} {}", 5L, true, false, 2, std::string_view("view1"), 4.0f); - LOG_INFO(logger, "logging lazy dog {} {} {} {} {} {}", std::string_view("view1"), 4.0f, - "example1", "example3", false, std::string("str2")); - LOG_INFO(logger, "fox dog over test {} {} {} {} {} {} {} {} {}", std::string("str2"), 5L, 3.0, - "example3", static_cast(9), true, 6LL, 8ULL, 1); - LOG_INFO(logger, "dog lazy jumps {}", static_cast(9)); - LOG_INFO(logger, "test example dog {} {} {} {} {} {} {} {} {} {}", - static_cast(10), std::string("str2"), 7UL, std::string("str1"), true, - static_cast(9), std::string_view("view2"), false, 1, 8ULL); - LOG_INFO(logger, "fox jumps dog test {} {} {} {} {}", 1, 8ULL, std::string("str1"), "example2", - std::string_view("view2")); - LOG_INFO(logger, "example brown fox quick {} {}", static_cast(9), false); - LOG_INFO(logger, "over quick dog {} {} {} {} {}", 5L, 1, 8ULL, 7UL, 3.0); - LOG_INFO(logger, "brown test over quick {} {} {} {} {} {} {} {} {} {}", std::string_view("view1"), - 3.0, 4.0f, 2, false, "example3", 7UL, static_cast(9), true, 5L); - LOG_INFO(logger, "brown lazy over {} {} {} {} {} {}", std::string("str2"), 7UL, - static_cast(9), true, 8ULL, 2); - LOG_INFO(logger, "brown lazy fox {} {} {} {} {} {} {} {}", 7UL, 4.0f, static_cast(9), 1, - 6LL, false, "example2", std::string_view("view1")); - LOG_INFO(logger, "fox logging jumps quick {} {}", 6LL, 5L); - LOG_INFO(logger, "quick fox brown {} {} {} {} {}", std::string_view("view1"), - std::string_view("view2"), "example1", 2, "example2"); - LOG_INFO(logger, "example quick over brown {} {} {}", 8ULL, static_cast(10), - std::string_view("view1")); - LOG_INFO(logger, "quick over lazy {} {} {} {} {} {}", 7UL, 2, static_cast(10), 1, 3.0, 8ULL); - LOG_INFO(logger, "logging fox test brown {} {} {} {} {}", false, 8ULL, 1, 5L, std::string_view("view2")); - LOG_INFO(logger, "fox over dog test {}", std::string_view("view2")); - LOG_INFO(logger, "brown jumps logging {} {} {} {} {}", 4.0f, 8ULL, true, - std::string_view("view1"), static_cast(9)); - LOG_INFO(logger, "quick over brown jumps {} {} {} {} {} {}", "example2", "example3", 7UL, false, 8ULL, 5L); - LOG_INFO(logger, "test dog example over {} {} {} {} {} {}", 2, 1, static_cast(9), - "example3", std::string_view("view2"), std::string_view("view1")); - LOG_INFO(logger, "fox logging lazy over {} {} {} {}", "example2", std::string("str1"), 5L, 3.0); - LOG_INFO(logger, "logging fox test {} {} {} {}", false, static_cast(9), - static_cast(10), "example3"); - LOG_INFO(logger, "brown logging dog example {} {} {} {} {} {} {} {} {}", "example2", - std::string_view("view1"), std::string("str1"), "example3", std::string_view("view2"), - "example1", false, static_cast(10), 5L); - LOG_INFO(logger, "dog test example over {}", "example1"); - LOG_INFO(logger, "over jumps logging test {} {} {} {}", true, 4.0f, std::string("str2"), false); - LOG_INFO(logger, "brown example test logging {} {} {} {} {} {}", 3.0, 6LL, std::string("str2"), - static_cast(10), "example2", std::string_view("view1")); - LOG_INFO(logger, "example over dog quick {} {} {} {} {}", 1, 2, false, "example1", "example3"); - LOG_INFO(logger, "test dog example {} {} {} {} {} {} {} {} {} {}", true, "example2", "example3", - std::string("str2"), 1, static_cast(10), std::string_view("view1"), - "example1", 7UL, false); - LOG_INFO(logger, "dog example lazy test {} {} {} {}", "example2", std::string_view("view2"), 5L, 7UL); - LOG_INFO(logger, "logging over dog {}", std::string("str1")); - LOG_INFO(logger, "logging jumps test example {} {} {} {} {} {} {}", "example2", 8ULL, - std::string_view("view1"), "example1", static_cast(10), 5L, "example3"); - LOG_INFO(logger, "quick dog example {} {} {} {} {} {} {} {} {} {}", std::string("str1"), - std::string_view("view2"), true, 8ULL, std::string_view("view1"), 7UL, - static_cast(9), 3.0, static_cast(10), std::string("str2")); - LOG_INFO(logger, "brown quick over {} {}", 7UL, 2); - LOG_INFO(logger, "over lazy fox test {} {}", 8ULL, std::string("str2")); - LOG_INFO(logger, "example test brown jumps {} {}", std::string("str2"), 4.0f); - LOG_INFO(logger, "quick example lazy {} {} {} {} {} {} {} {} {} {}", std::string_view("view2"), false, - 2, static_cast(9), 3.0, "example3", std::string_view("view1"), "example1", true, 1); - LOG_INFO(logger, "dog fox test {} {} {} {} {} {} {}", 3.0, false, static_cast(9), - static_cast(10), 6LL, 1, "example3"); - LOG_INFO(logger, "test quick fox logging {} {} {} {}", true, 1, 7UL, 2); - LOG_INFO(logger, "brown example dog {} {} {} {} {}", std::string("str1"), 5L, "example1", - std::string("str2"), "example2"); - LOG_INFO(logger, "logging test dog {} {} {} {} {} {} {}", 5L, static_cast(9), 8ULL, false, - 4.0f, 6LL, std::string("str2")); - LOG_INFO(logger, "jumps brown quick {} {} {} {} {}", "example3", "example2", std::string("str2"), 4.0f, 5L); - LOG_INFO(logger, "test over dog {} {} {} {} {} {} {} {} {} {}", 6LL, 2, "example3", - std::string_view("view1"), static_cast(9), 1, 5L, "example1", 4.0f, "example2"); - LOG_INFO(logger, "jumps test quick {} {} {} {} {} {} {}", false, "example2", 8ULL, std::string_view("view1"), - static_cast(10), static_cast(9), std::string("str1")); - LOG_INFO(logger, "test logging fox {} {} {} {} {} {} {} {} {}", static_cast(9), "example3", - std::string_view("view1"), true, std::string("str2"), 7UL, - static_cast(10), std::string("str1"), 8ULL); - LOG_INFO(logger, "lazy dog over {} {} {} {} {} {} {} {} {}", 4.0f, 1, "example3", - std::string("str2"), true, 3.0, 5L, "example2", std::string_view("view2")); - LOG_INFO(logger, "test lazy dog {} {} {} {}", true, std::string_view("view2"), 6LL, "example1"); - LOG_INFO(logger, "jumps over logging example {} {} {} {} {}", std::string_view("view1"), - "example2", static_cast(10), std::string("str2"), 3.0); - LOG_INFO(logger, "example over jumps {} {}", std::string("str1"), "example3"); - LOG_INFO(logger, "quick brown test {} {} {} {} {} {} {} {} {} {}", std::string_view("view1"), - std::string("str1"), 6LL, 8ULL, "example1", std::string_view("view2"), "example3", 2, 7UL, 5L); - LOG_INFO(logger, "dog lazy quick over {} {} {} {} {} {} {} {}", 5L, 8ULL, true, false, - std::string("str1"), std::string_view("view2"), "example1", static_cast(10)); - LOG_INFO(logger, "jumps test dog {} {} {}", "example1", 4.0f, static_cast(10)); - LOG_INFO(logger, "example test lazy {} {} {} {} {} {} {} {} {}", "example1", true, std::string_view("view2"), - std::string("str1"), 7UL, 6LL, 8ULL, static_cast(10), "example2"); - LOG_INFO(logger, "fox brown quick over {} {} {} {}", 6LL, std::string_view("view1"), "example3", 4.0f); - LOG_INFO(logger, "dog jumps test brown {}", true); - LOG_INFO(logger, "quick dog test {} {} {} {}", static_cast(9), 3.0, 2, - static_cast(10)); - LOG_INFO(logger, "lazy over brown {} {} {} {} {} {} {} {} {} {}", std::string("str2"), 8ULL, 6LL, - 7UL, 4.0f, false, 5L, 3.0, std::string_view("view2"), "example1"); - LOG_INFO(logger, "quick jumps fox {} {} {} {}", static_cast(9), 2, 8ULL, std::string_view("view1")); - LOG_INFO(logger, "quick lazy test brown {} {} {} {} {}", 6LL, false, "example2", 2, 1); - LOG_INFO(logger, "test lazy logging dog {} {} {} {}", 2, static_cast(9), - std::string_view("view2"), false); - LOG_INFO(logger, "quick lazy logging {} {} {} {} {} {} {} {} {}", std::string_view("view1"), - static_cast(9), 2, std::string("str2"), 7UL, 3.0, std::string_view("view2"), 4.0f, 6LL); - LOG_INFO(logger, "over lazy fox test {} {} {} {} {} {} {} {}", "example2", static_cast(10), - std::string("str1"), "example3", 1, 2, true, std::string_view("view2")); - LOG_INFO(logger, "brown logging over {} {} {} {}", 1, false, 8ULL, true); - LOG_INFO(logger, "dog brown jumps quick {} {} {} {} {}", std::string_view("view1"), true, 7UL, - std::string_view("view2"), 5L); - LOG_INFO(logger, "jumps dog fox logging {} {} {} {} {} {} {} {}", "example1", 6LL, 1, - static_cast(9), 3.0, 2, std::string("str2"), 7UL); - LOG_INFO(logger, "logging lazy dog test {} {} {} {}", 5L, "example3", std::string_view("view1"), - static_cast(10)); - LOG_INFO(logger, "over fox test {} {} {} {}", 4.0f, false, "example1", true); - LOG_INFO(logger, "quick logging jumps over {} {} {} {} {} {} {} {}", false, true, - std::string_view("view1"), 2, "example3", 3.0, "example2", std::string("str1")); - LOG_INFO(logger, "test brown fox {} {}", std::string_view("view2"), 7UL); - LOG_INFO(logger, "example lazy dog {} {} {} {} {} {} {} {}", "example2", 4.0f, - std::string("str2"), std::string("str1"), 8ULL, 7UL, std::string_view("view2"), 2); - LOG_INFO(logger, "example logging fox test {} {} {} {} {} {} {} {}", true, static_cast(9), - 2, 7UL, 3.0, "example2", std::string("str2"), std::string("str1")); - LOG_INFO(logger, "brown jumps logging test {} {} {}", 6LL, true, std::string_view("view1")); - LOG_INFO(logger, "fox lazy jumps {} {} {} {}", "example3", std::string("str1"), true, 3.0); - LOG_INFO(logger, "fox test over quick {} {} {} {} {} {} {} {}", 8ULL, 4.0f, std::string("str1"), - 3.0, 7UL, std::string_view("view2"), "example2", static_cast(10)); - LOG_INFO(logger, "brown dog over logging {} {} {} {} {} {} {}", 4.0f, 7UL, "example3", - std::string("str2"), 3.0, 8ULL, "example2"); - LOG_INFO(logger, "lazy dog brown logging {} {}", 4.0f, 8ULL); - LOG_INFO(logger, "quick over jumps lazy {} {} {} {} {} {} {} {} {} {}", std::string("str2"), - "example2", 7UL, std::string("str1"), std::string_view("view2"), "example3", - static_cast(9), 2, "example1", true); - LOG_INFO(logger, "jumps logging lazy over {} {} {} {} {}", true, std::string_view("view2"), 3.0, - "example3", static_cast(10)); - LOG_INFO(logger, "brown quick example {} {} {} {}", true, "example1", std::string("str1"), 2); - LOG_INFO(logger, "over fox quick lazy {} {} {}", 5L, 3.0, std::string_view("view1")); - LOG_INFO(logger, "fox logging example {}", "example2"); - LOG_INFO(logger, "over dog test {} {} {} {} {} {} {}", 4.0f, static_cast(10), 1, - 7UL, true, false, 6LL); - LOG_INFO(logger, "quick logging lazy dog {} {} {} {} {} {} {} {} {} {}", static_cast(10), - true, "example3", 5L, 8ULL, 1, static_cast(9), std::string("str1"), "example2", 6LL); - LOG_INFO(logger, "brown jumps lazy test {} {} {} {} {} {} {}", 8ULL, "example3", 6LL, - std::string_view("view2"), std::string("str2"), "example2", false); - LOG_INFO(logger, "quick example test lazy {} {} {} {} {}", true, false, "example2", 6LL, - "example3"); - LOG_INFO(logger, "brown jumps logging {} {} {} {} {} {}", static_cast(10), 3.0, - 8ULL, "example3", true, 4.0f); - LOG_INFO(logger, "fox jumps logging {}", "example3"); - LOG_INFO(logger, "jumps test example {} {}", std::string("str2"), 1); - LOG_INFO(logger, "quick example jumps lazy {} {} {} {} {} {} {} {} {} {}", 5L, 6LL, static_cast(9), - 4.0f, "example3", "example2", 1, std::string("str2"), std::string_view("view2"), false); - LOG_INFO(logger, "fox quick over logging {} {} {} {} {} {} {} {} {}", 1, std::string_view("view2"), - 8ULL, false, 3.0, std::string_view("view1"), "example1", true, 7UL); - LOG_INFO(logger, "brown logging test fox {} {} {} {} {} {} {} {}", std::string("str1"), 5L, - static_cast(9), 7UL, 6LL, std::string_view("view2"), "example2", 8ULL); - LOG_INFO(logger, "brown example quick test {} {} {}", std::string_view("view2"), "example2", - std::string_view("view1")); - LOG_INFO(logger, "logging example test brown {} {} {} {} {} {}", std::string_view("view2"), - "example3", std::string("str2"), 8ULL, 3.0, std::string_view("view1")); - LOG_INFO(logger, "over quick fox dog {} {} {} {} {} {}", std::string("str2"), 5L, 6LL, "example3", - 8ULL, std::string_view("view2")); - LOG_INFO(logger, "test example brown {} {} {} {} {} {} {} {} {} {}", "example1", 7UL, 6LL, - "example2", 2, std::string("str1"), 1, false, 4.0f, 5L); - LOG_INFO(logger, "over test logging {} {} {} {} {} {} {} {} {} {}", static_cast(10), 5L, - "example3", static_cast(9), 6LL, std::string_view("view1"), 2, "example1", 3.0, 7UL); - LOG_INFO(logger, "logging over dog {} {}", std::string_view("view1"), 6LL); - LOG_INFO(logger, "jumps test example over {} {} {}", 5L, 7UL, "example1"); - LOG_INFO(logger, "fox test over {}", 5L); - LOG_INFO(logger, "quick jumps over brown {} {} {} {} {} {} {} {} {}", std::string("str2"), - std::string_view("view2"), 1, static_cast(9), std::string_view("view1"), true, - false, 8ULL, static_cast(10)); - LOG_INFO(logger, "over test jumps example {} {} {} {} {} {}", std::string("str2"), 1, - std::string_view("view1"), "example2", std::string_view("view2"), 6LL); - LOG_INFO(logger, "fox brown test lazy {} {} {} {}", static_cast(10), 2, - std::string("str1"), "example3"); - LOG_INFO(logger, "brown test jumps lazy {} {} {}", 7UL, std::string("str2"), 1); - LOG_INFO(logger, "over jumps brown dog {} {} {}", 7UL, std::string("str2"), static_cast(9)); - LOG_INFO(logger, "brown test example {} {} {} {} {} {} {}", 5L, static_cast(10), - "example3", 7UL, "example2", std::string_view("view1"), 6LL); - LOG_INFO(logger, "test brown dog {} {} {} {} {} {} {}", 1, 2, 6LL, 8ULL, true, "example1", 5L); - LOG_INFO(logger, "lazy fox over {} {} {} {} {} {} {} {} {}", std::string_view("view1"), true, - std::string("str2"), 4.0f, 3.0, "example2", 1, std::string_view("view2"), - static_cast(10)); - LOG_INFO(logger, "dog over jumps {} {}", "example2", 3.0); - LOG_INFO(logger, "test quick jumps dog {} {} {} {} {} {}", std::string("str1"), - std::string("str2"), 5L, std::string_view("view2"), 3.0, 4.0f); - LOG_INFO(logger, "logging over example {} {} {} {} {}", static_cast(10), 4.0f, 5L, - 2, "example2"); - LOG_INFO(logger, "dog example jumps {} {} {}", "example1", static_cast(10), 8ULL); - LOG_INFO(logger, "example dog fox logging {} {} {} {}", 5L, std::string("str2"), "example3", - "example2"); - LOG_INFO(logger, "fox dog test lazy {} {} {} {} {} {} {}", "example3", std::string("str1"), - "example2", 1, "example1", std::string_view("view2"), false); - LOG_INFO(logger, "fox logging lazy quick {}", 2); - LOG_INFO(logger, "test quick over {}", std::string_view("view2")); - LOG_INFO(logger, "example logging jumps dog {} {}", std::string("str1"), std::string_view("view2")); - LOG_INFO(logger, "over lazy logging {} {} {} {} {} {}", 7UL, 6LL, static_cast(9), - "example1", std::string_view("view1"), "example3"); - LOG_INFO(logger, "logging example dog {} {} {} {} {} {} {} {} {} {}", 3.0, static_cast(10), - 5L, "example3", 2, static_cast(9), false, std::string("str1"), 6LL, 4.0f); - LOG_INFO(logger, "example quick lazy {} {}", static_cast(10), false); - LOG_INFO(logger, "example fox over logging {} {} {}", "example2", static_cast(9), - "example1"); - LOG_INFO(logger, "logging jumps brown {} {} {} {} {} {} {} {} {} {}", 5L, 2, 6LL, 4.0f, - "example2", std::string_view("view2"), 3.0, static_cast(10), "example3", - std::string_view("view1")); - LOG_INFO(logger, "quick logging example fox {}", 2); - LOG_INFO(logger, "example over quick {} {} {} {} {} {} {}", 6LL, 1, 5L, 2, 4.0f, 8ULL, "example3"); - LOG_INFO(logger, "quick lazy test example {} {} {} {} {} {} {}", 4.0f, std::string("str2"), 2, - 7UL, false, "example2", 1); - LOG_INFO(logger, "dog jumps fox lazy {} {} {} {} {} {}", true, 3.0, std::string("str2"), false, - std::string("str1"), 5L); - LOG_INFO(logger, "brown quick dog jumps {} {} {}", 6LL, 4.0f, false); - LOG_INFO(logger, "test lazy over brown {} {} {}", std::string("str2"), static_cast(9), - "example2"); - LOG_INFO(logger, "fox example quick jumps {} {} {} {}", 6LL, std::string("str2"), 2, 8ULL); - LOG_INFO(logger, "logging brown dog over {} {} {} {}", 4.0f, 2, std::string_view("view2"), 6LL); - LOG_INFO(logger, "over fox brown lazy {} {} {} {} {} {} {} {}", static_cast(10), - 4.0f, true, 7UL, 5L, "example2", std::string_view("view1"), std::string("str1")); - LOG_INFO(logger, "fox quick lazy {} {} {} {} {} {} {} {} {}", "example1", - std::string_view("view2"), true, 7UL, 2, std::string_view("view1"), - static_cast(9), std::string("str1"), std::string("str2")); - LOG_INFO(logger, "test brown example fox {} {} {} {} {} {} {} {} {} {}", 1, static_cast(9), - false, true, 5L, std::string("str2"), "example3", 8ULL, 6LL, 7UL); - LOG_INFO(logger, "dog lazy logging example {} {} {} {} {} {}", 5L, - static_cast(10), 3.0, 1, true, 8ULL); - LOG_INFO(logger, "logging quick fox test {} {} {} {} {} {} {} {} {}", true, false, std::string("str1"), 7UL, - static_cast(9), static_cast(10), 5L, "example3", std::string("str2")); - LOG_INFO(logger, "test quick over brown {} {}", false, "example3"); - LOG_INFO(logger, "lazy quick over test {} {} {} {} {} {} {}", std::string("str1"), - static_cast(9), std::string("str2"), std::string_view("view1"), 8ULL, 7UL, 6LL); - LOG_INFO(logger, "fox brown example {} {} {} {} {} {} {}", 7UL, static_cast(10), - 6LL, true, false, "example2", std::string("str2")); - LOG_INFO(logger, "brown logging quick {} {} {} {} {} {} {} {} {} {}", "example3", 4.0f, 5L, true, - "example1", "example2", static_cast(9), 2, 6LL, 1); - LOG_INFO(logger, "test dog jumps {} {}", "example2", 4.0f); - LOG_INFO(logger, "brown test dog {} {}", 5L, 3.0); - LOG_INFO(logger, "dog jumps test {} {} {} {} {}", 8ULL, std::string("str1"), 6LL, 1, false); - LOG_INFO(logger, "example over jumps {} {} {} {} {} {} {} {} {} {}", std::string_view("view1"), - 3.0, 2, "example1", 5L, 6LL, std::string_view("view2"), 4.0f, static_cast(9), 8ULL); - LOG_INFO(logger, "quick logging brown jumps {} {} {} {} {}", 7UL, 1, - static_cast(10), true, "example3"); - LOG_INFO(logger, "test dog fox brown {} {} {} {} {} {} {} {}", std::string_view("view2"), 6LL, - 7UL, std::string("str1"), static_cast(9), true, std::string_view("view1"), false); - LOG_INFO(logger, "over lazy brown {} {} {} {} {} {} {}", "example3", 8ULL, std::string_view("view1"), - false, std::string("str1"), std::string_view("view2"), "example2"); - LOG_INFO(logger, "dog over logging lazy {} {} {} {} {} {} {} {}", "example1", 4.0f, "example3", - true, 8ULL, std::string("str2"), std::string_view("view1"), 3.0); - LOG_INFO(logger, "logging over dog quick {} {} {} {} {} {}", 5L, std::string("str2"), 7UL, - "example3", std::string("str1"), 4.0f); - LOG_INFO(logger, "dog example test {} {} {} {}", static_cast(10), - std::string("str1"), "example2", std::string_view("view2")); - LOG_INFO(logger, "quick example jumps {} {} {} {} {}", 1, 7UL, 3.0, "example3", 6LL); - LOG_INFO(logger, "quick brown dog {} {} {} {} {} {} {} {} {}", std::string_view("view2"), false, - 6LL, static_cast(10), 5L, "example2", 8ULL, 7UL, true); - LOG_INFO(logger, "example brown test quick {} {} {}", 3.0, 2, static_cast(10)); - LOG_INFO(logger, "test over fox {} {} {} {}", "example3", "example1", true, static_cast(9)); - LOG_INFO(logger, "logging quick example {} {} {} {} {}", static_cast(9), 5L, - std::string_view("view1"), "example1", 2); - LOG_INFO(logger, "example brown over {} {} {} {} {} {}", std::string_view("view2"), - std::string("str2"), 2, 7UL, std::string_view("view1"), static_cast(10)); - LOG_INFO(logger, "dog test lazy fox {} {} {} {} {} {} {}", std::string("str2"), 8ULL, 6LL, 2, - 4.0f, "example3", false); - LOG_INFO(logger, "test brown dog {}", false); - LOG_INFO(logger, "jumps example lazy {}", 4.0f); - LOG_INFO(logger, "over lazy jumps logging {} {} {} {} {} {} {} {} {} {}", 8ULL, - static_cast(10), 3.0, std::string_view("view2"), false, true, 5L, 4.0f, - static_cast(9), "example1"); - LOG_INFO(logger, "fox lazy brown jumps {} {} {} {} {} {} {}", std::string("str2"), - static_cast(10), 5L, 1, "example2", 4.0f, false); - LOG_INFO(logger, "example brown logging jumps {} {} {} {} {} {} {} {}", 6LL, std::string_view("view1"), - 2, false, static_cast(9), static_cast(10), "example1", 4.0f); - LOG_INFO(logger, "fox test brown {} {} {} {} {}", static_cast(9), 3.0, 8ULL, 5L, 4.0f); - LOG_INFO(logger, "over logging dog test {} {} {}", std::string_view("view1"), 8ULL, - static_cast(10)); - LOG_INFO(logger, "brown dog jumps test {} {} {}", 3.0, "example2", 5L); - LOG_INFO(logger, "jumps example lazy {} {}", "example1", false); - LOG_INFO(logger, "lazy dog test {} {} {} {}", std::string("str2"), - static_cast(10), false, static_cast(9)); - LOG_INFO(logger, "test fox lazy logging {} {}", static_cast(10), 8ULL); - LOG_INFO(logger, "logging jumps fox {} {} {}", true, 3.0, 5L); - LOG_INFO(logger, "quick example lazy brown {} {} {} {} {} {} {} {} {} {}", "example1", true, 3.0, 7UL, - 8ULL, std::string("str2"), std::string("str1"), 4.0f, "example2", std::string_view("view2")); - LOG_INFO(logger, "brown example over lazy {} {} {} {} {} {} {}", std::string_view("view1"), 3.0, - 4.0f, "example3", std::string("str2"), 8ULL, 6LL); - LOG_INFO(logger, "example test brown quick {} {} {} {} {} {}", "example2", 7UL, 4.0f, - static_cast(9), "example1", 2); - LOG_INFO(logger, "over logging example jumps {} {} {} {} {} {}", static_cast(10), - 6LL, 4.0f, 7UL, 3.0, true); - LOG_INFO(logger, "example fox lazy test {} {} {} {} {} {}", static_cast(9), 6LL, 7UL, 1, 4.0f, 8ULL); - LOG_INFO(logger, "brown lazy quick {} {} {} {} {} {} {}", static_cast(9), 6LL, true, - static_cast(10), "example2", false, 5L); - LOG_INFO(logger, "quick example lazy {}", std::string_view("view2")); - LOG_INFO(logger, "fox example over {} {} {}", static_cast(10), std::string_view("view2"), 5L); - LOG_INFO(logger, "dog over fox {} {} {} {}", 1, std::string_view("view2"), 2, std::string("str2")); - LOG_INFO(logger, "test jumps quick dog {} {} {} {} {} {} {}", std::string("str1"), 1, "example3", - 4.0f, static_cast(10), 8ULL, "example2"); - LOG_INFO(logger, "example jumps lazy {} {} {} {} {}", std::string("str2"), "example2", - static_cast(9), 6LL, 8ULL); - LOG_INFO(logger, "quick jumps lazy example {} {} {} {} {} {} {}", 4.0f, 7UL, false, - static_cast(10), "example2", static_cast(9), 1); - LOG_INFO(logger, "dog quick brown {} {} {} {} {}", false, 4.0f, "example3", 7UL, true); - LOG_INFO(logger, "quick brown jumps {} {} {} {} {} {} {}", 2, 3.0, "example3", 1, 8ULL, - static_cast(10), std::string("str1")); - LOG_INFO(logger, "test lazy dog quick {} {} {} {} {}", std::string("str2"), static_cast(9), - 8ULL, false, static_cast(10)); - LOG_INFO(logger, "over quick lazy fox {} {}", "example1", std::string_view("view1")); - LOG_INFO(logger, "quick over lazy {} {} {} {} {} {}", false, static_cast(9), 2, 1, 3.0, - std::string("str1")); - LOG_INFO(logger, "fox lazy logging {} {} {} {} {} {} {}", 4.0f, "example3", true, false, - std::string_view("view2"), static_cast(9), std::string("str1")); - LOG_INFO(logger, "example jumps dog fox {} {} {} {}", std::string_view("view1"), - static_cast(10), std::string("str1"), 8ULL); - LOG_INFO(logger, "dog lazy test logging {} {} {} {} {} {} {} {}", std::string_view("view2"), 8ULL, - 2, std::string("str1"), static_cast(9), "example3", std::string("str2"), true); - LOG_INFO(logger, "logging dog jumps {} {} {} {} {} {} {} {} {} {}", "example2", 1, false, 6LL, - 3.0, static_cast(10), std::string_view("view2"), 4.0f, true, "example3"); - LOG_INFO(logger, "example dog logging quick {} {} {} {} {} {}", false, "example3", 4.0f, - std::string("str1"), 7UL, 5L); - LOG_INFO(logger, "test fox quick brown {}", std::string_view("view2")); - LOG_INFO(logger, "example quick logging {} {} {} {} {} {} {}", static_cast(10), - std::string("str1"), 2, "example2", std::string("str2"), std::string_view("view2"), - "example1"); - LOG_INFO(logger, "jumps fox quick test {} {} {} {} {} {} {} {}", 4.0f, 5L, "example2", 3.0, - static_cast(9), 1, 8ULL, std::string_view("view1")); - LOG_INFO(logger, "logging lazy jumps quick {} {} {} {} {}", 7UL, "example2", - std::string_view("view2"), 4.0f, 3.0); - LOG_INFO(logger, "test logging lazy over {} {} {} {} {} {} {} {}", "example1", - std::string_view("view2"), 6LL, 5L, std::string("str1"), 8ULL, 3.0, static_cast(9)); - LOG_INFO(logger, "logging test fox {}", 8ULL); - LOG_INFO(logger, "dog lazy jumps {} {} {} {} {} {} {}", 3.0, 7UL, "example2", 1, - std::string_view("view2"), 6LL, std::string_view("view1")); - LOG_INFO(logger, "dog over fox jumps {} {} {} {} {} {} {} {}", static_cast(9), - std::string_view("view2"), 2, "example2", 6LL, 8ULL, std::string("str2"), - std::string_view("view1")); - LOG_INFO(logger, "logging quick lazy {} {} {} {} {}", 8ULL, std::string("str1"), 4.0f, - std::string("str2"), "example2"); - LOG_INFO(logger, "dog test fox {} {} {} {} {} {} {} {} {}", "example1", std::string("str2"), 1, - 3.0, std::string_view("view2"), 7UL, false, 8ULL, 2); - LOG_INFO(logger, "over dog quick jumps {} {} {} {} {} {} {} {} {}", std::string("str2"), 8ULL, - "example3", 3.0, false, true, 2, std::string_view("view2"), static_cast(9)); - LOG_INFO(logger, "quick logging brown {} {} {} {} {}", "example3", - static_cast(10), 8ULL, "example1", false); - LOG_INFO(logger, "lazy example logging fox {} {} {} {} {} {} {}", 7UL, 6LL, 3.0, false, 5L, - std::string("str2"), true); - LOG_INFO(logger, "fox over brown lazy {} {} {} {} {}", 3.0, 6LL, true, std::string_view("view2"), - "example3"); - LOG_INFO(logger, "test fox quick {} {} {} {} {} {} {} {} {}", "example2", 4.0f, std::string("str2"), - static_cast(10), 6LL, 5L, static_cast(9), false, true); - LOG_INFO(logger, "brown quick lazy dog {} {} {} {} {} {}", static_cast(9), "example1", 2, - 4.0f, 8ULL, 7UL); - LOG_INFO(logger, "example dog logging {} {}", true, "example1"); - LOG_INFO(logger, "logging example jumps over {} {} {} {}", 4.0f, static_cast(10), - "example2", static_cast(9)); - LOG_INFO(logger, "lazy brown example test {} {} {} {} {} {}", true, 1, static_cast(9), - 8ULL, 3.0, std::string("str1")); - LOG_INFO(logger, "test example jumps {} {} {} {} {}", "example3", 4.0f, true, std::string_view("view1"), 6LL); - LOG_INFO(logger, "fox quick over {} {} {} {} {} {} {}", 3.0, std::string_view("view1"), 2, 8ULL, - 7UL, true, "example3"); - LOG_INFO(logger, "test logging jumps brown {}", 1); - LOG_INFO(logger, "jumps lazy logging quick {}", "example2"); - LOG_INFO(logger, "lazy quick dog logging {} {} {} {} {} {}", "example3", 5L, "example1", 3.0, - std::string("str2"), std::string("str1")); - LOG_INFO(logger, "example test logging {} {}", std::string_view("view2"), "example1"); - LOG_INFO(logger, "brown logging dog fox {} {} {} {} {} {} {} {} {} {}", 1, static_cast(9), - "example2", 7UL, 8ULL, std::string("str2"), "example3", 5L, 2, 6LL); - LOG_INFO(logger, "logging lazy dog {} {} {}", std::string("str1"), "example2", "example1"); - LOG_INFO(logger, "test lazy fox brown {} {} {}", static_cast(9), std::string_view("view1"), - static_cast(10)); - LOG_INFO(logger, "over test example fox {}", std::string_view("view2")); - LOG_INFO(logger, "fox test lazy {}", std::string("str2")); - LOG_INFO(logger, "over test dog {} {} {} {}", std::string("str2"), 7UL, std::string("str1"), 8ULL); - LOG_INFO(logger, "fox example brown {} {} {} {} {} {} {} {} {}", true, std::string("str1"), 1, - std::string_view("view1"), "example2", "example1", std::string_view("view2"), 6LL, 7UL); - LOG_INFO(logger, "test jumps fox example {} {} {} {} {} {} {} {}", static_cast(10), - "example3", static_cast(9), 5L, std::string("str2"), 8ULL, true, 7UL); - LOG_INFO(logger, "fox jumps over {} {} {} {} {} {} {} {}", 5L, std::string_view("view1"), 4.0f, - 8ULL, "example2", std::string("str1"), "example3", static_cast(9)); - LOG_INFO(logger, "jumps fox logging lazy {} {} {} {} {} {} {} {}", "example2", 3.0, 5L, - std::string("str2"), 2, 6LL, 8ULL, 1); - LOG_INFO(logger, "quick lazy dog example {}", static_cast(9)); - LOG_INFO(logger, "jumps example lazy {} {} {} {} {} {} {} {} {}", 1, 3.0, 4.0f, true, 5L, 8ULL, - "example3", std::string_view("view1"), 7UL); - LOG_INFO(logger, "over test quick {} {} {}", static_cast(9), 2, 5L); - LOG_INFO(logger, "jumps fox lazy {} {} {} {} {}", "example2", 3.0, "example3", - std::string_view("view1"), std::string_view("view2")); - LOG_INFO(logger, "jumps dog test {} {} {} {} {} {} {}", false, 7UL, std::string("str2"), 8ULL, - std::string_view("view2"), 6LL, std::string("str1")); - LOG_INFO(logger, "fox quick brown {} {} {} {}", 7UL, "example2", std::string_view("view1"), 5L); - LOG_INFO(logger, "over quick jumps {} {} {} {} {} {} {} {} {}", 4.0f, 6LL, static_cast(9), - 3.0, "example2", std::string("str1"), "example3", "example1", std::string_view("view1")); - LOG_INFO(logger, "lazy jumps over fox {} {} {} {} {} {} {} {} {}", std::string_view("view2"), 1, - 3.0, static_cast(10), std::string("str2"), "example2", - static_cast(9), true, 6LL); - LOG_INFO(logger, "jumps dog brown example {} {} {} {} {} {}", 8ULL, 6LL, std::string("str2"), - "example2", false, 4.0f); - LOG_INFO(logger, "test fox jumps logging {} {} {} {} {} {} {} {} {} {}", false, "example2", 4.0f, - std::string("str1"), "example3", true, std::string_view("view2"), 1, std::string("str2"), - static_cast(10)); - LOG_INFO(logger, "logging test example over {}", false); - LOG_INFO(logger, "jumps brown dog {}", 5L); - LOG_INFO(logger, "dog lazy brown quick {} {} {} {} {} {} {} {} {} {}", std::string("str2"), - std::string("str1"), "example3", 8ULL, std::string_view("view1"), "example1", "example2", - false, 6LL, static_cast(9)); - LOG_INFO(logger, "lazy fox brown {} {} {}", std::string_view("view2"), static_cast(10), 5L); - LOG_INFO(logger, "jumps brown lazy {} {} {} {} {} {} {}", std::string_view("view1"), - static_cast(9), 1, 2, std::string("str1"), 4.0f, static_cast(10)); - LOG_INFO(logger, "jumps lazy fox {} {} {} {} {} {} {} {} {} {}", static_cast(10), - 3.0, 2, std::string("str2"), 6LL, "example2", "example3", true, 4.0f, std::string("str1")); - LOG_INFO(logger, "test logging dog {} {} {} {} {} {}", false, std::string_view("view2"), 3.0, 6LL, - "example1", 2); - LOG_INFO(logger, "dog logging example fox {} {} {} {} {} {} {} {} {}", false, static_cast(9), - std::string("str1"), static_cast(10), 6LL, true, 1, 3.0, std::string("str2")); - LOG_INFO(logger, "fox test lazy {} {} {} {} {} {} {}", static_cast(10), - std::string("str2"), 2, true, 3.0, static_cast(9), std::string_view("view2")); - LOG_INFO(logger, "dog test over {} {} {}", std::string_view("view1"), 2, static_cast(9)); - LOG_INFO(logger, "fox example test {} {} {} {} {} {} {}", 5L, std::string_view("view1"), - "example3", 8ULL, std::string("str1"), true, 7UL); - LOG_INFO(logger, "dog over quick {} {} {} {}", "example3", 2, std::string_view("view1"), - static_cast(10)); - LOG_INFO(logger, "lazy example over {} {}", 4.0f, true); - LOG_INFO(logger, "over brown jumps fox {} {} {} {} {} {} {} {}", "example1", std::string_view("view2"), - 2, static_cast(9), std::string("str2"), 5L, std::string("str1"), 1); - LOG_INFO(logger, "over dog fox quick {} {} {} {} {} {}", static_cast(9), false, - std::string("str2"), 8ULL, "example2", "example3"); - LOG_INFO(logger, "fox quick jumps example {} {} {} {} {}", 2, "example3", static_cast(9), - std::string_view("view2"), std::string("str1")); - LOG_INFO(logger, "test fox logging {} {} {} {} {} {}", "example2", 4.0f, - static_cast(10), 6LL, "example3", std::string("str1")); - LOG_INFO(logger, "quick logging lazy {} {} {} {} {} {} {} {} {}", 1, 8ULL, 4.0f, 6LL, - std::string("str2"), std::string_view("view1"), 2, true, false); - LOG_INFO(logger, "example lazy quick fox {} {} {} {} {} {} {} {} {} {}", false, 7UL, 3.0, true, - 6LL, 5L, 8ULL, 1, "example1", std::string_view("view1")); - LOG_INFO(logger, "jumps example over {} {} {} {} {}", true, 2, std::string("str1"), - std::string_view("view2"), 3.0); - LOG_INFO(logger, "test dog jumps fox {} {} {} {} {}", "example2", "example1", 4.0f, 5L, 3.0); - LOG_INFO(logger, "brown over jumps {}", 8ULL); - LOG_INFO(logger, "test jumps quick {} {} {}", 1, 5L, "example1"); - LOG_INFO(logger, "example test jumps brown {} {} {}", static_cast(10), 5L, - "example2"); - LOG_INFO(logger, "dog brown test lazy {} {} {} {} {} {} {}", std::string("str2"), 7UL, "example2", - 5L, 2, false, "example3"); - LOG_INFO(logger, "example fox dog over {} {} {} {} {} {} {} {}", true, 3.0, 8ULL, "example3", 1, - std::string("str2"), static_cast(9), 7UL); - LOG_INFO(logger, "over dog jumps {} {}", std::string_view("view2"), static_cast(10)); - LOG_INFO(logger, "lazy quick jumps {} {} {} {} {} {} {}", static_cast(9), 1, 2, false, - 4.0f, std::string_view("view1"), 3.0); - LOG_INFO(logger, "over quick test logging {} {} {} {} {} {} {} {} {}", 2, std::string("str1"), - 7UL, 5L, "example2", true, "example1", std::string("str2"), 4.0f); - LOG_INFO(logger, "over test logging {} {} {} {} {} {} {} {} {}", 5L, 4.0f, std::string_view("view1"), - std::string_view("view2"), 3.0, std::string("str1"), "example3", 8ULL, 1); - LOG_INFO(logger, "test lazy logging dog {} {}", 7UL, "example3"); - LOG_INFO(logger, "example fox lazy logging {} {} {} {} {} {} {} {} {}", 1, 8ULL, 3.0, - std::string_view("view2"), "example3", std::string_view("view1"), true, - static_cast(10), "example2"); - LOG_INFO(logger, "dog over test {} {} {}", 1, 8ULL, std::string_view("view1")); - LOG_INFO(logger, "dog logging test brown {} {} {}", std::string_view("view1"), 5L, - static_cast(10)); - LOG_INFO(logger, "fox quick over example {} {} {}", static_cast(10), "example3", true); - LOG_INFO(logger, "lazy jumps example {} {} {}", 8ULL, 3.0, true); - LOG_INFO(logger, "quick logging test {} {} {} {} {} {} {} {}", 3.0, std::string_view("view1"), 1, - true, std::string_view("view2"), static_cast(9), std::string("str2"), 4.0f); - LOG_INFO(logger, "quick dog fox example {}", 5L); - LOG_INFO(logger, "lazy fox brown {} {} {} {} {} {}", true, "example1", 3.0, "example3", 7UL, - std::string("str1")); - LOG_INFO(logger, "fox jumps quick test {} {} {} {} {}", std::string("str2"), - std::string_view("view2"), static_cast(9), "example2", 6LL); - LOG_INFO(logger, "brown logging fox {} {} {} {} {} {} {} {} {} {}", 2, std::string_view("view2"), - "example2", std::string("str1"), "example1", 7UL, 6LL, false, 3.0, "example3"); - LOG_INFO(logger, "dog lazy over logging {} {} {} {}", std::string("str2"), 1, - std::string_view("view1"), std::string_view("view2")); - LOG_INFO(logger, "dog test over {} {} {} {}", std::string_view("view2"), 5L, "example1", - static_cast(10)); - LOG_INFO(logger, "dog example quick logging {} {} {}", 3.0, std::string_view("view1"), 8ULL); - LOG_INFO(logger, "dog lazy test {} {} {} {} {} {} {}", true, static_cast(9), - std::string_view("view1"), 2, false, std::string("str2"), 5L); - LOG_INFO(logger, "test jumps quick {} {} {}", std::string("str1"), 1, std::string_view("view1")); - LOG_INFO(logger, "example lazy brown {} {} {} {} {} {} {}", std::string("str2"), std::string_view("view1"), - 2, static_cast(10), 1, std::string_view("view2"), 8ULL); - LOG_INFO(logger, "test example fox {} {} {} {} {} {} {}", "example1", "example3", true, 8ULL, - static_cast(10), 6LL, false); - LOG_INFO(logger, "test brown over fox {} {} {} {} {} {}", "example1", std::string_view("view1"), - 8ULL, static_cast(9), 6LL, false); - LOG_INFO(logger, "jumps dog test logging {} {}", "example1", 4.0f); - LOG_INFO(logger, "fox quick lazy jumps {} {} {}", false, 6LL, 1); - LOG_INFO(logger, "fox brown test lazy {} {} {} {} {} {} {}", static_cast(9), - std::string_view("view2"), "example3", std::string("str2"), std::string_view("view1"), false, true); - LOG_INFO(logger, "jumps fox brown lazy {} {} {} {} {} {} {} {}", static_cast(10), - 2, "example1", true, static_cast(9), std::string_view("view2"), "example3", 6LL); - LOG_INFO(logger, "logging lazy jumps test {} {} {} {} {}", 7UL, std::string_view("view2"), 8ULL, - "example1", static_cast(9)); - LOG_INFO(logger, "jumps logging test {} {} {} {} {} {} {} {}", 2, false, 5L, 6LL, 7UL, 8ULL, 4.0f, - std::string("str2")); - LOG_INFO(logger, "fox quick brown test {} {} {} {} {} {}", "example2", 7UL, - static_cast(10), false, "example3", std::string_view("view2")); - LOG_INFO(logger, "brown logging lazy {} {} {} {} {} {}", false, std::string_view("view1"), - std::string("str1"), std::string_view("view2"), 3.0, "example1"); - LOG_INFO(logger, "test fox dog {} {} {}", std::string_view("view2"), 6LL, static_cast(10)); - LOG_INFO(logger, "dog over jumps {} {} {} {} {} {}", true, 3.0, "example1", "example3", 1, 2); - LOG_INFO(logger, "fox example over {} {} {}", "example3", 8ULL, 6LL); - LOG_INFO(logger, "logging test example {} {} {} {}", std::string_view("view1"), 7UL, 3.0, 2); - LOG_INFO(logger, "jumps test dog {} {} {}", 1, 3.0, 2); - LOG_INFO(logger, "brown test logging fox {} {} {} {} {} {} {} {}", 8ULL, 4.0f, 7UL, - std::string("str2"), std::string_view("view1"), "example3", false, 6LL); - LOG_INFO(logger, "quick dog over {} {} {} {} {} {} {} {}", true, 5L, 4.0f, "example1", false, - "example2", static_cast(10), 3.0); - LOG_INFO(logger, "over quick logging {} {} {}", 6LL, static_cast(10), 3.0); - LOG_INFO(logger, "brown over lazy logging {} {} {} {} {} {}", "example2", "example1", 7UL, 4.0f, - std::string_view("view2"), "example3"); - LOG_INFO(logger, "lazy quick jumps {} {} {} {} {} {} {}", 3.0, 5L, false, 6LL, - std::string_view("view2"), "example1", static_cast(10)); - LOG_INFO(logger, "over brown dog logging {} {}", "example3", "example1"); - LOG_INFO(logger, "lazy example jumps {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - "example1", 6LL, "example3", false, static_cast(9), "example2", std::string("str2"), 8ULL); - LOG_INFO(logger, "brown logging dog fox {} {} {}", std::string_view("view2"), 3.0, 2); - LOG_INFO(logger, "over test brown {} {} {} {} {} {} {} {}", std::string("str2"), 7UL, false, true, - 1, 5L, std::string_view("view2"), static_cast(10)); - LOG_INFO(logger, "fox brown logging {} {} {} {} {} {} {} {}", 2, false, 6LL, 1, 4.0f, - std::string_view("view1"), "example1", static_cast(9)); - LOG_INFO(logger, "jumps dog quick {} {} {} {} {} {} {}", std::string("str1"), 7UL, true, 4.0f, 5L, 2, 3.0); - LOG_INFO(logger, "example over lazy quick {} {} {} {} {} {} {}", 6LL, 8ULL, true, - static_cast(10), 4.0f, 2, std::string("str2")); - LOG_INFO(logger, "brown test quick {} {} {} {} {}", 3.0, "example1", 7UL, static_cast(9), 5L); - LOG_INFO(logger, "test lazy jumps {} {} {} {} {} {} {} {} {} {}", 7UL, 1, std::string("str2"), - std::string_view("view1"), "example3", "example2", static_cast(10), 6LL, - 4.0f, std::string("str1")); - LOG_INFO(logger, "logging over quick test {} {} {} {} {} {} {} {} {} {}", true, std::string("str1"), - 5L, 6LL, 3.0, std::string_view("view2"), 8ULL, static_cast(10), false, 2); - LOG_INFO(logger, "jumps brown logging {} {} {} {}", "example1", std::string("str1"), - std::string_view("view1"), 7UL); - LOG_INFO(logger, "test fox dog quick {} {} {} {} {} {} {} {} {}", static_cast(10), - 6LL, std::string("str1"), 2, true, "example1", std::string_view("view2"), false, 3.0); - LOG_INFO(logger, "fox dog logging {} {} {}", false, std::string("str1"), static_cast(10)); - LOG_INFO(logger, "lazy brown logging over {} {}", 7UL, std::string("str1")); - LOG_INFO(logger, "quick brown lazy over {}", "example3"); - LOG_INFO(logger, "over logging test {} {} {} {} {} {}", std::string_view("view2"), - static_cast(9), 2, std::string("str1"), 7UL, true); - LOG_INFO(logger, "over quick dog jumps {} {} {}", static_cast(9), "example2", - std::string_view("view1")); - LOG_INFO(logger, "example test fox lazy {} {} {} {} {} {} {} {} {} {}", 6LL, 1, true, - std::string_view("view1"), static_cast(9), std::string_view("view2"), - std::string("str1"), 8ULL, "example3", false); - LOG_INFO(logger, "example fox quick over {} {} {} {} {} {} {} {} {}", 7UL, static_cast(9), - static_cast(10), "example2", true, 5L, 4.0f, 2, 8ULL); - LOG_INFO(logger, "quick lazy test brown {} {} {} {} {} {} {} {} {}", 8ULL, 6LL, 3.0, - std::string("str1"), 2, 5L, "example3", false, 1); - LOG_INFO(logger, "example dog jumps lazy {}", std::string_view("view2")); - LOG_INFO(logger, "fox over quick {} {} {} {} {} {} {} {} {}", 7UL, static_cast(9), - std::string_view("view1"), std::string("str2"), static_cast(10), - "example1", 1, 8ULL, true); - LOG_INFO(logger, "over jumps brown example {} {} {} {} {} {}", std::string_view("view1"), 2, - "example1", 6LL, static_cast(10), 5L); - LOG_INFO(logger, "fox test over jumps {} {} {} {} {} {} {} {} {} {}", "example2", "example1", 7UL, - "example3", 8ULL, std::string_view("view1"), 2, std::string("str2"), std::string("str1"), false); - LOG_INFO(logger, "logging jumps lazy {} {} {} {} {}", std::string("str2"), "example3", 6LL, - "example2", std::string("str1")); - LOG_INFO(logger, "example jumps logging {}", 8ULL); - LOG_INFO(logger, "logging test over {}", "example1"); - LOG_INFO(logger, "logging lazy test {} {} {} {} {} {} {} {} {}", "example2", 1, - static_cast(10), std::string_view("view2"), 3.0, static_cast(9), - 7UL, 5L, 8ULL); - LOG_INFO(logger, "logging dog test {} {} {}", std::string_view("view2"), 2, false); - LOG_INFO(logger, "jumps example test {} {} {} {} {}", 1, true, 2, std::string("str2"), "example3"); - LOG_INFO(logger, "jumps example brown {}", "example2"); - LOG_INFO(logger, "logging fox quick lazy {}", static_cast(9)); - LOG_INFO(logger, "logging over test jumps {} {} {} {}", std::string_view("view1"), 8ULL, - std::string_view("view2"), std::string("str2")); - LOG_INFO(logger, "quick test jumps {} {} {} {} {}", std::string("str2"), "example1", "example2", 8ULL, 1); - LOG_INFO(logger, "test lazy dog brown {} {} {}", 2, static_cast(9), 8ULL); - LOG_INFO(logger, "test quick over {} {}", std::string("str2"), "example1"); - LOG_INFO(logger, "quick dog fox {} {} {}", 5L, 8ULL, "example3"); - LOG_INFO(logger, "test lazy fox {} {}", std::string("str1"), std::string("str2")); - LOG_INFO(logger, "example brown dog {} {} {} {} {} {} {} {} {} {}", 4.0f, std::string("str2"), - "example1", 1, 5L, "example2", std::string_view("view2"), static_cast(9), - std::string("str1"), 7UL); - LOG_INFO(logger, "brown test example dog {} {} {} {} {}", "example3", false, - std::string_view("view2"), std::string_view("view1"), 3.0); - LOG_INFO(logger, "dog over lazy quick {} {} {} {} {} {} {} {} {} {}", 2, 6LL, - static_cast(9), std::string_view("view2"), std::string_view("view1"), - std::string("str1"), true, "example2", false, static_cast(10)); - LOG_INFO(logger, "brown lazy example {} {} {}", static_cast(9), true, 7UL); - LOG_INFO(logger, "jumps quick dog {} {}", std::string("str1"), 3.0); - LOG_INFO(logger, "brown test over quick {} {} {} {} {} {} {}", 3.0, true, std::string("str2"), - std::string_view("view2"), 7UL, static_cast(9), "example1"); - LOG_INFO(logger, "brown over example logging {} {} {} {} {}", 7UL, true, "example1", - std::string_view("view2"), 8ULL); - LOG_INFO(logger, "quick example test brown {} {} {} {} {} {} {} {} {} {}", std::string("str1"), - std::string_view("view2"), 2, 5L, "example1", 1, 6LL, 8ULL, "example3", 7UL); - LOG_INFO(logger, "lazy over logging {} {} {} {} {} {} {} {} {}", static_cast(10), 1, - 7UL, std::string_view("view1"), "example3", 8ULL, static_cast(9), "example2", 3.0); - LOG_INFO(logger, "test quick lazy {} {} {} {} {} {}", false, "example3", 6LL, 5L, "example1", - std::string_view("view2")); - LOG_INFO(logger, "dog logging fox {} {} {}", 4.0f, std::string("str1"), 2); - LOG_INFO(logger, "lazy logging example jumps {} {} {}", static_cast(10), - std::string("str1"), 3.0); - LOG_INFO(logger, "dog jumps test {} {} {} {} {} {}", "example2", std::string("str1"), 4.0f, - static_cast(9), "example1", std::string_view("view1")); - LOG_INFO(logger, "example jumps logging over {} {} {} {}", 7UL, "example1", std::string("str2"), - "example2"); - LOG_INFO(logger, "quick fox lazy {} {} {} {} {} {} {}", 1, 6LL, 3.0, 5L, - static_cast(10), 2, std::string("str2")); - LOG_INFO(logger, "quick jumps test {} {} {} {} {} {} {} {} {}", std::string_view("view1"), 3.0, - 6LL, "example2", 7UL, true, std::string_view("view2"), static_cast(9), false); - LOG_INFO(logger, "jumps example quick lazy {} {}", false, std::string("str2")); - LOG_INFO(logger, "test brown quick {} {} {}", std::string("str2"), std::string("str1"), 4.0f); - LOG_INFO(logger, "lazy brown dog {} {} {} {} {} {}", std::string("str1"), 8ULL, "example2", 2, 7UL, false); - LOG_INFO(logger, "fox over dog lazy {} {} {}", 5L, 3.0, std::string("str1")); - LOG_INFO(logger, "over test quick jumps {} {} {} {} {} {}", std::string_view("view1"), "example3", - std::string("str2"), 8ULL, std::string("str1"), std::string_view("view2")); - LOG_INFO(logger, "quick test dog {} {} {} {} {} {} {} {} {} {}", 1, - static_cast(10), "example3", false, true, static_cast(9), 6LL, - std::string_view("view1"), "example1", 2); - LOG_INFO(logger, "over brown test jumps {} {} {} {} {} {} {} {}", std::string_view("view2"), 7UL, - std::string("str1"), static_cast(10), 4.0f, std::string_view("view1"), false, true); - LOG_INFO(logger, "test lazy jumps over {} {}", 1, static_cast(10)); - LOG_INFO(logger, "brown dog lazy {} {} {} {}", std::string_view("view1"), - static_cast(10), 7UL, true); - LOG_INFO(logger, "logging example dog over {}", std::string("str1")); - LOG_INFO(logger, "fox brown lazy logging {} {} {} {} {} {} {} {} {} {}", 2, 6LL, 4.0f, "example3", - std::string_view("view1"), "example2", true, 1, false, static_cast(10)); - LOG_INFO(logger, "over brown dog lazy {} {} {} {}", 6LL, 8ULL, std::string_view("view1"), 2); - LOG_INFO(logger, "lazy logging test {} {}", 2, "example1"); - LOG_INFO(logger, "quick fox jumps test {} {} {} {} {} {} {}", static_cast(10), - true, std::string_view("view1"), false, "example1", std::string_view("view2"), 1); - LOG_INFO(logger, "jumps test dog brown {} {} {} {} {} {} {}", 1, std::string("str2"), "example3", - std::string_view("view1"), static_cast(10), std::string("str1"), false); - LOG_INFO(logger, "example quick logging {} {} {} {} {}", 5L, static_cast(9), false, 2, - "example1"); - LOG_INFO(logger, "dog example fox test {} {} {} {} {} {} {}", 3.0, "example3", - std::string_view("view2"), false, 5L, 4.0f, "example2"); - LOG_INFO(logger, "dog lazy jumps {} {} {} {} {} {} {} {} {} {}", static_cast(10), - 3.0, "example2", "example1", 1, 6LL, 5L, 8ULL, 2, std::string_view("view2")); - LOG_INFO(logger, "fox over jumps quick {} {} {} {} {}", true, 3.0, static_cast(9), - std::string_view("view2"), 8ULL); - LOG_INFO(logger, "lazy jumps logging {} {}", std::string_view("view2"), 1); - LOG_INFO(logger, "quick logging over {} {} {} {} {} {}", 5L, std::string_view("view1"), 1, - std::string_view("view2"), false, 2); - LOG_INFO(logger, "logging over jumps example {}", std::string("str1")); - LOG_INFO(logger, "jumps example fox {} {}", 3.0, "example1"); - LOG_INFO(logger, "brown dog lazy {} {} {} {} {} {} {}", 5L, false, 7UL, "example2", - std::string_view("view1"), static_cast(9), "example3"); - LOG_INFO(logger, "lazy example over test {} {} {} {} {} {} {} {}", std::string("str1"), - std::string_view("view2"), "example1", std::string_view("view1"), "example3", 6LL, - "example2", 2); - LOG_INFO(logger, "quick logging fox brown {} {} {} {} {} {} {} {} {}", 3.0, 4.0f, - static_cast(9), 5L, false, 6LL, std::string("str1"), 1, std::string_view("view1")); - LOG_INFO(logger, "over example quick fox {} {} {} {} {}", false, 7UL, - static_cast(10), "example1", static_cast(9)); - LOG_INFO(logger, "jumps dog lazy {} {} {} {}", std::string("str1"), "example3", 1, std::string_view("view1")); - LOG_INFO(logger, "brown dog quick {} {} {} {} {} {} {} {}", std::string("str2"), 1, static_cast(9), - "example3", static_cast(10), 3.0, std::string_view("view2"), 4.0f); - LOG_INFO(logger, "jumps lazy quick {} {}", false, 1); - LOG_INFO(logger, "quick logging lazy {} {} {} {} {} {} {} {} {} {}", std::string("str1"), 8ULL, - 4.0f, 6LL, false, 1, static_cast(9), true, std::string_view("view2"), "example1"); - LOG_INFO(logger, "brown example fox {} {} {} {}", "example2", 8ULL, 3.0, 6LL); - LOG_INFO(logger, "dog over test {} {} {} {} {} {} {} {} {}", 5L, false, "example1", 1, 7UL, - static_cast(10), 8ULL, static_cast(9), 4.0f); - LOG_INFO(logger, "test fox logging quick {}", "example2"); - LOG_INFO(logger, "lazy brown example quick {} {} {} {} {}", std::string_view("view1"), true, 5L, - std::string("str1"), static_cast(10)); - LOG_INFO(logger, "example dog jumps logging {} {} {} {} {} {} {} {}", 5L, 8ULL, 4.0f, - static_cast(10), std::string("str2"), static_cast(9), 6LL, false); - LOG_INFO(logger, "over test brown {} {} {}", 2, 4.0f, 3.0); - LOG_INFO(logger, "over example brown quick {}", 5L); - LOG_INFO(logger, "over example jumps lazy {} {}", std::string_view("view1"), - static_cast(10)); - LOG_INFO(logger, "fox lazy over logging {} {} {} {} {} {}", 3.0, std::string_view("view1"), true, - 5L, 1, std::string("str1")); - LOG_INFO(logger, "test jumps example logging {} {} {} {} {} {} {} {}", "example2", 5L, 7UL, 6LL, - std::string_view("view1"), "example3", "example1", std::string("str2")); - LOG_INFO(logger, "brown dog fox {} {} {}", true, std::string("str1"), 5L); - LOG_INFO(logger, "example brown over {} {} {} {} {}", std::string_view("view1"), "example2", 2, - std::string_view("view2"), 6LL); - LOG_INFO(logger, "fox dog test {} {} {} {}", static_cast(10), std::string("str1"), 8ULL, true); - LOG_INFO(logger, "example quick lazy {} {}", 2, 1); - LOG_INFO(logger, "jumps fox over {} {}", static_cast(9), true); - LOG_INFO(logger, "dog logging over lazy {} {} {}", "example1", std::string("str1"), 4.0f); - LOG_INFO(logger, "quick dog lazy example {} {} {}", 3.0, 5L, 7UL); - LOG_INFO(logger, "over fox quick {} {} {} {} {} {} {} {} {}", 4.0f, static_cast(10), - std::string_view("view1"), "example1", false, std::string("str1"), 6LL, 3.0, 1); - LOG_INFO(logger, "lazy example logging quick {} {}", std::string("str2"), 1); - LOG_INFO(logger, "jumps fox dog test {} {} {} {}", 3.0, "example2", 8ULL, 5L); - LOG_INFO(logger, "quick example logging {} {} {} {} {}", std::string_view("view2"), 3.0, 8ULL, - std::string("str2"), 5L); - LOG_INFO(logger, "lazy example test over {} {} {} {} {} {}", 8ULL, 3.0, 1, - std::string_view("view2"), std::string("str2"), "example1"); - LOG_INFO(logger, "dog example jumps {} {} {} {} {} {} {} {}", static_cast(9), 7UL, 8ULL, - "example1", 5L, "example3", 6LL, std::string("str1")); - LOG_INFO(logger, "test jumps logging quick {} {} {}", std::string_view("view1"), 5L, false); - LOG_INFO(logger, "fox jumps over {} {} {} {} {} {} {} {} {} {}", std::string("str2"), - static_cast(9), std::string_view("view2"), 1, "example1", "example3", - static_cast(10), 3.0, 5L, "example2"); - LOG_INFO(logger, "dog logging jumps test {} {} {} {} {} {} {} {} {}", "example3", 8ULL, - "example1", 6LL, std::string("str2"), static_cast(10), 2, 1, false); - LOG_INFO(logger, "quick fox jumps {} {} {} {} {} {} {} {}", true, 6LL, std::string_view("view1"), - 8ULL, static_cast(10), "example2", 1, 2); - LOG_INFO(logger, "jumps over test logging {} {} {} {} {} {}", std::string("str2"), static_cast(9), - std::string_view("view1"), "example3", "example2", std::string_view("view2")); - LOG_INFO(logger, "example brown fox dog {} {} {} {} {}", 2, true, 1, 6LL, std::string("str2")); - LOG_INFO(logger, "jumps dog example {} {} {} {} {} {} {} {} {}", 8ULL, 2, std::string_view("view2"), - 1, std::string("str1"), "example3", "example2", static_cast(10), true); - LOG_INFO(logger, "example over brown {} {} {} {} {} {} {} {} {} {}", "example3", - std::string_view("view1"), 5L, 4.0f, std::string("str1"), 6LL, true, "example2", 2, 8ULL); - LOG_INFO(logger, "dog brown quick example {} {} {} {} {} {} {} {} {} {}", 7UL, "example3", true, - 8ULL, 1, 4.0f, false, 3.0, std::string("str1"), "example1"); - LOG_INFO(logger, "jumps lazy logging {} {} {} {} {}", 6LL, 8ULL, 7UL, std::string("str1"), - std::string("str2")); - LOG_INFO(logger, "example quick jumps {} {} {} {} {} {} {} {}", 1, 6LL, std::string_view("view2"), - "example1", std::string("str2"), std::string("str1"), 5L, false); - LOG_INFO(logger, "test dog jumps over {} {} {} {} {} {} {} {} {}", "example1", - std::string_view("view2"), 6LL, 8ULL, true, "example3", 2, 1, std::string("str1")); - LOG_INFO(logger, "brown dog fox {} {} {} {} {} {} {} {}", 2, 5L, static_cast(9), - "example1", 3.0, "example3", false, std::string("str1")); - LOG_INFO(logger, "over jumps lazy {} {} {} {} {} {} {} {}", static_cast(9), 2, 1, true, - 3.0, 8ULL, 4.0f, std::string_view("view1")); - LOG_INFO(logger, "example brown test {} {} {} {} {} {}", 7UL, 6LL, std::string("str1"), - "example2", std::string_view("view1"), static_cast(10)); - LOG_INFO(logger, "jumps brown over fox {} {}", 7UL, 1); - LOG_INFO(logger, "lazy example over {} {} {} {} {} {} {} {}", true, false, 6LL, - std::string_view("view1"), std::string("str2"), std::string_view("view2"), "example2", 3.0); - LOG_INFO(logger, "logging example dog fox {} {} {} {}", 1, std::string_view("view1"), - std::string("str2"), 4.0f); - LOG_INFO(logger, "fox lazy brown quick {} {} {} {} {}", 3.0, false, std::string_view("view1"), - "example2", true); - LOG_INFO(logger, "test fox dog quick {} {} {} {}", "example2", "example3", 3.0, static_cast(9)); - LOG_INFO(logger, "jumps dog test {} {} {} {} {}", 5L, 7UL, true, 1, std::string("str1")); - LOG_INFO(logger, "quick jumps fox lazy {} {} {} {}", false, true, std::string("str1"), "example2"); - LOG_INFO(logger, "jumps lazy over fox {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - "example1", 1, 3.0, std::string("str1"), true, "example2", "example3", static_cast(9)); - LOG_INFO(logger, "brown fox lazy {} {} {} {} {} {}", true, static_cast(10), 6LL, - "example3", static_cast(9), std::string_view("view1")); - LOG_INFO(logger, "brown fox over {} {} {} {} {} {} {} {}", static_cast(9), std::string("str1"), - std::string("str2"), 5L, 1, 6LL, std::string_view("view1"), "example1"); - LOG_INFO(logger, "logging dog over brown {} {} {} {} {} {} {}", "example1", 2, "example2", - std::string("str2"), 3.0, 4.0f, 8ULL); - LOG_INFO(logger, "lazy fox logging {}", 7UL); - LOG_INFO(logger, "quick example logging {} {} {}", false, std::string("str1"), std::string_view("view1")); - LOG_INFO(logger, "quick dog test {} {} {} {}", "example3", 1, 3.0, 7UL); - LOG_INFO(logger, "example lazy logging {} {} {} {} {} {} {} {}", 1, static_cast(9), - "example2", static_cast(10), 3.0, 2, "example3", 8ULL); - LOG_INFO(logger, "dog fox example {} {}", static_cast(10), "example1"); - LOG_INFO(logger, "lazy example jumps brown {} {} {} {}", 5L, "example2", 6LL, 3.0); - LOG_INFO(logger, "jumps lazy quick {} {} {} {} {} {} {} {} {}", 5L, 6LL, 8ULL, - std::string("str1"), static_cast(10), std::string_view("view2"), - std::string("str2"), "example3", 4.0f); - LOG_INFO(logger, "over test quick {} {} {}", std::string("str1"), std::string_view("view2"), - "example3"); - LOG_INFO(logger, "example test brown over {} {} {} {} {} {} {} {}", static_cast(10), - 8ULL, std::string_view("view1"), 6LL, static_cast(9), "example1", 5L, true); - LOG_INFO(logger, "dog logging example {}", 4.0f); - LOG_INFO(logger, "example jumps dog over {} {} {} {} {} {} {} {}", "example1", "example2", true, - 6LL, std::string_view("view2"), 2, false, std::string("str1")); - LOG_INFO(logger, "test example dog jumps {} {} {} {} {} {} {}", 1, std::string_view("view1"), 2, - "example1", static_cast(9), 3.0, 6LL); - LOG_INFO(logger, "jumps fox dog {} {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - std::string_view("view1"), "example3", 6LL, 5L, 2, true, 4.0f, 1, "example2"); - LOG_INFO(logger, "fox quick over jumps {} {} {} {} {} {} {} {}", 7UL, 2, "example3", "example1", - true, std::string_view("view1"), 5L, 1); - LOG_INFO(logger, "test quick logging brown {} {}", true, "example2"); - LOG_INFO(logger, "quick jumps logging {} {} {} {} {}", 1, 7UL, 6LL, 3.0, static_cast(10)); - LOG_INFO(logger, "test logging fox quick {} {} {} {} {} {} {}", 3.0, std::string_view("view2"), - std::string("str1"), 4.0f, 8ULL, false, 2); - LOG_INFO(logger, "example quick logging brown {} {} {} {} {} {} {} {} {} {}", 3.0, 8ULL, std::string("str2"), - 4.0f, false, true, 6LL, static_cast(10), "example1", std::string("str1")); - LOG_INFO(logger, "jumps logging quick {} {}", std::string("str1"), 8ULL); - LOG_INFO(logger, "fox example lazy {} {} {} {} {} {}", std::string_view("view2"), 8ULL, 6LL, 4.0f, - true, "example2"); - LOG_INFO(logger, "over example logging {} {} {}", std::string("str1"), "example1", "example3"); - LOG_INFO(logger, "fox brown lazy over {} {} {} {} {} {} {}", 1, static_cast(9), 4.0f, - std::string("str2"), 6LL, 5L, "example1"); - LOG_INFO(logger, "jumps logging quick {} {} {} {} {} {} {} {} {} {}", - static_cast(10), std::string_view("view1"), std::string_view("view2"), - 5L, true, std::string("str2"), 4.0f, 8ULL, 3.0, "example2"); - LOG_INFO(logger, "over logging example {} {} {} {} {} {} {} {} {} {}", std::string("str1"), 3.0, - 2, false, 8ULL, 4.0f, 1, 6LL, std::string_view("view2"), std::string("str2")); - LOG_INFO(logger, "logging brown test fox {} {} {} {}", std::string("str2"), 3.0, std::string("str1"), 1); - LOG_INFO(logger, "example dog brown jumps {} {} {} {}", 1, "example2", 5L, false); - LOG_INFO(logger, "logging jumps example fox {} {} {} {} {} {} {}", 3.0, std::string_view("view2"), - true, static_cast(10), 5L, std::string_view("view1"), std::string("str1")); - LOG_INFO(logger, "fox brown lazy test {} {}", 2, 8ULL); - LOG_INFO(logger, "dog brown lazy fox {} {} {} {} {} {} {} {}", std::string_view("view2"), 1, 4.0f, - true, 7UL, "example3", 6LL, 5L); - LOG_INFO(logger, "lazy test dog {}", 3.0); - LOG_INFO(logger, "brown example jumps {}", 4.0f); - LOG_INFO(logger, "quick logging fox jumps {} {} {} {} {} {} {} {} {} {}", 1, - static_cast(9), std::string_view("view1"), std::string_view("view2"), true, 6LL, - false, std::string("str1"), 2, 7UL); - LOG_INFO(logger, "brown jumps test {}", 3.0); - LOG_INFO(logger, "jumps lazy quick {} {} {} {} {} {} {}", 8ULL, true, std::string_view("view1"), - false, std::string("str1"), "example1", std::string("str2")); - LOG_INFO(logger, "example logging quick over {} {} {} {}", std::string("str1"), 1, "example1", true); - LOG_INFO(logger, "example logging lazy over {} {} {} {} {} {} {} {} {}", "example2", 3.0, - std::string_view("view2"), static_cast(9), "example3", 2, std::string("str1"), - false, std::string_view("view1")); - LOG_INFO(logger, "dog fox example quick {} {} {}", std::string("str2"), true, static_cast(9)); - LOG_INFO(logger, "test quick example fox {} {} {} {} {}", true, 2, 5L, "example3", 1); - LOG_INFO(logger, "quick over jumps fox {} {} {} {} {}", 6LL, 8ULL, 4.0f, true, 5L); - LOG_INFO(logger, "example fox logging jumps {} {}", 6LL, 3.0); - LOG_INFO(logger, "quick jumps dog {} {} {}", 6LL, std::string_view("view2"), false); - LOG_INFO(logger, "lazy example quick {} {} {} {} {} {}", std::string("str2"), - static_cast(9), std::string("str1"), 6LL, true, 8ULL); - LOG_INFO(logger, "example logging over {} {} {} {} {}", std::string("str1"), 2, - static_cast(9), std::string_view("view2"), false); - LOG_INFO(logger, "test quick example {} {} {} {} {} {} {}", static_cast(10), 6LL, - static_cast(9), false, std::string_view("view2"), 8ULL, "example1"); - LOG_INFO(logger, "quick brown logging dog {} {} {} {} {} {} {}", 4.0f, 1, 2, - std::string_view("view2"), 8ULL, static_cast(9), 7UL); - LOG_INFO(logger, "logging lazy jumps {} {} {} {} {} {} {} {}", "example1", 5L, - static_cast(10), std::string("str2"), true, std::string_view("view2"), 4.0f, false); - LOG_INFO(logger, "over quick fox dog {} {} {} {} {} {} {} {} {}", 3.0, 1, false, 5L, 4.0f, 6LL, - static_cast(9), std::string_view("view2"), std::string_view("view1")); - LOG_INFO(logger, "brown fox test example {} {} {} {} {} {} {} {} {} {}", std::string("str2"), - true, static_cast(10), std::string_view("view1"), 5L, "example2", false, - 3.0, 1, std::string_view("view2")); - LOG_INFO(logger, "example lazy jumps fox {} {} {} {} {} {}", 7UL, false, - std::string_view("view1"), 6LL, "example2", 5L); - LOG_INFO(logger, "fox jumps over test {} {}", "example2", "example1"); - LOG_INFO(logger, "jumps dog logging {}", static_cast(10)); - LOG_INFO(logger, "fox test jumps {} {} {} {} {} {} {} {}", true, std::string_view("view2"), - std::string("str1"), 4.0f, 2, 6LL, std::string_view("view1"), std::string("str2")); - LOG_INFO(logger, "over quick brown {} {} {} {} {} {} {} {} {} {}", false, 8ULL, "example2", - "example3", "example1", std::string("str2"), static_cast(10), 4.0f, 5L, - std::string("str1")); - LOG_INFO(logger, "quick brown fox example {} {} {} {} {} {}", "example1", false, - static_cast(9), std::string("str1"), "example2", 4.0f); - LOG_INFO(logger, "test logging jumps quick {} {} {} {} {} {}", 4.0f, true, - std::string_view("view1"), "example1", 5L, 7UL); - LOG_INFO(logger, "test lazy example {} {}", 2, std::string("str2")); - LOG_INFO(logger, "quick over dog logging {} {} {} {} {} {} {} {} {} {}", 8ULL, std::string_view("view1"), - true, 6LL, "example2", 4.0f, "example1", static_cast(10), "example3", 7UL); - LOG_INFO(logger, "lazy jumps quick dog {} {} {}", std::string("str1"), "example2", false); - LOG_INFO(logger, "test brown logging example {} {}", std::string_view("view2"), 6LL); - LOG_INFO(logger, "over lazy dog jumps {} {} {} {} {} {}", std::string("str1"), 1, 4.0f, 6LL, 2, - "example3"); - LOG_INFO(logger, "lazy over fox {} {}", std::string_view("view2"), std::string_view("view1")); - LOG_INFO(logger, "brown dog lazy over {} {} {} {} {} {} {} {} {} {}", "example1", "example2", 7UL, - static_cast(10), 4.0f, false, 1, "example3", 2, std::string_view("view1")); - LOG_INFO(logger, "jumps example over {} {} {} {}", 8ULL, static_cast(10), - "example1", std::string_view("view1")); - LOG_INFO(logger, "test jumps over lazy {} {} {} {}", std::string("str2"), 2, 8ULL, std::string("str1")); - LOG_INFO(logger, "logging example over {} {}", std::string("str2"), static_cast(10)); - LOG_INFO(logger, "jumps lazy fox {} {} {} {} {} {}", 3.0, false, 5L, static_cast(9), - "example1", std::string("str2")); - LOG_INFO(logger, "dog example quick brown {} {} {} {} {} {} {} {}", 5L, static_cast(9), - "example3", true, false, std::string_view("view2"), 7UL, 8ULL); - LOG_INFO(logger, "dog over quick {} {} {} {} {} {}", static_cast(9), - static_cast(10), "example2", 5L, "example3", 2); - LOG_INFO(logger, "example test jumps {} {} {} {} {} {} {} {} {}", 8ULL, false, - std::string_view("view2"), true, "example3", "example1", static_cast(10), - std::string_view("view1"), "example2"); - LOG_INFO(logger, "example brown jumps quick {} {} {} {}", "example1", std::string("str1"), - static_cast(9), 8ULL); - LOG_INFO(logger, "jumps lazy dog {} {} {} {}", std::string_view("view2"), "example3", - std::string("str2"), 3.0); - LOG_INFO(logger, "dog lazy brown {} {}", 6LL, std::string("str1")); - LOG_INFO(logger, "test quick dog {} {} {} {} {} {} {}", "example2", std::string_view("view2"), - 6LL, static_cast(9), 1, std::string("str2"), 3.0); - LOG_INFO(logger, "quick fox lazy over {} {} {} {} {} {} {} {}", 4.0f, false, - std::string_view("view1"), 3.0, 8ULL, "example3", 6LL, "example2"); - LOG_INFO(logger, "brown fox jumps {}", "example3"); - LOG_INFO(logger, "logging quick fox {} {} {} {} {} {}", 1, std::string_view("view1"), - std::string("str2"), 5L, false, 6LL); - LOG_INFO(logger, "test dog over {}", 7UL); - LOG_INFO(logger, "fox test lazy {} {} {} {} {} {} {} {} {}", 3.0, true, 6LL, std::string_view("view2"), - "example2", static_cast(9), std::string_view("view1"), "example1", 4.0f); - LOG_INFO(logger, "example fox quick {} {} {} {} {} {} {}", 5L, 7UL, std::string_view("view1"), - "example3", "example2", "example1", static_cast(10)); - LOG_INFO(logger, "dog lazy jumps {} {} {} {} {} {} {} {} {}", true, std::string_view("view1"), - 7UL, 8ULL, static_cast(10), 1, 4.0f, 6LL, std::string("str2")); - LOG_INFO(logger, "logging example lazy test {}", true); - LOG_INFO(logger, "over quick test jumps {} {} {} {}", std::string("str2"), true, std::string("str1"), 3.0); - LOG_INFO(logger, "quick example over brown {} {} {} {} {} {} {} {}", "example3", false, - std::string_view("view2"), static_cast(10), 2, static_cast(9), 5L, 7UL); - LOG_INFO(logger, "example test dog {} {}", 3.0, "example2"); - LOG_INFO(logger, "jumps dog brown logging {} {} {} {}", std::string("str2"), std::string("str1"), - "example3", "example1"); - LOG_INFO(logger, "over logging lazy test {} {} {} {} {} {} {}", 6LL, true, std::string("str1"), - "example2", std::string_view("view2"), 4.0f, "example1"); - LOG_INFO(logger, "dog quick lazy test {} {} {} {} {} {} {} {} {}", 2, "example2", "example3", - std::string("str1"), static_cast(9), 4.0f, "example1", 6LL, 5L); - LOG_INFO(logger, "example test brown {} {} {}", 4.0f, "example1", 8ULL); - LOG_INFO(logger, "lazy over brown jumps {} {} {} {} {} {} {}", std::string("str1"), 8ULL, 5L, 3.0, - "example3", "example2", "example1"); - LOG_INFO(logger, "fox quick jumps dog {} {} {} {} {} {}", 4.0f, "example1", true, - std::string("str1"), std::string_view("view1"), 3.0); - LOG_INFO(logger, "dog test jumps over {} {} {} {} {} {} {}", std::string_view("view1"), 4.0f, - static_cast(9), 1, std::string_view("view2"), static_cast(10), false); - LOG_INFO(logger, "lazy quick test {} {} {} {}", 1, static_cast(9), 3.0, std::string("str2")); - LOG_INFO(logger, "jumps brown fox {} {} {} {} {} {}", std::string("str1"), - static_cast(10), 8ULL, "example1", std::string("str2"), 1); - LOG_INFO(logger, "test jumps quick {} {} {} {} {} {}", "example2", 1, 2, std::string_view("view2"), 8ULL, true); - LOG_INFO(logger, "fox over example quick {}", std::string("str2")); - LOG_INFO(logger, "over dog test {} {} {} {} {} {} {} {} {} {}", false, 3.0, "example1", - std::string("str1"), std::string("str2"), 2, "example2", "example3", static_cast(9), 1); - LOG_INFO(logger, "example logging dog {}", "example1"); - LOG_INFO(logger, "test logging jumps {} {} {} {} {} {} {} {}", 1, "example3", std::string("str1"), - 6LL, 3.0, "example1", 7UL, 5L); - LOG_INFO(logger, "fox example jumps quick {} {} {} {} {} {} {} {} {} {}", 5L, std::string("str1"), - false, 3.0, 2, 6LL, 7UL, true, "example3", std::string_view("view2")); - LOG_INFO(logger, "fox lazy example test {} {}", true, 5L); - LOG_INFO(logger, "example brown dog jumps {}", 4.0f); - LOG_INFO(logger, "dog jumps fox {} {} {} {} {} {}", 8ULL, "example2", std::string_view("view2"), - "example3", std::string("str2"), 3.0); - LOG_INFO(logger, "quick lazy example logging {}", std::string_view("view2")); - LOG_INFO(logger, "dog brown over {} {}", std::string_view("view2"), "example3"); - LOG_INFO(logger, "jumps brown over {} {}", "example2", "example3"); - LOG_INFO(logger, "test over quick {} {} {} {}", 4.0f, std::string("str2"), 8ULL, 5L); - LOG_INFO(logger, "quick jumps brown example {} {} {} {} {} {} {}", static_cast(10), - std::string("str1"), 1, 8ULL, "example2", 4.0f, static_cast(9)); - LOG_INFO(logger, "over jumps dog {} {} {} {} {} {} {} {} {} {}", "example2", - static_cast(10), "example1", 4.0f, std::string_view("view1"), 3.0, - std::string("str2"), 5L, false, "example3"); - LOG_INFO(logger, "fox jumps quick {} {} {} {} {} {} {} {}", true, 1, std::string_view("view2"), - std::string_view("view1"), std::string("str1"), 5L, static_cast(10), - "example1"); - LOG_INFO(logger, "fox logging lazy {} {} {} {} {}", 2, 4.0f, std::string("str2"), - std::string_view("view2"), 3.0); - LOG_INFO(logger, "logging fox jumps {} {} {} {}", std::string_view("view2"), 4.0f, - std::string_view("view1"), static_cast(10)); - LOG_INFO(logger, "fox brown dog test {} {}", 2, 7UL); - LOG_INFO(logger, "lazy dog jumps brown {} {} {}", std::string_view("view2"), 3.0, "example1"); - LOG_INFO(logger, "fox dog test jumps {} {} {} {}", 6LL, static_cast(9), - static_cast(10), 8ULL); - LOG_INFO(logger, "quick brown logging over {}", static_cast(10)); - LOG_INFO(logger, "logging dog jumps {}", "example2"); - LOG_INFO(logger, "quick jumps example {} {} {} {} {} {} {} {} {} {}", 8ULL, 2, static_cast(9), - "example2", 6LL, std::string_view("view1"), "example3", true, 5L, 4.0f); - LOG_INFO(logger, "brown over quick logging {} {} {} {} {}", false, 7UL, "example3", true, - std::string_view("view1")); - LOG_INFO(logger, "jumps example fox {}", 1); - LOG_INFO(logger, "over example jumps quick {} {} {}", 1, 2, std::string("str1")); - LOG_INFO(logger, "test over dog quick {}", "example3"); - LOG_INFO(logger, "over quick logging {} {} {}", false, 4.0f, 3.0); - LOG_INFO(logger, "fox test example jumps {} {} {} {} {} {} {}", static_cast(10), - 8ULL, 2, "example2", std::string_view("view1"), std::string("str1"), static_cast(9)); - LOG_INFO(logger, "brown jumps example logging {} {} {} {}", static_cast(9), - static_cast(10), 3.0, "example3"); - LOG_INFO(logger, "over fox lazy {}", 6LL); - LOG_INFO(logger, "test fox example {} {} {} {} {} {} {} {}", 2, true, std::string_view("view2"), - static_cast(9), std::string("str1"), 4.0f, "example1", std::string_view("view1")); - LOG_INFO(logger, "dog over test {} {} {} {} {}", 5L, false, 3.0, 7UL, 8ULL); - LOG_INFO(logger, "over jumps logging example {} {} {} {} {} {} {} {} {} {}", - static_cast(10), "example3", std::string("str2"), true, - std::string("str1"), "example1", false, 6LL, 1, "example2"); - LOG_INFO(logger, "logging test fox over {} {} {} {} {} {} {} {} {}", false, true, - static_cast(9), 3.0, 4.0f, 5L, 8ULL, 6LL, 1); - LOG_INFO(logger, "logging lazy example {} {} {} {} {} {} {} {} {} {}", 8ULL, "example2", - std::string_view("view1"), 7UL, 6LL, static_cast(10), "example3", false, - 3.0, "example1"); - LOG_INFO(logger, "dog brown example {}", "example1"); - LOG_INFO(logger, "logging dog example fox {} {} {} {} {} {} {} {} {}", "example2", 4.0f, - "example1", true, 5L, static_cast(9), 7UL, "example3", std::string_view("view1")); - LOG_INFO(logger, "fox dog test {} {} {} {} {} {}", false, static_cast(10), - std::string_view("view1"), static_cast(9), 7UL, "example1"); - LOG_INFO(logger, "fox brown example {} {} {} {} {}", static_cast(9), "example3", 6LL, - std::string("str1"), "example1"); - LOG_INFO(logger, "fox dog example {}", static_cast(10)); - LOG_INFO(logger, "fox quick lazy {} {} {} {} {} {} {}", std::string_view("view2"), 1, - std::string("str2"), "example2", 3.0, static_cast(9), 6LL); - LOG_INFO(logger, "dog test example logging {} {}", std::string_view("view1"), 8ULL); - LOG_INFO(logger, "lazy quick over {}", true); - LOG_INFO(logger, "over fox test {} {} {}", std::string_view("view2"), false, 1); - LOG_INFO(logger, "lazy jumps over dog {}", 2); - LOG_INFO(logger, "example fox brown over {} {} {} {} {}", "example1", 8ULL, "example2", 5L, 3.0); - LOG_INFO(logger, "dog brown over fox {} {} {} {}", static_cast(10), "example2", - 6LL, "example3"); - LOG_INFO(logger, "quick lazy over {} {} {} {} {} {}", 6LL, "example3", - static_cast(10), 5L, std::string_view("view1"), 7UL); - LOG_INFO(logger, "over example fox quick {} {}", true, 4.0f); - LOG_INFO(logger, "logging over jumps brown {} {} {} {} {} {} {} {} {} {}", "example3", 5L, - std::string_view("view1"), 8ULL, static_cast(10), 7UL, - std::string("str1"), 1, static_cast(9), true); - LOG_INFO(logger, "lazy quick dog {} {} {} {} {} {} {}", 4.0f, "example2", "example1", 2, - std::string("str1"), true, 3.0); - LOG_INFO(logger, "dog example brown {} {} {} {} {} {} {}", 2, 7UL, - static_cast(10), 4.0f, std::string_view("view2"), "example3", "example1"); - LOG_INFO(logger, "jumps dog fox test {}", std::string_view("view2")); - LOG_INFO(logger, "jumps dog quick fox {} {} {} {} {} {}", false, std::string_view("view1"), - static_cast(9), 8ULL, 4.0f, 5L); - LOG_INFO(logger, "fox lazy test jumps {} {} {} {} {} {} {} {} {}", 7UL, std::string("str2"), - std::string_view("view1"), std::string("str1"), 4.0f, static_cast(9), "example2", 3.0, 2); - LOG_INFO(logger, "test logging over fox {} {} {}", "example2", false, 8ULL); - LOG_INFO(logger, "example quick brown lazy {} {} {} {} {} {} {} {}", 7UL, std::string("str2"), 5L, - true, std::string_view("view1"), "example2", 2, 6LL); - LOG_INFO(logger, "dog quick jumps {} {} {} {}", 5L, "example3", 1, std::string("str2")); - LOG_INFO(logger, "dog fox lazy {}", false); - LOG_INFO(logger, "logging fox quick {} {} {} {} {} {} {} {} {} {}", 1, std::string("str2"), 4.0f, - 7UL, static_cast(10), std::string_view("view1"), static_cast(9), - std::string("str1"), "example2", 5L); - LOG_INFO(logger, "lazy quick example test {} {} {} {} {} {} {} {}", 5L, "example3", false, - std::string_view("view2"), static_cast(10), 4.0f, "example1", 2); - LOG_INFO(logger, "jumps quick dog {} {} {} {} {}", 5L, "example3", std::string("str1"), true, 7UL); - LOG_INFO(logger, "example jumps logging {} {} {} {} {} {} {} {} {}", static_cast(10), - 3.0, false, 2, std::string_view("view1"), "example1", std::string_view("view2"), 8ULL, 6LL); - LOG_INFO(logger, "brown example test {} {} {} {} {} {}", 6LL, static_cast(10), - 3.0, "example1", 4.0f, 7UL); - LOG_INFO(logger, "brown jumps dog lazy {}", 2); - LOG_INFO(logger, "test quick logging brown {} {} {} {} {}", 5L, "example3", 8ULL, true, 4.0f); - LOG_INFO(logger, "fox logging brown {} {} {} {} {} {}", std::string_view("view1"), "example2", - true, std::string("str2"), 2, 5L); - LOG_INFO(logger, "test lazy quick over {} {} {} {}", 7UL, 5L, static_cast(10), - std::string_view("view1")); - LOG_INFO(logger, "test over brown {} {} {} {} {} {} {} {}", std::string("str2"), false, 8ULL, 2, - true, "example3", 1, std::string_view("view1")); - LOG_INFO(logger, "jumps brown fox logging {} {} {} {} {} {} {} {} {}", false, true, 6LL, - static_cast(9), 2, 4.0f, std::string("str1"), 7UL, "example2"); - LOG_INFO(logger, "logging test over {} {} {} {}", std::string("str2"), "example1", 5L, 3.0); - LOG_INFO(logger, "lazy test jumps {} {} {}", 2, "example1", std::string("str2")); - LOG_INFO(logger, "quick jumps fox test {} {}", 1, std::string("str2")); - LOG_INFO(logger, "example logging over jumps {} {}", 7UL, 6LL); - LOG_INFO(logger, "over fox test {} {} {} {} {} {} {} {} {}", 8ULL, static_cast(9), 1, - std::string_view("view1"), "example1", 7UL, "example3", 3.0, 6LL); - LOG_INFO(logger, "test lazy dog {} {} {}", 2, 3.0, std::string_view("view2")); - LOG_INFO(logger, "quick test logging lazy {} {}", std::string_view("view2"), "example3"); - LOG_INFO(logger, "quick fox test brown {} {} {} {} {} {} {} {} {}", 7UL, 1, - static_cast(10), 8ULL, false, std::string_view("view2"), 3.0, "example2", - std::string_view("view1")); - LOG_INFO(logger, "lazy over jumps {}", std::string("str2")); - LOG_INFO(logger, "test dog lazy {} {}", std::string_view("view1"), false); - LOG_INFO(logger, "jumps over quick {} {} {} {} {} {} {} {}", 7UL, 1, std::string_view("view2"), - "example2", 4.0f, true, static_cast(9), "example3"); - LOG_INFO(logger, "logging brown jumps {} {} {} {} {} {} {} {}", std::string("str2"), false, - std::string("str1"), "example3", 4.0f, 6LL, 8ULL, 5L); - LOG_INFO(logger, "brown jumps quick over {} {} {} {} {}", 8ULL, 5L, "example2", - static_cast(10), std::string_view("view1")); - LOG_INFO(logger, "brown fox example logging {} {} {} {} {} {}", 3.0, std::string_view("view1"), - 6LL, "example2", 8ULL, 7UL); - LOG_INFO(logger, "dog test fox {} {} {} {} {} {}", 1, static_cast(10), - static_cast(9), 2, 5L, true); - LOG_INFO(logger, "dog logging quick {} {}", std::string("str2"), 7UL); - LOG_INFO(logger, "jumps brown quick logging {} {} {} {} {} {}", std::string("str2"), 7UL, - static_cast(10), 4.0f, 5L, false); - LOG_INFO(logger, "dog logging jumps {} {} {} {} {} {} {} {} {} {}", std::string("str2"), 2, - "example1", "example3", std::string("str1"), false, static_cast(9), - std::string_view("view2"), std::string_view("view1"), 5L); - LOG_INFO(logger, "fox over lazy {} {} {} {} {} {}", 1, std::string_view("view2"), 3.0, "example1", - std::string_view("view1"), "example3"); - LOG_INFO(logger, "dog lazy quick fox {} {} {} {}", std::string_view("view2"), 4.0f, "example3", 2); - LOG_INFO(logger, "fox lazy dog {} {} {} {} {} {} {} {} {} {}", "example1", 6LL, 3.0, false, - "example2", std::string("str2"), std::string_view("view1"), true, 8ULL, - static_cast(10)); - LOG_INFO(logger, "fox over jumps {} {}", 6LL, std::string("str2")); - LOG_INFO(logger, "test logging jumps {} {} {} {} {} {} {} {}", "example1", static_cast(9), 7UL, - std::string("str2"), std::string_view("view2"), false, static_cast(10), 3.0); - LOG_INFO(logger, "test logging lazy example {} {} {} {}", 7UL, 5L, 2, false); - LOG_INFO(logger, "logging dog lazy {} {} {} {} {} {} {} {} {} {}", "example2", 2, true, - "example1", static_cast(9), 4.0f, 5L, 1, "example3", 6LL); - LOG_INFO(logger, "brown over fox {} {} {} {}", std::string_view("view1"), - std::string_view("view2"), 8ULL, std::string("str2")); - LOG_INFO(logger, "jumps logging lazy {} {} {} {} {} {} {}", std::string("str2"), - std::string_view("view1"), 7UL, 1, 8ULL, 3.0, std::string("str1")); - LOG_INFO(logger, "fox brown dog logging {}", false); - LOG_INFO(logger, "brown over fox {} {} {} {} {} {} {} {} {}", 8ULL, static_cast(9), 2, 6LL, - std::string_view("view1"), false, 7UL, 3.0, 1); - LOG_INFO(logger, "test over dog {} {} {} {}", 5L, std::string_view("view1"), 7UL, std::string_view("view2")); - LOG_INFO(logger, "dog brown jumps {} {} {}", static_cast(9), static_cast(10), 8ULL); - LOG_INFO(logger, "logging brown fox over {} {} {}", false, 8ULL, std::string_view("view1")); - LOG_INFO(logger, "logging over brown example {} {} {} {} {} {} {} {}", 2, 1, std::string_view("view1"), - 3.0, std::string_view("view2"), static_cast(9), std::string("str1"), 5L); - LOG_INFO(logger, "lazy jumps logging test {} {} {} {} {}", "example2", false, std::string("str1"), - "example3", 2); - LOG_INFO(logger, "brown example lazy {} {}", std::string_view("view1"), static_cast(9)); - LOG_INFO(logger, "example brown quick logging {} {} {} {} {} {}", 4.0f, "example2", 3.0, 1, false, - std::string("str1")); - LOG_INFO(logger, "over dog test {} {} {} {} {} {} {}", 4.0f, "example1", 7UL, 5L, - std::string("str2"), std::string_view("view1"), false); - LOG_INFO(logger, "quick lazy jumps {} {} {} {} {} {} {} {}", 6LL, 5L, "example1", 2, "example2", - 7UL, std::string_view("view1"), static_cast(9)); - LOG_INFO(logger, "brown logging quick {} {} {} {} {} {} {} {} {}", std::string("str2"), - std::string_view("view1"), std::string_view("view2"), "example3", false, 6LL, 4.0f, true, 5L); - LOG_INFO(logger, "quick logging jumps {} {} {} {} {} {} {} {} {} {}", "example2", std::string_view("view2"), - true, 6LL, 8ULL, static_cast(9), 4.0f, 3.0, std::string("str1"), "example1"); - LOG_INFO(logger, "lazy jumps quick fox {} {}", 8ULL, std::string_view("view2")); - LOG_INFO(logger, "over fox jumps {} {} {} {} {}", std::string_view("view1"), - static_cast(10), static_cast(9), "example1", true); - LOG_INFO(logger, "dog over lazy {} {} {} {} {}", 1, static_cast(9), std::string("str1"), true, 3.0); - LOG_INFO(logger, "jumps quick fox example {} {} {} {} {} {}", std::string("str1"), 8ULL, true, - false, "example3", static_cast(9)); - LOG_INFO(logger, "quick lazy test brown {} {} {} {}", "example2", true, 1, "example1"); - LOG_INFO(logger, "dog logging jumps {} {} {} {} {} {} {} {} {}", std::string("str1"), - static_cast(9), std::string("str2"), std::string_view("view2"), 4.0f, false, - "example2", static_cast(10), 1); - LOG_INFO(logger, "lazy dog fox example {} {} {} {} {} {} {} {} {}", 2, "example1", - static_cast(9), true, "example2", false, std::string_view("view1"), 8ULL, 4.0f); - LOG_INFO(logger, "quick test lazy {} {} {} {} {} {} {} {} {}", false, std::string("str2"), 1, 2, - std::string_view("view1"), 8ULL, "example2", "example3", 5L); - LOG_INFO(logger, "brown lazy test over {} {} {} {} {} {} {} {} {}", static_cast(10), - 5L, static_cast(9), 8ULL, 7UL, 1, 6LL, "example3", 2); - LOG_INFO(logger, "dog jumps fox {} {} {} {} {} {} {} {}", 7UL, 8ULL, false, std::string("str2"), - std::string_view("view2"), true, "example2", std::string("str1")); - LOG_INFO(logger, "lazy jumps over {} {} {} {} {} {} {}", "example1", std::string_view("view1"), - 5L, static_cast(10), 2, std::string("str1"), true); - LOG_INFO(logger, "dog brown test {} {} {} {} {} {} {} {} {}", 2, std::string("str2"), - std::string_view("view2"), 6LL, static_cast(9), std::string("str1"), "example3", 5L, true); - LOG_INFO(logger, "test jumps logging brown {} {} {} {} {} {} {} {}", "example2", 3.0, 6LL, true, - 5L, 2, 4.0f, static_cast(10)); - LOG_INFO(logger, "brown lazy logging {} {} {} {} {} {}", "example3", 2, false, true, 4.0f, - "example2"); - LOG_INFO(logger, "logging example lazy brown {} {}", 5L, std::string("str1")); - LOG_INFO(logger, "jumps example lazy logging {}", 8ULL); - LOG_INFO(logger, "logging test brown {} {} {} {} {} {} {} {} {} {}", std::string("str2"), 6LL, - "example1", 8ULL, 1, 3.0, std::string_view("view1"), std::string_view("view2"), - "example3", static_cast(10)); - LOG_INFO(logger, "example lazy jumps {} {} {}", "example1", static_cast(10), - static_cast(9)); - LOG_INFO(logger, "dog test fox logging {} {} {} {} {} {}", 6LL, std::string_view("view1"), true, - 5L, 8ULL, 7UL); - LOG_INFO(logger, "brown over fox dog {} {} {} {} {} {} {}", 6LL, "example3", 4.0f, "example1", 3.0, true, 1); - LOG_INFO(logger, "dog logging brown {} {} {} {} {} {} {} {} {}", 3.0, true, std::string("str1"), - static_cast(9), 1, 2, 6LL, 5L, "example2"); - LOG_INFO(logger, "logging fox dog lazy {} {} {} {} {} {}", 3.0, static_cast(9), - std::string_view("view1"), "example1", 5L, 1); - LOG_INFO(logger, "fox lazy dog brown {} {} {} {} {} {} {} {}", false, 1, 8ULL, 3.0, - static_cast(10), true, "example2", 4.0f); - LOG_INFO(logger, "quick test dog brown {} {} {}", true, std::string("str2"), - static_cast(10)); - LOG_INFO(logger, "jumps logging brown {} {} {} {} {} {}", false, 4.0f, std::string_view("view1"), - std::string("str1"), 5L, "example1"); - LOG_INFO(logger, "dog fox brown jumps {} {} {} {} {} {} {} {}", std::string_view("view2"), 5L, - static_cast(9), std::string("str1"), 8ULL, 4.0f, std::string_view("view1"), - std::string("str2")); - LOG_INFO(logger, "lazy over fox logging {} {} {} {} {} {}", std::string_view("view2"), 5L, 1, 4.0f, 8ULL, true); - LOG_INFO(logger, "over quick example {} {} {} {} {} {} {}", static_cast(10), 1, - "example1", 7UL, "example2", true, 5L); - LOG_INFO(logger, "dog example over {} {} {} {}", 5L, 3.0, 7UL, 1); - LOG_INFO(logger, "dog example fox {} {} {} {}", "example1", 3.0, static_cast(10), 1); - LOG_INFO(logger, "quick fox dog {}", 2); - LOG_INFO(logger, "fox logging example {} {} {} {}", std::string("str1"), "example1", true, false); - LOG_INFO(logger, "brown fox example {} {} {} {} {} {} {}", static_cast(9), 7UL, "example3", - 8ULL, 6LL, false, std::string_view("view1")); - LOG_INFO(logger, "jumps logging dog {} {} {}", std::string("str2"), std::string_view("view1"), - std::string("str1")); - LOG_INFO(logger, "logging lazy dog {} {} {} {} {}", 6LL, 5L, static_cast(10), - std::string("str1"), "example2"); - LOG_INFO(logger, "test fox logging {}", 7UL); - LOG_INFO(logger, "logging lazy quick {} {}", 2, static_cast(9)); - LOG_INFO(logger, "brown over example test {} {} {} {} {} {} {} {} {}", std::string("str2"), 6LL, - "example1", 4.0f, std::string("str1"), false, 1, 3.0, 2); - LOG_INFO(logger, "brown over example {} {} {} {} {} {} {} {} {} {}", 1, 5L, - std::string_view("view1"), std::string("str1"), static_cast(9), 3.0, "example2", - static_cast(10), "example1", 4.0f); - LOG_INFO(logger, "test quick fox lazy {} {} {} {} {} {} {}", false, - static_cast(10), std::string("str2"), 3.0, 2, true, 1); - LOG_INFO(logger, "brown logging dog example {} {} {} {} {} {}", 8ULL, 5L, - std::string_view("view1"), 4.0f, static_cast(9), std::string("str2")); - LOG_INFO(logger, "logging brown dog {} {} {} {} {} {}", std::string("str1"), - std::string_view("view1"), std::string_view("view2"), "example3", true, 2); - LOG_INFO(logger, "quick fox lazy {}", 8ULL); - LOG_INFO(logger, "test logging example brown {} {} {} {} {}", "example2", false, - static_cast(10), 2, true); - LOG_INFO(logger, "brown jumps fox {} {} {} {} {} {} {} {} {} {}", 4.0f, 8ULL, 2, std::string_view("view2"), - std::string("str2"), 1, "example2", "example3", std::string("str1"), 3.0); - LOG_INFO(logger, "over dog quick {} {} {} {} {} {} {} {}", std::string("str1"), 5L, true, - static_cast(10), 7UL, std::string("str2"), std::string_view("view1"), 4.0f); - LOG_INFO(logger, "test dog brown lazy {} {} {} {} {} {} {} {}", true, std::string_view("view2"), - 6LL, std::string_view("view1"), false, 8ULL, "example3", 3.0); - LOG_INFO(logger, "example fox lazy {} {}", 5L, static_cast(10)); - LOG_INFO(logger, "example logging over {} {} {} {} {} {} {} {}", 8ULL, 2, 6LL, "example2", - "example1", std::string("str2"), 5L, 7UL); - LOG_INFO(logger, "jumps test example {} {}", 1, 7UL); - LOG_INFO(logger, "over dog test example {} {} {} {} {} {} {} {} {}", static_cast(10), - 2, "example3", std::string_view("view2"), 8ULL, 5L, 3.0, static_cast(9), 6LL); - LOG_INFO(logger, "quick dog brown {} {} {} {} {} {} {} {} {}", static_cast(9), 4.0f, - std::string("str1"), true, 6LL, 7UL, 8ULL, "example1", std::string("str2")); - LOG_INFO(logger, "logging dog fox brown {} {} {} {}", std::string("str1"), 3.0, "example3", 6LL); - LOG_INFO(logger, "quick test over {} {} {} {} {} {} {}", 6LL, 8ULL, std::string_view("view1"), 1, - std::string_view("view2"), 7UL, true); - LOG_INFO(logger, "test over fox {} {} {} {}", 5L, static_cast(9), 8ULL, 7UL); - LOG_INFO(logger, "fox logging test {} {} {}", 1, 7UL, std::string_view("view1")); - LOG_INFO(logger, "fox over quick {} {} {} {} {} {} {} {}", "example2", std::string_view("view2"), - static_cast(9), false, 7UL, "example3", "example1", 4.0f); - LOG_INFO(logger, "fox quick test example {}", std::string("str2")); - LOG_INFO(logger, "quick over dog {}", "example2"); - LOG_INFO(logger, "example quick fox {} {} {} {}", 7UL, std::string("str1"), "example3", 4.0f); - LOG_INFO(logger, "example fox brown dog {} {} {} {} {} {} {} {} {}", 5L, static_cast(9), - 3.0, "example1", 1, true, 7UL, false, std::string("str2")); - LOG_INFO(logger, "lazy dog jumps quick {} {} {} {} {}", std::string_view("view1"), 1, - static_cast(9), false, 6LL); - LOG_INFO(logger, "logging dog test {}", 6LL); - LOG_INFO(logger, "fox jumps quick logging {} {} {} {} {} {} {} {} {} {}", true, 8ULL, 1, 5L, - "example1", std::string("str1"), 6LL, static_cast(10), 2, "example3"); - LOG_INFO(logger, "jumps over example {} {} {} {} {} {} {} {} {} {}", - static_cast(10), std::string_view("view1"), std::string_view("view2"), - 8ULL, 4.0f, 3.0, std::string("str1"), true, 1, "example1"); - LOG_INFO(logger, "over jumps logging {} {} {} {} {} {} {} {} {} {}", 4.0f, 5L, false, - std::string_view("view1"), static_cast(9), 2, 7UL, 6LL, "example2", - std::string_view("view2")); - LOG_INFO(logger, "quick example jumps {}", 5L); - LOG_INFO(logger, "logging brown lazy {} {} {} {} {} {} {}", std::string_view("view1"), false, - static_cast(10), true, "example3", std::string("str2"), 3.0); - LOG_INFO(logger, "lazy dog quick brown {} {} {} {} {} {} {} {} {} {}", 2, "example3", 7UL, 3.0, - std::string("str1"), std::string_view("view2"), true, 6LL, std::string_view("view1"), false); - LOG_INFO(logger, "fox logging example test {}", 1); - LOG_INFO(logger, "test quick brown fox {} {} {} {} {} {}", "example1", static_cast(9), - 4.0f, 1, 5L, std::string_view("view1")); - LOG_INFO(logger, "dog logging test {} {} {} {}", std::string("str1"), "example1", true, - std::string_view("view1")); - LOG_INFO(logger, "test lazy quick example {} {} {} {} {}", 8ULL, std::string("str1"), 4.0f, 2, - std::string_view("view1")); - LOG_INFO(logger, "brown logging jumps dog {} {}", false, 8ULL); - LOG_INFO(logger, "test lazy logging example {} {} {} {} {} {} {} {}", std::string("str2"), false, - "example2", 7UL, "example3", 4.0f, std::string_view("view1"), static_cast(9)); - LOG_INFO(logger, "lazy example jumps brown {} {} {}", 6LL, std::string_view("view2"), std::string("str1")); - LOG_INFO(logger, "brown fox test over {} {} {} {} {} {} {} {} {} {}", - static_cast(10), 1, false, 6LL, static_cast(9), 7UL, - std::string_view("view2"), "example2", std::string("str2"), true); - LOG_INFO(logger, "over example test {} {} {} {} {} {}", static_cast(9), 1, - std::string_view("view2"), 8ULL, static_cast(10), 5L); - LOG_INFO(logger, "dog fox test example {} {} {}", "example3", std::string_view("view1"), std::string("str2")); - LOG_INFO(logger, "jumps test over logging {} {} {} {} {} {} {}", 4.0f, 6LL, 5L, 2, "example1", 1, - std::string_view("view2")); - LOG_INFO(logger, "brown test lazy {} {} {} {} {} {} {}", false, std::string("str1"), 4.0f, - "example3", std::string("str2"), 8ULL, true); - LOG_INFO(logger, "example jumps brown {} {} {} {} {} {} {} {} {} {}", 2, "example3", 4.0f, 7UL, - 8ULL, 3.0, static_cast(10), 1, "example1", std::string("str2")); - LOG_INFO(logger, "dog fox jumps {} {}", std::string("str1"), "example2"); - LOG_INFO(logger, "dog brown example {} {} {} {} {} {}", 1, std::string("str1"), 7UL, 6LL, - std::string("str2"), 4.0f); - LOG_INFO(logger, "jumps brown quick {} {}", static_cast(9), true); - LOG_INFO(logger, "brown example jumps {} {} {}", false, 5L, std::string_view("view1")); - LOG_INFO(logger, "logging quick test {} {}", std::string_view("view2"), "example3"); - LOG_INFO(logger, "test over quick fox {} {} {} {} {}", 2, 5L, 3.0, true, "example2"); - LOG_INFO(logger, "over lazy dog brown {} {} {} {} {}", "example2", 3.0, 2, static_cast(9), false); - LOG_INFO(logger, "fox dog logging {} {} {} {} {} {}", static_cast(10), - std::string_view("view2"), static_cast(9), 6LL, 5L, 1); - LOG_INFO(logger, "over logging brown quick {} {} {} {} {} {} {} {} {} {}", static_cast(9), - "example2", std::string_view("view1"), 8ULL, 2, std::string("str1"), - static_cast(10), 7UL, 6LL, "example3"); - LOG_INFO(logger, "brown logging lazy quick {} {} {} {} {} {}", 5L, - static_cast(10), static_cast(9), std::string("str2"), 8ULL, true); - LOG_INFO(logger, "example test quick {} {}", std::string("str1"), static_cast(10)); - LOG_INFO(logger, "brown over jumps {} {} {}", true, 1, std::string_view("view1")); - LOG_INFO(logger, "dog over lazy example {} {} {} {}", "example1", "example3", 2, 7UL); - LOG_INFO(logger, "fox test quick {} {} {} {} {} {} {} {} {} {}", 1, "example2", 7UL, - static_cast(10), 3.0, 2, 5L, std::string_view("view1"), 4.0f, 6LL); - LOG_INFO(logger, "lazy test brown {} {} {}", 2, false, 5L); - LOG_INFO(logger, "lazy example fox quick {} {} {} {} {} {} {}", false, 4.0f, 5L, - std::string("str1"), "example3", 7UL, std::string_view("view1")); - LOG_INFO(logger, "quick brown test dog {} {} {} {} {} {} {} {} {} {}", 7UL, "example2", false, - 8ULL, std::string("str2"), 6LL, 2, std::string("str1"), "example1", true); - LOG_INFO(logger, "quick logging test over {} {} {} {}", std::string_view("view1"), "example1", - static_cast(9), 2); - LOG_INFO(logger, "jumps logging dog {} {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - std::string("str2"), 6LL, 3.0, 2, static_cast(10), false, 8ULL, true, 4.0f); - LOG_INFO(logger, "quick logging over dog {} {} {} {} {} {} {} {}", 5L, true, 3.0, "example2", 2, - 7UL, "example1", std::string_view("view1")); - LOG_INFO(logger, "example over lazy fox {} {} {} {}", std::string_view("view1"), 6LL, "example1", - std::string_view("view2")); - LOG_INFO(logger, "jumps brown quick {} {} {} {}", "example1", 3.0, 5L, std::string("str1")); - LOG_INFO(logger, "lazy quick over jumps {} {} {}", 2, true, static_cast(9)); - LOG_INFO(logger, "brown example dog {}", 5L); - LOG_INFO(logger, "over brown logging dog {} {}", static_cast(10), 6LL); - LOG_INFO(logger, "test lazy over dog {} {} {} {} {}", 6LL, static_cast(9), 3.0, false, 1); - LOG_INFO(logger, "over lazy jumps brown {} {} {} {}", static_cast(9), std::string("str2"), 8ULL, 5L); - LOG_INFO(logger, "lazy fox example {} {} {}", 8ULL, std::string_view("view1"), static_cast(9)); - LOG_INFO(logger, "logging jumps dog test {} {} {}", static_cast(9), true, 7UL); - LOG_INFO(logger, "test example over lazy {} {} {} {} {} {} {} {}", static_cast(10), - 6LL, 7UL, static_cast(9), "example1", true, std::string("str1"), false); - LOG_INFO(logger, "lazy over test {} {} {} {} {} {} {} {} {}", std::string("str1"), 7UL, - "example2", true, std::string_view("view1"), 6LL, "example1", 4.0f, std::string("str2")); - LOG_INFO(logger, "jumps example lazy {} {}", "example3", std::string_view("view2")); - LOG_INFO(logger, "fox logging lazy test {} {} {} {} {} {} {} {}", static_cast(10), - 5L, "example2", 4.0f, 3.0, std::string_view("view2"), 2, "example1"); - LOG_INFO(logger, "fox over quick test {} {} {} {} {} {} {} {} {}", "example1", - static_cast(10), static_cast(9), "example2", false, - std::string_view("view2"), 6LL, "example3", 5L); - LOG_INFO(logger, "test quick over logging {} {}", std::string_view("view2"), 6LL); - LOG_INFO(logger, "logging test quick over {} {}", true, 6LL); - LOG_INFO(logger, "lazy quick fox {} {} {} {} {} {} {} {}", 4.0f, false, 8ULL, std::string_view("view1"), - 6LL, 3.0, std::string_view("view2"), static_cast(10)); - LOG_INFO(logger, "dog lazy test jumps {} {} {} {} {} {} {}", 2, 8ULL, 1, - static_cast(10), "example1", true, static_cast(9)); - LOG_INFO(logger, "lazy dog test fox {}", std::string("str1")); - LOG_INFO(logger, "test jumps example brown {} {} {} {} {} {} {}", false, 4.0f, 2, - std::string_view("view1"), "example1", 6LL, std::string("str2")); - LOG_INFO(logger, "fox dog lazy logging {} {} {} {} {} {} {} {} {}", "example3", - std::string("str2"), 8ULL, "example1", false, "example2", 4.0f, 3.0, std::string("str1")); - LOG_INFO(logger, "fox test example brown {} {}", std::string("str1"), "example2"); - LOG_INFO(logger, "test quick logging {}", std::string("str1")); - LOG_INFO(logger, "brown fox example jumps {} {} {} {} {} {} {} {}", std::string_view("view1"), - 7UL, false, 6LL, std::string("str1"), 8ULL, std::string_view("view2"), "example3"); - LOG_INFO(logger, "lazy logging fox jumps {} {} {} {} {}", std::string_view("view1"), "example2", - "example3", false, static_cast(9)); - LOG_INFO(logger, "dog jumps example over {}", true); - LOG_INFO(logger, "brown lazy quick {} {} {} {} {} {} {} {}", static_cast(10), - std::string("str1"), true, std::string("str2"), std::string_view("view2"), 4.0f, - "example3", false); - LOG_INFO(logger, "dog fox jumps logging {} {} {}", 6LL, 5L, 1); - LOG_INFO(logger, "jumps brown example quick {} {} {} {} {} {}", std::string_view("view1"), 7UL, - "example3", 8ULL, 6LL, 3.0); - LOG_INFO(logger, "quick example jumps lazy {} {} {} {} {}", static_cast(10), - false, std::string_view("view1"), 1, 7UL); - LOG_INFO(logger, "dog lazy quick over {}", "example3"); - LOG_INFO(logger, "over dog brown {} {} {} {} {} {}", 8ULL, 7UL, std::string("str2"), "example3", - 1, std::string_view("view1")); - LOG_INFO(logger, "test quick dog lazy {} {} {}", "example3", "example1", "example2"); - LOG_INFO(logger, "dog fox jumps over {} {}", static_cast(10), "example3"); - LOG_INFO(logger, "jumps fox lazy dog {} {} {} {} {} {} {} {} {}", 5L, 2, "example3", "example2", - static_cast(10), 3.0, std::string("str2"), 6LL, 8ULL); - LOG_INFO(logger, "over quick fox {} {} {} {} {} {} {}", std::string_view("view2"), - static_cast(10), 4.0f, 8ULL, 2, 1, std::string("str2")); - LOG_INFO(logger, "dog test lazy {} {} {} {}", 8ULL, std::string_view("view1"), "example3", 3.0); - LOG_INFO(logger, "fox jumps example dog {} {}", "example2", static_cast(10)); - LOG_INFO(logger, "logging lazy jumps example {} {} {} {} {} {} {}", std::string_view("view2"), - static_cast(10), std::string_view("view1"), 7UL, true, 5L, 4.0f); - LOG_INFO(logger, "dog example fox {} {}", 6LL, std::string("str2")); - LOG_INFO(logger, "logging dog quick {} {} {} {} {}", static_cast(9), true, false, - std::string_view("view1"), std::string("str1")); - LOG_INFO(logger, "jumps example over {} {} {} {} {} {} {}", 3.0, false, std::string_view("view1"), - 4.0f, std::string("str2"), 5L, std::string_view("view2")); - LOG_INFO(logger, "example jumps test brown {} {} {} {} {} {}", std::string("str2"), 6LL, 7UL, - static_cast(9), "example2", 8ULL); - LOG_INFO(logger, "dog logging quick {} {} {} {} {} {} {}", "example1", std::string("str2"), 8ULL, - "example2", "example3", static_cast(10), 3.0); - LOG_INFO(logger, "quick logging brown {} {} {} {} {}", true, 3.0, static_cast(10), - 5L, std::string("str1")); - LOG_INFO(logger, "quick lazy dog brown {} {} {} {} {} {} {} {} {}", 7UL, static_cast(10), - 3.0, 1, "example2", "example1", 6LL, false, static_cast(9)); - LOG_INFO(logger, "jumps quick over {} {} {} {} {} {}", std::string("str2"), 4.0f, "example3", 1, - true, "example2"); - LOG_INFO(logger, "quick dog example jumps {} {} {} {} {} {} {} {}", "example1", 2, 6LL, false, - static_cast(10), 5L, 1, std::string_view("view1")); - LOG_INFO(logger, "jumps dog quick test {}", 2); - LOG_INFO(logger, "logging fox example {} {} {} {} {} {} {} {} {}", true, 2, - static_cast(10), std::string("str1"), std::string("str2"), - std::string_view("view1"), "example1", 1, static_cast(9)); - LOG_INFO(logger, "brown test dog {} {} {} {} {}", "example3", std::string_view("view1"), false, - 6LL, std::string("str1")); - LOG_INFO(logger, "over example logging brown {} {} {} {}", "example1", 1, 6LL, 7UL); - LOG_INFO(logger, "logging jumps test example {} {} {}", 1, 8ULL, 6LL); - LOG_INFO(logger, "logging brown lazy example {} {}", 6LL, static_cast(9)); - LOG_INFO(logger, "quick jumps lazy example {} {}", 7UL, 2); - LOG_INFO(logger, "brown over logging lazy {} {}", std::string("str2"), 7UL); - LOG_INFO(logger, "logging brown fox {}", std::string_view("view2")); - LOG_INFO(logger, "quick fox test {} {} {}", "example2", 5L, static_cast(10)); - LOG_INFO(logger, "quick test over brown {} {} {}", std::string_view("view1"), true, 2); - LOG_INFO(logger, "brown lazy jumps {} {} {} {} {} {} {}", 5L, "example2", 3.0, true, 4.0f, - std::string("str1"), static_cast(9)); - LOG_INFO(logger, "test jumps lazy logging {} {} {}", std::string_view("view2"), static_cast(9), 7UL); - LOG_INFO(logger, "brown quick dog jumps {}", false); - LOG_INFO(logger, "fox example test brown {} {} {} {} {} {}", 1, std::string_view("view2"), 3.0, - false, 8ULL, "example1"); - LOG_INFO(logger, "dog quick brown test {} {} {} {}", std::string_view("view2"), "example1", - std::string_view("view1"), 5L); - LOG_INFO(logger, "quick lazy example fox {} {} {} {} {} {} {} {} {} {}", 1, 2, 8ULL, false, 6LL, - true, "example2", "example1", 4.0f, static_cast(9)); - LOG_INFO(logger, "lazy dog brown fox {} {} {} {}", 6LL, true, std::string("str2"), 3.0); - LOG_INFO(logger, "quick test brown fox {} {} {} {} {}", std::string("str2"), - std::string_view("view2"), false, "example3", 5L); - LOG_INFO(logger, "dog jumps brown {}", static_cast(10)); - LOG_INFO(logger, "dog test example jumps {} {} {} {} {} {}", static_cast(10), - true, 8ULL, std::string("str1"), std::string_view("view1"), 2); - LOG_INFO(logger, "brown logging fox {} {} {} {} {} {} {} {}", "example1", static_cast(9), - "example3", "example2", true, static_cast(10), std::string("str2"), 5L); - LOG_INFO(logger, "lazy dog jumps {} {} {} {} {} {} {} {} {} {}", 7UL, 5L, std::string_view("view2"), - std::string("str1"), true, 3.0, std::string("str2"), "example1", 8ULL, static_cast(9)); - LOG_INFO(logger, "dog lazy quick {} {} {} {} {} {} {}", 8ULL, 6LL, true, 2, 1, 4.0f, "example2"); - LOG_INFO(logger, "logging over brown example {} {} {} {} {} {} {} {} {}", true, 3.0, 8ULL, - "example1", std::string_view("view2"), 5L, "example2", 6LL, std::string_view("view1")); - LOG_INFO(logger, "logging example test {} {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - 5L, "example3", 8ULL, 2, "example2", 7UL, std::string_view("view1"), - static_cast(9), std::string("str2")); - LOG_INFO(logger, "jumps over example test {} {} {} {} {} {} {} {} {}", 7UL, std::string("str2"), true, - 1, "example2", "example1", static_cast(10), std::string_view("view1"), 6LL); - LOG_INFO(logger, "brown lazy over {} {} {} {} {} {}", static_cast(9), "example1", - "example2", 8ULL, 3.0, std::string("str1")); - LOG_INFO(logger, "logging jumps test {} {}", 1, "example1"); - LOG_INFO(logger, "quick brown logging {} {} {} {} {} {} {}", 1, 4.0f, 7UL, "example3", - std::string_view("view2"), static_cast(9), 3.0); - LOG_INFO(logger, "jumps dog over test {} {} {} {} {} {} {} {} {}", std::string_view("view2"), false, - std::string_view("view1"), 7UL, "example1", "example2", static_cast(9), 4.0f, 6LL); - LOG_INFO(logger, "over dog quick fox {} {} {} {} {} {}", std::string("str2"), - std::string_view("view1"), "example3", std::string("str1"), "example2", 5L); - LOG_INFO(logger, "quick test fox brown {} {}", 8ULL, static_cast(10)); - LOG_INFO(logger, "example brown jumps quick {} {} {} {} {} {}", std::string_view("view2"), false, - 1, 6LL, 8ULL, 3.0); - LOG_INFO(logger, "brown example test quick {} {}", static_cast(9), 4.0f); - LOG_INFO(logger, "example dog lazy {} {} {} {} {} {} {} {} {} {}", 5L, 2, std::string("str2"), - static_cast(10), 1, std::string_view("view2"), false, 4.0f, 6LL, - std::string_view("view1")); - LOG_INFO(logger, "over logging dog {} {} {} {} {} {} {} {} {} {}", 7UL, 5L, 8ULL, 3.0, - static_cast(10), "example1", std::string_view("view1"), - std::string_view("view2"), true, std::string("str1")); - LOG_INFO(logger, "quick test example {} {} {} {} {} {} {} {}", 8ULL, 7UL, false, "example1", - "example3", std::string("str2"), 2, 6LL); - LOG_INFO(logger, "brown test lazy fox {} {} {} {} {} {} {} {} {} {}", "example3", 6LL, "example2", - std::string_view("view1"), 8ULL, static_cast(9), 4.0f, 3.0, 5L, false); - LOG_INFO(logger, "over test fox quick {} {} {} {} {} {} {}", 3.0, 2, std::string("str2"), - static_cast(9), 1, std::string_view("view1"), 8ULL); - LOG_INFO(logger, "test brown jumps {} {} {} {} {} {} {} {}", 7UL, "example2", std::string("str1"), - true, 6LL, false, 8ULL, "example3"); - LOG_INFO(logger, "over brown quick {} {} {} {} {} {} {} {}", 2, 7UL, "example1", - static_cast(10), std::string_view("view2"), std::string("str1"), 1, 3.0); - LOG_INFO(logger, "quick jumps over logging {} {} {} {} {} {} {} {} {}", 5L, false, 3.0, - std::string("str1"), "example1", 7UL, static_cast(10), - std::string("str2"), static_cast(9)); - LOG_INFO(logger, "dog over jumps {} {} {} {} {} {} {} {}", "example2", "example3", 6LL, false, - std::string_view("view1"), 2, 3.0, "example1"); - LOG_INFO(logger, "lazy quick test logging {} {} {}", false, std::string_view("view1"), 8ULL); - LOG_INFO(logger, "fox quick over {} {} {} {} {} {} {} {} {} {}", "example1", 6LL, 4.0f, - std::string_view("view1"), false, 1, 3.0, 7UL, std::string_view("view2"), 5L); - LOG_INFO(logger, "jumps lazy over logging {} {} {} {} {} {} {} {} {}", std::string("str1"), - "example1", 3.0, "example2", "example3", true, 4.0f, std::string_view("view1"), 6LL); - LOG_INFO(logger, "fox example quick {} {} {} {} {} {} {} {} {} {}", static_cast(9), - "example3", false, 5L, 7UL, 3.0, 8ULL, std::string_view("view1"), - static_cast(10), 4.0f); - LOG_INFO(logger, "jumps over dog brown {} {} {}", 3.0, 8ULL, "example1"); - LOG_INFO(logger, "jumps quick test {} {} {} {} {} {} {} {}", 7UL, 4.0f, "example2", - std::string("str2"), 3.0, false, 8ULL, 5L); - LOG_INFO(logger, "brown logging over fox {} {}", 5L, 6LL); - LOG_INFO(logger, "jumps dog over quick {} {} {} {} {} {} {}", static_cast(10), - std::string("str1"), "example2", "example1", std::string_view("view2"), "example3", 1); - LOG_INFO(logger, "over quick brown {} {} {} {} {} {} {} {}", 8ULL, 6LL, std::string("str2"), true, - "example2", 1, std::string_view("view2"), std::string_view("view1")); - LOG_INFO(logger, "logging quick brown fox {} {} {} {} {} {} {}", std::string_view("view1"), 1, - false, std::string("str1"), 6LL, "example2", std::string_view("view2")); - LOG_INFO(logger, "jumps fox logging {} {}", static_cast(10), static_cast(9)); - LOG_INFO(logger, "fox example dog {} {} {} {}", static_cast(10), - std::string("str2"), true, "example3"); - LOG_INFO(logger, "brown quick logging fox {} {} {} {} {} {} {} {} {}", 8ULL, 5L, static_cast(9), - "example1", 6LL, std::string("str1"), std::string_view("view2"), "example2", true); - LOG_INFO(logger, "lazy dog test {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - static_cast(10), std::string_view("view1"), false, 8ULL, "example3", 3.0, - 2, std::string("str1")); - LOG_INFO(logger, "lazy test example over {}", "example1"); - LOG_INFO(logger, "test brown fox example {} {} {} {} {} {} {} {} {} {}", 3.0, true, std::string("str2"), - 8ULL, 1, "example1", false, static_cast(9), "example3", "example2"); - LOG_INFO(logger, "example lazy jumps {} {} {} {} {} {} {} {} {} {}", 2, 5L, "example2", 4.0f, - static_cast(9), 6LL, static_cast(10), true, 1, 7UL); - LOG_INFO(logger, "fox test jumps {} {} {} {} {} {} {} {} {}", std::string("str1"), "example2", 4.0f, - std::string_view("view1"), 6LL, 1, static_cast(9), 5L, std::string_view("view2")); - LOG_INFO(logger, "brown lazy example {} {} {} {} {} {} {} {} {}", "example2", - std::string_view("view1"), "example1", true, static_cast(9), 5L, 2, 1, 8ULL); - LOG_INFO(logger, "fox brown dog test {} {} {}", std::string_view("view2"), false, 4.0f); - LOG_INFO(logger, "example test brown {} {} {} {}", 6LL, 8ULL, true, 1); - LOG_INFO(logger, "over example logging brown {} {}", 5L, std::string("str1")); - LOG_INFO(logger, "example dog test {} {} {} {} {} {}", false, "example2", 4.0f, - std::string("str1"), "example3", 2); - LOG_INFO(logger, "over quick logging {} {} {}", 1, std::string_view("view2"), 8ULL); - LOG_INFO(logger, "logging jumps example {} {} {} {} {} {} {} {}", 7UL, std::string("str2"), 6LL, - "example2", 5L, 8ULL, false, std::string("str1")); - LOG_INFO(logger, "jumps dog quick {} {}", 8ULL, 5L); - LOG_INFO(logger, "logging fox test {} {} {} {}", 7UL, false, 2, std::string_view("view2")); - LOG_INFO(logger, "fox over dog quick {} {} {} {} {} {} {} {}", 7UL, "example1", - std::string_view("view1"), true, 2, 4.0f, 6LL, false); - LOG_INFO(logger, "test jumps quick {} {} {} {} {} {} {}", 2, false, "example1", 8ULL, 6LL, - static_cast(10), 4.0f); - LOG_INFO(logger, "jumps logging dog fox {}", std::string_view("view1")); - LOG_INFO(logger, "fox lazy test {} {} {} {} {} {} {} {}", std::string_view("view1"), 3.0, - "example1", true, std::string("str2"), 5L, 4.0f, static_cast(10)); - LOG_INFO(logger, "fox brown jumps {} {} {} {} {} {} {}", std::string("str1"), 7UL, - static_cast(9), std::string_view("view1"), false, 1, "example3"); - LOG_INFO(logger, "over example fox {} {} {} {}", std::string_view("view1"), "example1", 8ULL, - std::string_view("view2")); - LOG_INFO(logger, "example lazy quick {} {} {} {} {} {} {}", 8ULL, 2, - static_cast(10), 3.0, std::string("str2"), 4.0f, 7UL); - LOG_INFO(logger, "logging fox brown jumps {} {} {} {} {} {} {} {} {}", std::string_view("view1"), - 8ULL, std::string("str2"), true, std::string_view("view2"), 7UL, 3.0, false, "example2"); - LOG_INFO(logger, "over brown quick {} {}", true, 1); - LOG_INFO(logger, "brown dog jumps {} {} {}", false, 8ULL, 2); - LOG_INFO(logger, "dog brown quick lazy {} {} {} {} {}", "example3", "example1", 8ULL, 3.0, - "example2"); - LOG_INFO(logger, "fox quick brown over {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - "example2", 2, 8ULL, "example1", std::string("str1"), 4.0f, false, 3.0); - LOG_INFO(logger, "over fox lazy {} {} {} {} {} {}", 5L, 4.0f, std::string("str1"), 8ULL, - std::string_view("view2"), 3.0); - LOG_INFO(logger, "lazy dog test {} {} {} {} {} {} {} {}", 2, "example2", false, 6LL, - std::string("str1"), 8ULL, static_cast(9), 1); - LOG_INFO(logger, "lazy quick brown logging {} {}", 1, 4.0f); - LOG_INFO(logger, "over quick fox {} {} {} {} {} {}", std::string_view("view2"), - static_cast(10), 2, std::string("str2"), std::string("str1"), 3.0); - LOG_INFO(logger, "test dog jumps lazy {} {} {}", 6LL, "example2", 7UL); - LOG_INFO(logger, "lazy dog jumps over {}", 7UL); - LOG_INFO(logger, "logging jumps fox lazy {} {} {}", false, 6LL, 4.0f); - LOG_INFO(logger, "jumps fox example {} {}", "example2", std::string_view("view2")); - LOG_INFO(logger, "quick jumps test dog {} {} {} {} {} {}", 7UL, 8ULL, 1, 6LL, 4.0f, std::string_view("view1")); - LOG_INFO(logger, "brown example dog {} {} {} {} {} {}", 4.0f, false, std::string("str1"), - static_cast(9), 6LL, true); - LOG_INFO(logger, "brown logging example {} {} {} {}", static_cast(10), 7UL, false, 3.0); - LOG_INFO(logger, "quick fox test {} {} {} {} {} {}", 3.0, std::string_view("view2"), true, false, - std::string("str1"), std::string("str2")); - LOG_INFO(logger, "lazy quick over {} {} {} {} {} {} {}", 6LL, false, static_cast(9), true, - 7UL, 5L, std::string_view("view2")); - LOG_INFO(logger, "jumps lazy over {} {}", "example3", 2); - LOG_INFO(logger, "test dog jumps logging {} {} {} {} {} {} {} {} {} {}", false, 8ULL, - static_cast(9), 7UL, std::string_view("view2"), "example1", 1, 5L, "example3", 2); - LOG_INFO(logger, "brown logging quick example {} {} {} {} {} {} {} {}", 2, "example3", - static_cast(10), std::string_view("view1"), true, std::string("str2"), false, 5L); - LOG_INFO(logger, "over dog jumps quick {} {} {}", 3.0, 4.0f, 8ULL); - LOG_INFO(logger, "fox lazy test quick {} {} {} {} {} {} {} {}", 5L, 4.0f, "example2", - std::string("str2"), 6LL, static_cast(10), 7UL, std::string_view("view1")); - LOG_INFO(logger, "jumps over logging lazy {} {} {} {} {} {} {} {} {} {}", static_cast(10), - 6LL, 7UL, 1, 5L, 4.0f, std::string_view("view2"), false, "example1", 3.0); - LOG_INFO(logger, "lazy over test {} {}", std::string("str1"), 3.0); - LOG_INFO(logger, "fox brown over {} {} {} {} {} {} {} {}", 6LL, std::string("str1"), - static_cast(9), 2, "example1", 5L, false, std::string_view("view2")); - LOG_INFO(logger, "brown lazy fox {}", static_cast(9)); - LOG_INFO(logger, "fox dog brown {} {} {} {} {}", true, 8ULL, std::string_view("view2"), - std::string("str1"), 6LL); - LOG_INFO(logger, "dog example over {} {} {} {}", static_cast(10), 6LL, 1, 3.0); - LOG_INFO(logger, "jumps dog brown {} {} {} {} {} {} {} {}", std::string_view("view1"), - static_cast(9), true, std::string("str2"), 8ULL, 2, 4.0f, "example3"); - LOG_INFO(logger, "jumps test logging {} {}", "example3", std::string_view("view1")); - LOG_INFO(logger, "example dog logging over {} {} {} {} {} {} {} {} {} {}", 2, - static_cast(9), 5L, "example1", 6LL, true, std::string("str2"), 4.0f, 8ULL, 1); - LOG_INFO(logger, "dog logging lazy example {} {} {} {} {} {} {} {} {} {}", std::string("str2"), 1, - 5L, 3.0, std::string("str1"), static_cast(10), std::string_view("view1"), - 6LL, 7UL, static_cast(9)); - LOG_INFO(logger, "jumps logging fox brown {} {} {} {} {} {}", false, 4.0f, std::string("str1"), - std::string_view("view1"), "example2", 3.0); - LOG_INFO(logger, "fox brown example {} {} {} {} {}", 1, 5L, "example2", - static_cast(10), std::string("str1")); - LOG_INFO(logger, "test fox example brown {} {} {} {} {} {} {} {} {} {}", std::string("str1"), - "example2", 7UL, 2, 8ULL, std::string_view("view1"), static_cast(10), - true, false, 4.0f); - LOG_INFO(logger, "lazy brown jumps {} {} {} {} {} {} {} {} {} {}", 2, std::string("str1"), - std::string("str2"), 4.0f, 1, "example3", static_cast(10), true, false, - "example1"); - LOG_INFO(logger, "quick jumps test lazy {} {} {} {} {}", 1, static_cast(9), 7UL, - std::string("str1"), 4.0f); - LOG_INFO(logger, "example jumps over lazy {} {} {} {} {} {} {}", 8ULL, true, - std::string_view("view2"), 4.0f, static_cast(9), std::string_view("view1"), 6LL); - LOG_INFO(logger, "brown fox dog logging {} {} {} {} {} {} {} {} {} {}", 2, std::string("str2"), - "example1", 4.0f, 5L, false, 7UL, 1, 6LL, 8ULL); - LOG_INFO(logger, "lazy quick fox over {} {}", std::string_view("view2"), 4.0f); - LOG_INFO(logger, "jumps over example dog {} {}", std::string_view("view2"), static_cast(9)); - LOG_INFO(logger, "brown example over {} {}", std::string_view("view1"), std::string("str1")); - LOG_INFO(logger, "test example fox logging {} {} {} {}", 4.0f, std::string("str1"), "example1", - "example3"); - LOG_INFO(logger, "fox over lazy test {} {} {}", "example1", 3.0, static_cast(9)); - LOG_INFO(logger, "example dog lazy {} {} {} {} {}", "example1", 6LL, 7UL, 4.0f, 5L); - LOG_INFO(logger, "lazy logging over {} {} {} {} {} {} {} {} {}", false, static_cast(9), - static_cast(10), 8ULL, std::string("str2"), 2, 5L, "example1", std::string("str1")); - LOG_INFO(logger, "test quick jumps {} {} {} {} {}", true, "example2", std::string_view("view1"), - std::string("str1"), "example3"); - LOG_INFO(logger, "test brown dog {} {} {} {} {}", 8ULL, 2, 6LL, static_cast(10), - "example1"); - LOG_INFO(logger, "logging test brown {} {} {} {} {} {} {} {}", 1, "example2", - static_cast(10), std::string("str2"), 3.0, 6LL, static_cast(9), - std::string("str1")); - LOG_INFO(logger, "test jumps lazy {} {} {} {} {} {} {}", 4.0f, "example1", 6LL, "example2", 2, 3.0, 8ULL); - LOG_INFO(logger, "brown over dog {} {} {} {} {} {} {} {} {}", 1, 6LL, 3.0, std::string("str1"), - std::string_view("view2"), 5L, static_cast(10), false, static_cast(9)); - LOG_INFO(logger, "logging brown over example {} {} {} {} {} {} {} {} {}", "example3", 3.0, true, - false, std::string_view("view1"), 7UL, 6LL, std::string("str2"), "example2"); - LOG_INFO(logger, "jumps test quick {} {} {} {} {} {} {}", false, 4.0f, static_cast(9), - std::string_view("view2"), "example3", 3.0, std::string("str2")); - LOG_INFO(logger, "dog jumps test example {} {} {} {} {} {}", 5L, static_cast(10), - 4.0f, 8ULL, std::string_view("view1"), std::string("str1")); - LOG_INFO(logger, "brown over lazy example {} {} {} {} {} {} {} {}", std::string("str1"), - "example3", std::string_view("view1"), 5L, std::string_view("view2"), "example2", 2, true); - LOG_INFO(logger, "lazy dog test {} {} {}", true, 1, 2); - LOG_INFO(logger, "fox brown example {} {} {}", std::string("str1"), static_cast(10), 2); - LOG_INFO(logger, "example dog quick brown {} {} {} {} {} {} {} {}", 8ULL, 4.0f, 7UL, true, - std::string("str2"), std::string("str1"), std::string_view("view2"), 2); - LOG_INFO(logger, "example dog quick {}", true); - LOG_INFO(logger, "test dog quick {} {} {} {} {}", std::string_view("view2"), 5L, 8ULL, 7UL, 6LL); - LOG_INFO(logger, "brown lazy jumps {} {} {} {} {} {} {}", 1, 2, 3.0, std::string("str1"), - "example1", std::string_view("view1"), true); - LOG_INFO(logger, "fox over dog {} {} {} {} {} {} {} {}", "example3", std::string_view("view2"), 1, - true, "example1", std::string("str2"), "example2", static_cast(10)); - LOG_INFO(logger, "over brown quick {} {} {}", false, 8ULL, 4.0f); - LOG_INFO(logger, "quick example jumps fox {}", 6LL); - LOG_INFO(logger, "logging jumps quick {} {}", std::string("str2"), "example1"); - LOG_INFO(logger, "dog logging lazy {} {} {} {}", std::string_view("view2"), true, std::string("str1"), 8ULL); - LOG_INFO(logger, "example fox jumps dog {} {} {} {} {} {}", true, 3.0, 1, 7UL, "example3", false); - LOG_INFO(logger, "test example lazy {} {} {} {} {} {} {} {} {}", std::string_view("view1"), 3.0, - 1, 4.0f, 2, static_cast(10), std::string("str1"), true, "example1"); - LOG_INFO(logger, "logging dog test example {} {} {} {} {}", "example2", 4.0f, 8ULL, true, - std::string_view("view1")); - LOG_INFO(logger, "lazy example quick {} {} {} {} {} {} {} {} {} {}", false, 8ULL, 3.0, 6LL, - "example1", true, std::string_view("view1"), static_cast(10), "example3", - std::string("str1")); - LOG_INFO(logger, "fox quick lazy {} {} {}", 7UL, 3.0, 1); - LOG_INFO(logger, "brown quick fox test {} {} {} {} {} {} {}", std::string_view("view2"), 1, 6LL, - 5L, std::string("str2"), static_cast(10), true); - LOG_INFO(logger, "fox test logging {} {} {} {} {} {} {} {} {} {}", 5L, 1, 8ULL, std::string("str1"), - "example3", std::string_view("view1"), 4.0f, std::string("str2"), "example2", false); - LOG_INFO(logger, "brown fox jumps over {} {} {} {} {} {} {}", std::string("str1"), 5L, 3.0, - std::string_view("view2"), static_cast(10), false, std::string_view("view1")); - LOG_INFO(logger, "test lazy example {} {} {} {}", 6LL, 1, 5L, "example1"); - LOG_INFO(logger, "over dog brown {} {} {}", std::string("str2"), 4.0f, static_cast(9)); - LOG_INFO(logger, "example brown test {} {} {}", 4.0f, true, 3.0); - LOG_INFO(logger, "lazy test logging fox {} {}", 5L, 3.0); - LOG_INFO(logger, "example fox lazy quick {} {} {} {} {} {} {} {}", 6LL, 7UL, true, - static_cast(10), 3.0, std::string("str2"), "example1", std::string_view("view2")); - LOG_INFO(logger, "brown over test fox {} {} {} {} {} {} {} {} {}", 6LL, "example2", 3.0, 4.0f, 1, - std::string_view("view1"), std::string("str2"), false, true); - LOG_INFO(logger, "lazy over example {}", 4.0f); - LOG_INFO(logger, "lazy example fox {} {} {} {} {} {} {} {} {}", "example2", "example3", 3.0, 8ULL, - 1, std::string("str1"), 7UL, std::string_view("view2"), std::string("str2")); - LOG_INFO(logger, "brown test lazy quick {} {} {} {} {} {} {} {}", std::string("str2"), - static_cast(9), "example3", "example1", 8ULL, 4.0f, static_cast(10), 7UL); - LOG_INFO(logger, "fox example logging {} {} {} {} {} {} {}", 3.0, 5L, 8ULL, - std::string_view("view2"), 2, std::string("str2"), 4.0f); - LOG_INFO(logger, "brown fox over lazy {} {} {} {} {} {}", false, static_cast(9), - std::string_view("view1"), "example2", true, 6LL); - LOG_INFO(logger, "quick logging over {} {} {} {} {} {} {}", 5L, 4.0f, std::string("str2"), - "example1", 2, std::string_view("view1"), 7UL); - LOG_INFO(logger, "example lazy brown dog {} {} {} {} {} {} {} {} {}", "example1", false, 3.0, - 4.0f, "example3", std::string("str1"), "example2", 7UL, true); - LOG_INFO(logger, "over dog test lazy {} {}", static_cast(10), 6LL); - LOG_INFO(logger, "quick over dog example {} {} {} {}", 3.0, false, "example3", 7UL); - LOG_INFO(logger, "example test quick {} {} {} {} {} {} {} {} {} {}", true, - std::string_view("view1"), 4.0f, std::string("str2"), 2, static_cast(10), - 3.0, 7UL, 1, std::string_view("view2")); - LOG_INFO(logger, "over dog quick {} {} {} {} {} {} {} {} {} {}", 4.0f, std::string("str1"), 7UL, - 2, 6LL, static_cast(10), 8ULL, std::string_view("view1"), true, 3.0); - LOG_INFO(logger, "lazy test fox {} {}", 5L, 1); - LOG_INFO(logger, "test over dog {} {} {} {} {} {}", std::string("str2"), "example2", 7UL, - std::string_view("view2"), 8ULL, false); - LOG_INFO(logger, "brown fox test jumps {} {} {} {} {} {}", std::string_view("view2"), - static_cast(10), 4.0f, 2, std::string("str1"), 1); - LOG_INFO(logger, "over fox lazy {} {} {} {} {} {} {} {} {}", false, 2, static_cast(9), - 4.0f, std::string("str2"), "example3", 1, std::string("str1"), std::string_view("view1")); - LOG_INFO(logger, "fox example quick logging {} {}", "example2", 6LL); - LOG_INFO(logger, "jumps dog fox {} {}", 6LL, 4.0f); - LOG_INFO(logger, "dog brown test logging {} {} {} {}", std::string("str2"), - std::string_view("view2"), 1, std::string_view("view1")); - LOG_INFO(logger, "over brown dog test {} {} {} {} {} {} {}", 3.0, std::string("str1"), "example1", - "example2", 6LL, 7UL, static_cast(9)); - LOG_INFO(logger, "jumps example lazy brown {} {} {} {}", "example3", 4.0f, - std::string_view("view1"), "example1"); - LOG_INFO(logger, "over example dog {} {} {} {}", true, 1, false, std::string_view("view1")); - LOG_INFO(logger, "test over logging {} {} {} {} {} {} {} {} {}", 5L, std::string_view("view2"), - 6LL, std::string_view("view1"), 1, true, "example1", std::string("str2"), "example2"); - LOG_INFO(logger, "lazy example jumps quick {} {} {} {} {} {} {} {}", std::string_view("view2"), - std::string_view("view1"), static_cast(10), std::string("str2"), - "example1", static_cast(9), 7UL, 6LL); - LOG_INFO(logger, "jumps quick over brown {} {} {} {} {}", static_cast(9), true, 2, - std::string_view("view2"), "example3"); - LOG_INFO(logger, "lazy dog logging {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - static_cast(10), 5L, std::string_view("view1"), "example2", 8ULL, 6LL, - static_cast(9), 3.0); - LOG_INFO(logger, "quick jumps brown {} {} {} {} {} {} {} {} {} {}", 1, true, - std::string_view("view1"), 3.0, "example2", 4.0f, std::string("str2"), "example1", - std::string_view("view2"), std::string("str1")); - LOG_INFO(logger, "over brown logging dog {} {} {} {} {}", std::string("str1"), 3.0, 8ULL, - static_cast(9), false); - LOG_INFO(logger, "jumps brown over {}", "example1"); - LOG_INFO(logger, "lazy test quick {} {} {} {} {}", 2, false, true, static_cast(10), 1); - LOG_INFO(logger, "dog fox lazy brown {} {} {}", 6LL, std::string("str1"), "example3"); - LOG_INFO(logger, "test jumps logging {} {} {} {} {} {} {} {}", 3.0, static_cast(9), 7UL, - std::string("str2"), 1, "example1", 8ULL, true); - LOG_INFO(logger, "quick lazy jumps fox {} {} {} {}", "example2", std::string_view("view2"), - "example1", 4.0f); - LOG_INFO(logger, "logging jumps brown {} {}", "example1", 5L); - LOG_INFO(logger, "brown example over {} {} {} {} {} {} {}", std::string("str1"), - std::string("str2"), 8ULL, 3.0, static_cast(9), true, std::string_view("view1")); - LOG_INFO(logger, "over jumps brown {} {} {} {} {} {}", std::string_view("view1"), 4.0f, 2, - std::string("str2"), 3.0, 6LL); - LOG_INFO(logger, "quick jumps logging test {} {} {} {}", false, std::string("str1"), - std::string_view("view1"), 8ULL); - LOG_INFO(logger, "jumps fox lazy dog {} {} {} {} {} {} {} {} {}", true, static_cast(10), - std::string_view("view1"), "example1", 7UL, static_cast(9), "example2", 8ULL, 1); - LOG_INFO(logger, "logging over test dog {}", std::string("str1")); - LOG_INFO(logger, "quick logging test lazy {} {} {} {} {} {} {} {} {} {}", std::string("str2"), 8ULL, 1, 3.0, - std::string_view("view2"), 6LL, true, 7UL, static_cast(10), "example1"); - LOG_INFO(logger, "lazy over example brown {} {}", 2, 8ULL); - LOG_INFO(logger, "dog logging quick test {} {} {} {} {}", true, false, 2, 6LL, "example1"); - LOG_INFO(logger, "example test jumps {} {} {} {} {} {} {} {} {}", false, "example1", - std::string_view("view2"), 6LL, std::string("str1"), 3.0, 7UL, 4.0f, "example3"); - LOG_INFO(logger, "dog logging jumps {} {} {} {} {} {}", 3.0, 2, "example2", true, false, - static_cast(9)); - LOG_INFO(logger, "example test fox {}", 4.0f); - LOG_INFO(logger, "brown logging example {} {} {} {}", std::string("str1"), 1, "example3", 3.0); - LOG_INFO(logger, "dog jumps fox quick {} {} {} {} {} {} {} {} {} {}", static_cast(9), - "example1", "example2", static_cast(10), 2, true, 8ULL, - std::string_view("view1"), 1, 7UL); - LOG_INFO(logger, "over dog fox lazy {} {} {} {} {} {} {} {} {} {}", 8ULL, 6LL, - std::string_view("view2"), 3.0, std::string("str2"), 2, static_cast(9), - "example3", static_cast(10), "example1"); - LOG_INFO(logger, "brown test logging {} {} {} {} {} {} {} {} {}", 3.0, std::string("str2"), 2, - std::string_view("view1"), "example1", 6LL, true, std::string_view("view2"), false); - LOG_INFO(logger, "lazy fox brown {} {} {}", static_cast(9), std::string_view("view2"), - "example1"); - LOG_INFO(logger, "jumps lazy fox quick {} {} {} {} {} {} {} {}", false, 4.0f, 2, "example3", - std::string("str1"), true, "example1", 3.0); - LOG_INFO(logger, "lazy logging over {} {} {} {} {} {}", "example2", "example1", - std::string("str1"), false, 2, std::string_view("view2")); - LOG_INFO(logger, "test dog jumps example {} {} {}", static_cast(9), - static_cast(10), 8ULL); - LOG_INFO(logger, "example dog over quick {} {} {} {} {} {} {} {} {} {}", true, 1, - std::string("str1"), std::string_view("view1"), "example1", 3.0, false, 2, "example3", - static_cast(10)); - LOG_INFO(logger, "brown test example over {} {} {} {} {} {}", 8ULL, 3.0, std::string("str1"), - "example2", 5L, true); - LOG_INFO(logger, "brown example jumps {} {} {} {} {} {} {}", 7UL, false, 6LL, 3.0, "example1", - static_cast(9), 8ULL); - LOG_INFO(logger, "dog fox jumps {} {} {} {} {} {} {} {}", 6LL, 5L, 8ULL, 1, true, 2, - std::string("str2"), std::string_view("view1")); - LOG_INFO(logger, "brown quick test {} {}", static_cast(10), 6LL); - LOG_INFO(logger, "logging brown fox {} {} {} {}", true, 5L, 7UL, 3.0); - LOG_INFO(logger, "test jumps lazy brown {}", "example2"); - LOG_INFO(logger, "logging test lazy {}", true); - LOG_INFO(logger, "lazy fox dog example {} {} {} {} {} {} {} {} {} {}", std::string("str2"), - std::string_view("view1"), std::string("str1"), 5L, 7UL, static_cast(9), - "example1", 3.0, "example2", 6LL); - LOG_INFO(logger, "lazy test example logging {} {} {} {} {} {} {} {} {} {}", 6LL, "example3", - false, 8ULL, std::string("str1"), "example1", 3.0, true, 4.0f, 7UL); - LOG_INFO(logger, "dog logging over quick {} {}", 4.0f, false); - LOG_INFO(logger, "logging brown fox {}", "example3"); - LOG_INFO(logger, "dog logging brown {} {} {} {} {} {} {} {}", "example3", - std::string_view("view1"), static_cast(10), "example2", - std::string_view("view2"), 2, 8ULL, "example1"); - LOG_INFO(logger, "brown over dog {} {} {} {} {} {} {} {} {} {}", "example1", 6LL, 4.0f, true, - std::string_view("view1"), 1, 3.0, static_cast(9), "example3", 5L); - LOG_INFO(logger, "logging example test quick {} {} {} {} {} {} {} {} {}", std::string("str1"), - std::string_view("view2"), "example3", "example2", 8ULL, static_cast(9), 1, - static_cast(10), false); - LOG_INFO(logger, "fox over lazy jumps {} {} {} {} {} {} {} {} {}", 1, false, - std::string_view("view1"), 6LL, 4.0f, 5L, 3.0, static_cast(9), 7UL); - LOG_INFO(logger, "lazy test example over {} {} {} {} {} {} {} {} {}", static_cast(9), - "example3", "example1", "example2", 8ULL, std::string("str1"), false, 6LL, 3.0); - LOG_INFO(logger, "over logging fox brown {} {} {} {} {} {} {} {} {}", "example3", 3.0, 4.0f, - std::string_view("view1"), 7UL, true, 6LL, std::string("str2"), 2); - LOG_INFO(logger, "jumps lazy brown logging {} {} {}", "example3", std::string_view("view1"), 6LL); - LOG_INFO(logger, "brown jumps lazy {}", static_cast(10)); - LOG_INFO(logger, "test quick brown {} {} {}", "example1", false, std::string_view("view1")); - LOG_INFO(logger, "fox brown over {} {} {} {} {} {} {} {} {}", 2, "example3", 3.0, 4.0f, - std::string_view("view2"), "example2", 1, std::string("str1"), 7UL); - LOG_INFO(logger, "fox logging jumps example {} {} {} {} {}", "example1", 4.0f, - static_cast(10), "example2", true); - LOG_INFO(logger, "quick over jumps fox {} {} {} {} {} {} {} {}", 8ULL, 1, 4.0f, std::string_view("view2"), - 2, static_cast(10), std::string_view("view1"), std::string("str1")); - LOG_INFO(logger, "logging dog brown {} {}", 5L, std::string_view("view1")); - LOG_INFO(logger, "fox example brown dog {} {} {}", 2, "example1", 4.0f); - LOG_INFO(logger, "brown logging dog fox {} {} {} {} {} {} {} {} {} {}", false, 5L, 8ULL, - std::string("str1"), 2, "example2", 3.0, static_cast(10), 1, "example3"); - LOG_INFO(logger, "over jumps fox {} {} {} {} {} {} {}", static_cast(10), - std::string_view("view2"), static_cast(9), 2, 4.0f, std::string_view("view1"), - "example3"); - LOG_INFO(logger, "example fox logging {} {} {} {} {} {} {} {} {} {}", std::string("str2"), 4.0f, - std::string("str1"), 5L, static_cast(9), 8ULL, 7UL, - static_cast(10), 3.0, 6LL); - LOG_INFO(logger, "fox jumps dog {} {}", 4.0f, true); - LOG_INFO(logger, "quick over example {} {} {} {} {} {}", 7UL, std::string("str2"), 5L, "example1", false, 1); - LOG_INFO(logger, "brown lazy over logging {} {} {} {} {} {} {} {}", std::string("str2"), 1, 8ULL, - static_cast(10), 5L, 4.0f, true, 3.0); - LOG_INFO(logger, "over jumps example {} {} {} {} {} {} {}", 5L, "example3", 4.0f, 7UL, "example2", - static_cast(10), true); - LOG_INFO(logger, "jumps brown example {} {} {} {} {} {} {}", 2, 8ULL, 1, std::string("str1"), - std::string_view("view1"), false, static_cast(10)); - LOG_INFO(logger, "jumps quick brown lazy {} {}", false, 8ULL); - LOG_INFO(logger, "example quick lazy {} {} {} {} {} {} {} {} {} {}", 3.0, 2, - static_cast(10), 7UL, 6LL, std::string("str1"), 1, std::string("str2"), - "example3", std::string_view("view1")); - LOG_INFO(logger, "lazy logging quick {} {} {} {} {} {} {} {}", 4.0f, true, 1, 5L, 3.0, 2, - std::string_view("view1"), static_cast(10)); - LOG_INFO(logger, "lazy brown dog fox {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - false, static_cast(9), "example1", 4.0f, 7UL, static_cast(10), - 3.0, "example3"); - LOG_INFO(logger, "quick logging brown over {} {} {} {} {} {}", std::string_view("view2"), - "example2", 6LL, static_cast(9), static_cast(10), 4.0f); - LOG_INFO(logger, "logging fox example {} {} {} {} {} {} {}", 5L, std::string_view("view2"), 6LL, - "example3", 7UL, std::string("str1"), 2); - LOG_INFO(logger, "jumps lazy quick dog {} {} {} {}", 7UL, 5L, 6LL, std::string("str1")); - LOG_INFO(logger, "jumps over lazy {} {} {} {} {} {}", "example2", static_cast(9), 8ULL, 5L, - 1, "example3"); - LOG_INFO(logger, "dog jumps fox {} {} {} {} {}", 3.0, std::string_view("view2"), 8ULL, - static_cast(9), 2); - LOG_INFO(logger, "quick example fox {} {} {} {} {}", 8ULL, true, 7UL, static_cast(9), - "example2"); - LOG_INFO(logger, "test quick fox logging {} {} {} {} {} {}", "example1", false, - std::string("str2"), static_cast(9), 3.0, "example2"); - LOG_INFO(logger, "jumps logging example quick {} {} {}", 4.0f, std::string("str1"), 8ULL); - LOG_INFO(logger, "dog brown logging {} {}", false, "example2"); - LOG_INFO(logger, "dog fox brown quick {} {} {} {} {}", "example3", 1, std::string_view("view1"), - static_cast(9), 8ULL); - LOG_INFO(logger, "quick jumps test dog {} {}", 7UL, 8ULL); - LOG_INFO(logger, "fox example quick {} {} {} {} {} {} {} {} {} {}", 2, 4.0f, 1, 6LL, std::string("str1"), - "example2", std::string_view("view1"), 7UL, false, static_cast(10)); - LOG_INFO(logger, "test quick logging {} {} {} {} {} {} {}", std::string("str2"), false, 2, 7UL, - 8ULL, 4.0f, static_cast(9)); - LOG_INFO(logger, "over test brown {} {} {} {} {} {} {} {} {} {}", 8ULL, 6LL, false, true, - "example1", "example2", 7UL, std::string("str1"), 5L, std::string_view("view1")); - LOG_INFO(logger, "test example over lazy {}", 8ULL); - LOG_INFO(logger, "quick dog over {}", 4.0f); - LOG_INFO(logger, "example quick jumps {} {} {}", 8ULL, std::string("str2"), 4.0f); - LOG_INFO(logger, "fox brown lazy {} {} {} {} {}", 3.0, false, static_cast(10), - "example1", 1); - LOG_INFO(logger, "quick lazy jumps brown {} {} {} {} {} {} {}", static_cast(10), - 7UL, true, std::string("str1"), 1, "example1", std::string_view("view1")); - LOG_INFO(logger, "over jumps logging quick {} {} {} {} {}", "example3", std::string("str2"), true, 5L, 2); - LOG_INFO(logger, "quick fox logging {} {} {} {}", 6LL, 2, 7UL, 1); - LOG_INFO(logger, "dog fox quick jumps {} {}", 6LL, static_cast(9)); - LOG_INFO(logger, "dog over jumps fox {} {}", true, 5L); - LOG_INFO(logger, "logging example dog jumps {} {} {} {}", 4.0f, "example2", static_cast(9), - std::string_view("view1")); - LOG_INFO(logger, "logging fox test {} {} {} {} {} {} {} {} {} {}", "example1", 7UL, "example2", 2, - 1, 3.0, std::string("str2"), 5L, 4.0f, "example3"); - LOG_INFO(logger, "logging fox quick brown {} {} {}", "example1", 3.0, 6LL); - LOG_INFO(logger, "quick lazy brown test {} {} {} {}", "example1", std::string_view("view1"), - std::string("str1"), std::string_view("view2")); - LOG_INFO(logger, "over fox dog {} {} {} {} {} {} {} {}", "example1", static_cast(10), - true, 5L, std::string_view("view2"), 3.0, std::string("str1"), 2); - LOG_INFO(logger, "jumps logging over {} {} {} {} {} {} {} {} {} {}", 8ULL, std::string("str2"), 7UL, - "example3", 4.0f, static_cast(10), std::string_view("view1"), 2, 3.0, 6LL); - LOG_INFO(logger, "jumps fox over {} {} {} {}", std::string_view("view2"), 5L, 7UL, std::string_view("view1")); - LOG_INFO(logger, "example brown over jumps {}", 7UL); - LOG_INFO(logger, "fox example jumps test {}", true); - LOG_INFO(logger, "fox test over {} {} {}", std::string_view("view1"), "example3", std::string("str1")); - LOG_INFO(logger, "logging dog brown over {} {} {} {} {}", 6LL, std::string_view("view2"), - std::string("str2"), 5L, "example1"); - LOG_INFO(logger, "fox example dog {} {} {} {} {} {}", 2, 1, static_cast(10), 4.0f, - std::string("str2"), std::string_view("view2")); - LOG_INFO(logger, "fox dog jumps {} {} {} {} {} {} {} {} {}", "example2", std::string("str1"), - std::string_view("view2"), std::string_view("view1"), 8ULL, 4.0f, 2, "example3", - static_cast(10)); - LOG_INFO(logger, "fox logging dog {} {} {} {} {} {} {} {}", "example1", 1, std::string("str1"), - static_cast(10), "example2", false, 6LL, "example3"); - LOG_INFO(logger, "quick test jumps {} {} {} {}", std::string("str2"), 6LL, - static_cast(10), false); - LOG_INFO(logger, "over fox quick dog {} {} {} {} {} {}", std::string("str1"), true, - std::string("str2"), 4.0f, 7UL, 2); - LOG_INFO(logger, "fox dog test {} {} {} {} {}", "example1", std::string("str1"), 6LL, - static_cast(10), false); - LOG_INFO(logger, "brown jumps example over {} {} {} {} {} {} {} {} {}", std::string("str2"), - static_cast(9), 5L, "example2", std::string("str1"), "example3", - std::string_view("view2"), 4.0f, 3.0); - LOG_INFO(logger, "quick logging dog {} {} {} {} {} {} {} {} {} {}", std::string("str2"), false, - 8ULL, std::string("str1"), 3.0, 5L, 4.0f, 6LL, 7UL, "example2"); - LOG_INFO(logger, "fox dog quick {} {} {} {} {}", 3.0, true, 4.0f, 2, "example1"); - LOG_INFO(logger, "quick brown over logging {}", 2); - LOG_INFO(logger, "dog logging example {} {} {}", "example3", 1, "example1"); - LOG_INFO(logger, "logging over jumps {} {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - 4.0f, static_cast(10), std::string_view("view1"), "example3", "example1", - std::string("str2"), "example2", 3.0, 6LL); - LOG_INFO(logger, "jumps quick over {} {} {} {} {} {} {}", "example1", false, true, "example3", 5L, - std::string("str2"), static_cast(10)); - LOG_INFO(logger, "logging lazy brown fox {}", 6LL); - LOG_INFO(logger, "over quick brown dog {} {} {} {}", "example3", std::string("str2"), 1, 4.0f); - LOG_INFO(logger, "brown logging fox jumps {} {} {}", true, 5L, 2); - LOG_INFO(logger, "example test fox {} {}", true, 1); - LOG_INFO(logger, "quick test fox logging {} {} {} {} {} {}", static_cast(10), - 8ULL, 4.0f, std::string("str1"), 7UL, false); - LOG_INFO(logger, "dog logging fox test {} {} {} {} {} {} {}", false, "example3", - static_cast(10), 5L, 2, 6LL, std::string("str1")); - LOG_INFO(logger, "dog example jumps {} {}", std::string("str1"), 7UL); - LOG_INFO(logger, "dog over jumps test {} {} {} {} {} {} {}", std::string("str2"), false, 4.0f, - std::string_view("view1"), static_cast(10), true, 7UL); - LOG_INFO(logger, "lazy fox brown dog {} {}", std::string_view("view2"), 5L); - LOG_INFO(logger, "over quick test example {} {} {} {} {} {} {}", 7UL, 5L, 8ULL, 1, - static_cast(9), std::string_view("view2"), std::string("str2")); - LOG_INFO(logger, "brown over fox example {} {} {} {} {} {} {} {}", static_cast(10), 5L, - std::string_view("view1"), std::string("str2"), static_cast(9), 8ULL, "example3", 3.0); - LOG_INFO(logger, "logging jumps brown {} {} {} {}", 7UL, 3.0, true, "example1"); - LOG_INFO(logger, "brown quick logging example {} {} {} {} {}", "example2", - static_cast(10), 5L, static_cast(9), 6LL); - LOG_INFO(logger, "jumps logging fox over {} {} {} {} {} {} {} {}", 3.0, 2, "example2", "example1", - 4.0f, std::string("str1"), std::string_view("view2"), true); - LOG_INFO(logger, "over logging lazy dog {}", 6LL); - LOG_INFO(logger, "dog lazy over {}", std::string("str1")); - LOG_INFO(logger, "jumps over logging dog {} {} {} {} {} {} {} {}", 4.0f, "example1", 8ULL, false, - 2, 5L, static_cast(9), std::string_view("view1")); - LOG_INFO(logger, "brown quick jumps {} {} {} {} {} {} {} {}", std::string_view("view2"), true, - "example1", 8ULL, static_cast(10), std::string("str2"), "example2", - std::string_view("view1")); - LOG_INFO(logger, "logging dog lazy {} {} {}", "example3", std::string_view("view1"), std::string("str1")); - LOG_INFO(logger, "test logging fox {} {}", 7UL, 8ULL); - LOG_INFO(logger, "fox brown lazy {} {} {} {} {} {} {} {}", static_cast(10), - static_cast(9), 1, 8ULL, false, "example2", std::string("str1"), 7UL); - LOG_INFO(logger, "example fox dog {} {}", "example3", std::string_view("view2")); - LOG_INFO(logger, "logging dog jumps {} {} {} {} {} {} {} {} {}", "example3", - std::string_view("view2"), static_cast(10), static_cast(9), 7UL, - 1, "example2", std::string("str1"), true); - LOG_INFO(logger, "example fox brown {} {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - static_cast(10), 4.0f, 5L, 6LL, "example2", true, 2, "example1", - std::string("str2")); - LOG_INFO(logger, "fox over example {} {} {} {} {} {} {} {}", static_cast(10), 2, - 3.0, std::string("str1"), std::string("str2"), true, 1, "example3"); - LOG_INFO(logger, "example jumps brown fox {} {}", false, std::string_view("view2")); - LOG_INFO(logger, "brown jumps dog logging {} {} {} {} {} {} {} {}", 7UL, "example2", 6LL, - std::string_view("view1"), 1, static_cast(9), std::string("str2"), 5L); - LOG_INFO(logger, "example test quick logging {} {} {} {} {} {} {}", std::string_view("view1"), - true, std::string("str2"), 7UL, std::string_view("view2"), "example3", 3.0); - LOG_INFO(logger, "over lazy example jumps {} {} {} {} {} {} {}", std::string_view("view2"), - "example2", std::string_view("view1"), 8ULL, 6LL, false, 3.0); - LOG_INFO(logger, "jumps dog quick logging {} {}", "example2", std::string_view("view2")); - LOG_INFO(logger, "lazy example fox test {} {}", std::string("str2"), "example1"); - LOG_INFO(logger, "example quick jumps {}", "example2"); - LOG_INFO(logger, "quick fox example {} {} {} {} {} {} {}", "example2", std::string("str2"), 1, - 8ULL, true, "example1", 3.0); - LOG_INFO(logger, "lazy jumps dog {} {} {} {} {} {} {} {}", std::string_view("view1"), - static_cast(10), std::string_view("view2"), 7UL, std::string("str2"), - false, 1, 6LL); - LOG_INFO(logger, "fox lazy over {} {} {}", static_cast(9), 4.0f, "example1"); - LOG_INFO(logger, "brown quick jumps test {} {} {} {} {} {} {} {}", 5L, 4.0f, - std::string_view("view2"), "example2", "example1", true, false, 2); - LOG_INFO(logger, "brown fox quick {} {} {}", "example3", static_cast(9), std::string("str2")); - LOG_INFO(logger, "lazy dog quick {} {} {} {} {} {}", 8ULL, "example1", 7UL, "example3", 3.0, 4.0f); - LOG_INFO(logger, "over dog test {} {} {} {} {}", static_cast(9), std::string("str2"), - std::string_view("view1"), std::string("str1"), true); - LOG_INFO(logger, "quick brown logging {} {} {} {} {} {} {} {} {} {}", 1, 2, "example2", - std::string("str2"), 5L, false, static_cast(10), std::string("str1"), - std::string_view("view2"), "example1"); - LOG_INFO(logger, "dog over test {}", std::string("str2")); - LOG_INFO(logger, "example logging fox test {} {} {}", true, 2, std::string_view("view1")); - LOG_INFO(logger, "logging fox quick {} {} {} {} {}", "example3", 6LL, true, 4.0f, 7UL); - LOG_INFO(logger, "logging brown test jumps {} {} {} {} {}", 2, 3.0, "example2", 5L, static_cast(9)); - LOG_INFO(logger, "dog example logging lazy {} {} {}", "example2", "example1", 2); - LOG_INFO(logger, "logging fox lazy jumps {} {} {} {} {} {} {}", static_cast(10), - false, "example2", 8ULL, "example1", "example3", 6LL); - LOG_INFO(logger, "test logging quick over {}", "example1"); - LOG_INFO(logger, "test quick example {} {}", "example1", 1); - LOG_INFO(logger, "dog lazy test brown {} {} {} {} {} {} {} {} {} {}", 5L, 2, true, std::string("str1"), - "example2", std::string_view("view2"), 1, static_cast(10), 3.0, 6LL); - LOG_INFO(logger, "over brown jumps fox {} {} {} {} {} {} {} {} {} {}", - static_cast(10), 2, "example1", 6LL, "example3", 7UL, - std::string_view("view2"), 3.0, "example2", std::string_view("view1")); - LOG_INFO(logger, "dog quick test brown {} {} {} {}", std::string("str1"), "example2", - std::string("str2"), 8ULL); - LOG_INFO(logger, "logging fox brown {} {} {} {} {} {}", std::string("str1"), 6LL, 1, "example1", 4.0f, true); - LOG_INFO(logger, "jumps over test quick {} {} {} {} {} {} {}", std::string("str2"), 6LL, true, - "example2", 7UL, 5L, 3.0); - LOG_INFO(logger, "example logging over {} {} {} {} {}", std::string("str1"), 5L, "example2", false, 7UL); - LOG_INFO(logger, "example quick fox dog {} {} {} {} {} {}", std::string_view("view2"), - static_cast(9), std::string("str1"), std::string("str2"), false, 1); - LOG_INFO(logger, "example dog lazy {} {} {}", 2, 6LL, 8ULL); - LOG_INFO(logger, "dog lazy example {} {} {} {} {} {}", 5L, "example2", "example3", 7UL, - std::string("str1"), 1); - LOG_INFO(logger, "brown lazy logging quick {}", static_cast(9)); - LOG_INFO(logger, "jumps test dog fox {} {} {} {} {} {} {} {}", 7UL, "example1", 5L, 6LL, 8ULL, - false, true, 4.0f); - LOG_INFO(logger, "dog quick logging test {} {} {} {} {}", 3.0, 2, true, 5L, std::string_view("view1")); - LOG_INFO(logger, "dog over lazy {} {} {} {} {} {} {}", 5L, "example3", std::string("str1"), - "example2", 6LL, 8ULL, std::string("str2")); - LOG_INFO(logger, "example quick jumps {} {} {} {}", "example2", static_cast(10), false, 7UL); - LOG_INFO(logger, "quick fox brown {}", true); - LOG_INFO(logger, "jumps over lazy dog {} {} {} {} {} {} {}", 7UL, 6LL, 8ULL, false, 5L, 3.0, 2); - LOG_INFO(logger, "brown quick logging {} {} {}", 1, static_cast(10), std::string("str1")); - LOG_INFO(logger, "jumps lazy example {} {} {} {} {}", 1, static_cast(10), 6LL, 5L, - "example1"); - LOG_INFO(logger, "example jumps quick {} {} {} {} {} {}", std::string_view("view1"), - std::string_view("view2"), 7UL, 3.0, 6LL, "example1"); - LOG_INFO(logger, "over jumps logging {} {} {} {} {} {} {} {} {} {}", 2, "example1", 4.0f, 6LL, - 7UL, 3.0, std::string_view("view2"), 1, static_cast(9), 8ULL); - LOG_INFO(logger, "lazy jumps dog {} {} {} {}", static_cast(9), 5L, 2, 4.0f); - LOG_INFO(logger, "fox dog jumps example {} {} {} {} {} {} {} {} {}", 5L, "example1", 4.0f, 2, - 8ULL, static_cast(9), "example2", 6LL, 7UL); - LOG_INFO(logger, "logging fox lazy jumps {} {} {} {} {} {} {} {} {}", 2, std::string("str1"), - std::string_view("view2"), std::string_view("view1"), 4.0f, false, "example2", 5L, - static_cast(10)); - LOG_INFO(logger, "test quick brown example {} {} {} {} {} {} {}", 3.0, false, std::string("str1"), - true, 7UL, "example1", 2); - LOG_INFO(logger, "dog fox jumps {} {} {} {} {} {} {} {} {}", 4.0f, 1, 2, "example1", - static_cast(9), "example3", 5L, 3.0, std::string("str2")); - LOG_INFO(logger, "dog fox brown {} {} {} {}", 2, 1, std::string_view("view1"), std::string("str2")); - LOG_INFO(logger, "lazy test brown example {} {} {} {} {} {}", "example1", true, "example2", - std::string("str2"), static_cast(9), 3.0); - LOG_INFO(logger, "logging brown quick example {} {}", 5L, std::string("str1")); - LOG_INFO(logger, "example fox lazy dog {} {} {} {} {} {} {}", true, 1, - static_cast(10), false, 5L, "example2", 6LL); - LOG_INFO(logger, "logging dog brown quick {} {} {} {} {}", static_cast(9), 1, - std::string("str1"), 7UL, 4.0f); - LOG_INFO(logger, "logging lazy quick {}", false); - LOG_INFO(logger, "over lazy jumps {} {} {} {}", "example3", "example2", "example1", 2); - LOG_INFO(logger, "lazy dog fox {} {} {} {} {}", "example1", true, 3.0, std::string("str1"), - static_cast(10)); - LOG_INFO(logger, "over logging example dog {} {} {} {} {} {}", true, - static_cast(10), 1, "example1", std::string_view("view2"), "example3"); - LOG_INFO(logger, "brown lazy example {} {} {} {} {} {} {}", 1, 6LL, 7UL, "example2", "example1", - std::string_view("view2"), false); - LOG_INFO(logger, "example over test {} {} {} {}", true, std::string_view("view1"), - static_cast(9), static_cast(10)); - LOG_INFO(logger, "test dog fox {} {} {} {} {} {} {} {}", "example3", std::string("str2"), - "example2", 3.0, 7UL, true, std::string_view("view1"), 6LL); - LOG_INFO(logger, "dog test fox {}", std::string_view("view1")); - LOG_INFO(logger, "jumps over lazy {} {} {} {} {}", std::string_view("view2"), false, "example3", 3.0, 4.0f); - LOG_INFO(logger, "example test over logging {} {} {} {} {} {} {} {} {}", 3.0, std::string("str2"), - std::string("str1"), 4.0f, 8ULL, 1, std::string_view("view1"), - static_cast(10), 7UL); - LOG_INFO(logger, "quick dog logging {} {} {} {} {} {} {} {}", static_cast(9), 8ULL, true, - 2, std::string("str1"), "example1", 1, 3.0); - LOG_INFO(logger, "quick logging jumps {} {}", "example3", "example1"); - LOG_INFO(logger, "example brown quick {}", "example1"); - LOG_INFO(logger, "jumps fox logging test {} {}", static_cast(9), 4.0f); - LOG_INFO(logger, "jumps fox lazy over {} {} {} {}", "example3", std::string("str2"), "example2", 5L); - LOG_INFO(logger, "example test logging {}", 7UL); - LOG_INFO(logger, "quick example dog {} {} {} {} {} {} {}", 4.0f, 6LL, 8ULL, - static_cast(10), true, "example3", 2); - LOG_INFO(logger, "lazy test fox {} {}", static_cast(9), "example1"); - LOG_INFO(logger, "logging lazy dog jumps {}", false); - LOG_INFO(logger, "brown jumps lazy fox {} {} {} {} {} {} {}", 8ULL, "example3", "example1", - std::string_view("view2"), 3.0, std::string("str1"), 2); - LOG_INFO(logger, "lazy quick dog {} {} {} {} {}", 8ULL, std::string_view("view2"), 7UL, false, - std::string_view("view1")); - LOG_INFO(logger, "fox logging brown jumps {} {}", 8ULL, std::string("str1")); - LOG_INFO(logger, "lazy quick brown example {} {} {} {}", 4.0f, "example3", true, false); - LOG_INFO(logger, "dog example brown fox {} {} {} {} {} {} {} {} {}", false, 1, "example2", 4.0f, - 8ULL, true, "example3", 2, std::string_view("view2")); - LOG_INFO(logger, "test quick over example {} {} {} {} {} {} {} {} {} {}", 2, - std::string_view("view2"), 3.0, 4.0f, false, "example2", 6LL, "example3", 5L, 7UL); - LOG_INFO(logger, "over dog fox {} {}", "example3", 8ULL); - LOG_INFO(logger, "fox over jumps {} {}", 3.0, 2); - LOG_INFO(logger, "jumps quick lazy over {} {}", static_cast(9), 1); - LOG_INFO(logger, "logging fox jumps {} {} {} {} {} {}", static_cast(10), - std::string_view("view1"), "example2", 2, 4.0f, 6LL); - LOG_INFO(logger, "lazy jumps example test {} {} {}", static_cast(10), 3.0, true); - LOG_INFO(logger, "lazy quick dog over {} {} {} {} {} {} {} {}", "example2", - static_cast(10), std::string("str2"), false, true, - std::string_view("view1"), 8ULL, "example3"); - LOG_INFO(logger, "logging test fox {} {} {} {}", static_cast(10), - std::string_view("view2"), false, "example2"); - LOG_INFO(logger, "example quick over {} {} {} {} {} {} {} {}", "example3", std::string_view("view1"), - 4.0f, std::string("str1"), true, static_cast(9), "example2", 1); - LOG_INFO(logger, "fox jumps quick lazy {} {}", 6LL, 1); - LOG_INFO(logger, "fox jumps logging brown {} {} {} {} {} {} {} {} {} {}", static_cast(9), 1, - std::string("str1"), "example2", 5L, "example3", std::string_view("view2"), 8ULL, 4.0f, 2); - LOG_INFO(logger, "test over fox lazy {} {} {}", false, std::string("str2"), "example3"); - LOG_INFO(logger, "jumps brown fox dog {} {} {} {}", true, 8ULL, std::string("str2"), "example3"); - LOG_INFO(logger, "quick fox lazy dog {} {} {} {} {} {} {}", 7UL, "example1", 3.0, 4.0f, - static_cast(9), static_cast(10), 5L); - LOG_INFO(logger, "lazy example logging {} {} {} {} {} {} {} {} {} {}", true, 1, 7UL, 8ULL, - std::string("str2"), std::string_view("view1"), 2, false, 6LL, "example3"); - LOG_INFO(logger, "dog brown logging {} {} {}", static_cast(10), 8ULL, 7UL); - LOG_INFO(logger, "test example lazy logging {} {} {} {} {} {} {} {}", 8ULL, 3.0, 5L, 4.0f, - std::string_view("view1"), std::string("str2"), static_cast(10), - "example1"); - LOG_INFO(logger, "dog logging over {} {} {} {} {} {}", 2, std::string("str2"), - static_cast(9), 8ULL, "example3", static_cast(10)); - LOG_INFO(logger, "test fox over {} {} {} {} {} {}", true, static_cast(9), 5L, 1, - std::string_view("view2"), "example2"); - LOG_INFO(logger, "lazy fox logging {} {} {}", 3.0, std::string_view("view1"), std::string_view("view2")); - LOG_INFO(logger, "logging over example test {} {} {} {} {} {} {}", std::string_view("view1"), - std::string("str2"), 2, "example3", 4.0f, 5L, "example1"); - LOG_INFO(logger, "fox example lazy over {} {} {} {} {} {} {} {}", "example1", false, true, 2, 5L, - static_cast(10), "example2", 7UL); - LOG_INFO(logger, "example fox lazy test {} {} {} {} {} {} {}", std::string_view("view2"), - std::string("str2"), static_cast(9), std::string_view("view1"), 7UL, "example2", 6LL); - LOG_INFO(logger, "quick test jumps example {} {} {} {}", "example3", 6LL, std::string_view("view1"), 3.0); - LOG_INFO(logger, "jumps over brown example {} {}", 4.0f, 8ULL); - LOG_INFO(logger, "jumps quick dog {} {} {} {} {} {}", 3.0, 8ULL, 7UL, 5L, "example1", std::string("str1")); - LOG_INFO(logger, "quick dog brown lazy {} {} {} {}", 2, true, 8ULL, static_cast(9)); - LOG_INFO(logger, "quick fox jumps {} {} {} {} {} {} {} {} {}", 8ULL, 7UL, static_cast(9), - 2, 4.0f, 1, std::string_view("view2"), std::string_view("view1"), std::string("str2")); - LOG_INFO(logger, "lazy example test logging {} {} {} {} {} {} {} {} {} {}", 5L, 2, 3.0, std::string("str1"), - "example2", std::string_view("view2"), 1, std::string("str2"), true, "example1"); - LOG_INFO(logger, "fox lazy jumps {} {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - "example1", std::string_view("view1"), 2, 6LL, 4.0f, "example2", - static_cast(10), 1, true); - LOG_INFO(logger, "dog test quick jumps {} {} {}", static_cast(10), 1, 6LL); - LOG_INFO(logger, "logging brown dog quick {} {} {} {}", true, 6LL, 4.0f, static_cast(9)); - LOG_INFO(logger, "lazy over dog logging {} {} {} {} {} {} {}", "example2", "example3", 4.0f, 5L, - true, static_cast(10), std::string("str1")); - LOG_INFO(logger, "lazy quick logging {} {} {} {}", 3.0, std::string("str1"), 2, std::string("str2")); - LOG_INFO(logger, "dog jumps logging lazy {} {}", 6LL, 4.0f); - LOG_INFO(logger, "logging fox dog quick {} {} {} {} {} {} {} {}", std::string_view("view1"), - "example2", true, "example1", 1, std::string_view("view2"), 7UL, 2); - LOG_INFO(logger, "brown logging over {} {} {} {} {} {} {}", std::string("str1"), 5L, - std::string("str2"), static_cast(10), "example3", 8ULL, "example1"); - LOG_INFO(logger, "test fox dog {} {} {}", std::string("str2"), static_cast(10), 2); - LOG_INFO(logger, "jumps fox brown {} {} {} {} {} {} {} {} {} {}", "example3", - static_cast(9), 5L, 8ULL, 3.0, std::string_view("view2"), 2, "example1", 4.0f, 1); - LOG_INFO(logger, "jumps lazy test dog {} {} {} {} {} {} {}", 3.0, true, 7UL, 4.0f, 6LL, - std::string("str1"), 2); - LOG_INFO(logger, "logging quick brown lazy {} {} {} {} {}", false, std::string_view("view2"), - std::string_view("view1"), 1, "example1"); - LOG_INFO(logger, "over brown fox logging {} {} {} {} {} {}", 5L, static_cast(9), - std::string("str2"), "example3", std::string("str1"), 8ULL); - LOG_INFO(logger, "quick brown logging {} {} {} {} {} {} {} {} {} {}", std::string("str1"), - "example3", "example1", 5L, static_cast(9), 1, "example2", 7UL, 2, 8ULL); - LOG_INFO(logger, "quick brown logging {} {} {} {} {} {} {} {} {} {}", - static_cast(10), static_cast(9), std::string_view("view2"), 6LL, - "example1", 7UL, 4.0f, false, std::string("str2"), 8ULL); - LOG_INFO(logger, "fox dog lazy test {} {} {}", std::string("str2"), static_cast(9), 5L); - LOG_INFO(logger, "quick example over {} {} {} {} {} {} {} {} {} {}", 6LL, - std::string_view("view2"), static_cast(10), true, 2, - static_cast(9), "example1", std::string("str1"), std::string("str2"), "example2"); - LOG_INFO(logger, "over example fox {} {} {}", std::string("str2"), "example3", std::string_view("view1")); - LOG_INFO(logger, "brown logging test {} {} {} {} {}", std::string("str1"), - std::string_view("view1"), std::string("str2"), false, 1); - LOG_INFO(logger, "logging quick test dog {} {} {} {} {}", 8ULL, std::string_view("view2"), - std::string_view("view1"), "example1", true); - LOG_INFO(logger, "dog example brown lazy {} {} {} {} {} {} {}", "example3", - std::string_view("view1"), static_cast(10), 2, 5L, "example2", true); - LOG_INFO(logger, "jumps brown fox {} {} {} {} {} {} {} {} {}", "example1", 4.0f, std::string("str1"), 8ULL, - std::string_view("view1"), static_cast(9), "example3", true, std::string_view("view2")); - LOG_INFO(logger, "logging over lazy {} {} {} {}", 2, false, 1, std::string_view("view2")); - LOG_INFO(logger, "example quick brown fox {} {} {} {} {}", 6LL, false, 3.0, 2, static_cast(9)); - LOG_INFO(logger, "test fox over logging {} {} {} {} {} {} {} {} {}", 2, 4.0f, 8ULL, 7UL, - "example1", std::string_view("view2"), false, "example2", 5L); - LOG_INFO(logger, "test lazy fox {} {} {} {} {} {}", 7UL, static_cast(9), 4.0f, - std::string_view("view1"), "example2", "example3"); - LOG_INFO(logger, "brown logging lazy {} {} {} {} {} {} {}", 4.0f, 7UL, std::string_view("view2"), - 8ULL, static_cast(10), "example2", "example1"); - LOG_INFO(logger, "test lazy over {} {} {} {} {} {} {} {} {} {}", 7UL, std::string_view("view2"), - 2, true, "example1", 4.0f, false, std::string("str1"), "example2", "example3"); - LOG_INFO(logger, "logging over test {} {} {} {}", 5L, "example1", static_cast(10), 7UL); - LOG_INFO(logger, "over dog lazy quick {} {}", 8ULL, 6LL); - LOG_INFO(logger, "brown example quick {}", "example1"); - LOG_INFO(logger, "test logging example fox {} {} {} {} {} {} {} {} {}", static_cast(9), - "example1", "example2", 4.0f, 3.0, std::string_view("view2"), 7UL, 5L, 8ULL); - LOG_INFO(logger, "quick example fox {}", true); - LOG_INFO(logger, "test dog fox {}", std::string_view("view1")); - LOG_INFO(logger, "quick lazy over test {} {} {} {} {} {} {} {}", 8ULL, 2, std::string("str1"), - "example2", "example1", 3.0, std::string_view("view1"), std::string_view("view2")); - LOG_INFO(logger, "fox dog jumps {} {} {} {} {} {} {} {} {} {}", std::string("str1"), 7UL, - "example1", 8ULL, 1, "example2", static_cast(9), std::string_view("view1"), 2, false); - LOG_INFO(logger, "example logging quick dog {} {} {} {} {} {}", static_cast(9), "example2", - std::string("str2"), 5L, 8ULL, std::string_view("view2")); - LOG_INFO(logger, "logging dog quick fox {} {} {} {} {} {} {} {} {}", std::string("str1"), 4.0f, - std::string("str2"), static_cast(9), 3.0, static_cast(10), - std::string_view("view2"), "example1", 5L); - LOG_INFO(logger, "over dog jumps {} {} {} {}", std::string_view("view2"), static_cast(9), - 4.0f, static_cast(10)); - LOG_INFO(logger, "logging example fox jumps {} {} {} {} {} {} {}", true, false, - static_cast(9), 5L, 7UL, 6LL, std::string_view("view2")); - LOG_INFO(logger, "over quick brown {} {} {} {} {} {} {} {}", 1, 2, false, true, 4.0f, - std::string_view("view2"), static_cast(10), std::string("str2")); - LOG_INFO(logger, "brown lazy logging {} {} {} {} {} {}", "example3", 3.0, - static_cast(10), 8ULL, 6LL, std::string("str1")); - LOG_INFO(logger, "example over dog {} {} {} {} {} {} {} {} {}", "example2", 2, 7UL, true, 8ULL, - "example3", 4.0f, 1, false); - LOG_INFO(logger, "example over fox {}", "example1"); - LOG_INFO(logger, "over example brown {}", "example1"); - LOG_INFO(logger, "over jumps fox lazy {} {} {} {} {} {} {} {} {} {}", 2, 4.0f, 8ULL, - std::string_view("view1"), static_cast(9), true, std::string("str1"), "example2", - std::string_view("view2"), 6LL); - LOG_INFO(logger, "brown logging example {} {}", "example3", std::string_view("view2")); - LOG_INFO(logger, "brown over fox {} {} {} {} {} {} {} {}", 1, "example1", std::string("str2"), - true, std::string_view("view1"), std::string_view("view2"), 3.0, static_cast(9)); - LOG_INFO(logger, "dog over quick {} {} {} {} {}", std::string("str2"), 8ULL, 4.0f, 5L, - static_cast(9)); - LOG_INFO(logger, "brown dog quick lazy {} {} {} {} {}", "example3", 3.0, 7UL, "example1", std::string("str1")); - LOG_INFO(logger, "dog lazy logging quick {} {} {} {} {}", std::string_view("view1"), 6LL, 2, - "example1", "example2"); - LOG_INFO(logger, "over quick test {} {} {} {}", std::string("str1"), 3.0, 6LL, std::string_view("view1")); - LOG_INFO(logger, "fox brown quick lazy {} {} {} {}", 3.0, "example3", 5L, std::string("str2")); - LOG_INFO(logger, "example over lazy {} {} {}", 7UL, 5L, 6LL); - LOG_INFO(logger, "quick example dog {} {} {} {}", "example1", std::string("str2"), - std::string_view("view2"), 5L); - LOG_INFO(logger, "example brown over logging {} {} {} {} {} {} {} {} {}", std::string("str2"), - 6LL, "example3", "example2", 4.0f, false, static_cast(10), 1, 2); - LOG_INFO(logger, "test brown quick {} {} {} {} {} {} {} {} {} {}", std::string("str2"), 7UL, - std::string_view("view1"), true, "example1", 6LL, static_cast(9), 1, - std::string("str1"), 5L); - LOG_INFO(logger, "brown dog jumps {} {} {} {} {} {} {} {} {} {}", 7UL, static_cast(10), - false, true, 8ULL, 1, 4.0f, std::string("str1"), "example3", std::string_view("view2")); - LOG_INFO(logger, "example lazy over test {} {} {} {} {}", 1, 3.0, 2, static_cast(10), 7UL); - LOG_INFO(logger, "lazy quick fox example {} {} {} {} {} {}", "example3", "example2", 2, - std::string("str1"), static_cast(10), 4.0f); - LOG_INFO(logger, "quick fox dog lazy {} {} {} {} {} {} {} {} {} {}", 5L, std::string_view("view2"), - 4.0f, 3.0, 2, std::string("str2"), "example1", 7UL, "example2", 6LL); - LOG_INFO(logger, "quick jumps over {} {} {} {} {} {} {}", 3.0, true, 2, "example2", - std::string("str2"), std::string_view("view2"), 7UL); - LOG_INFO(logger, "over jumps fox {} {} {} {} {}", "example3", std::string("str1"), - static_cast(9), std::string_view("view2"), 2); - LOG_INFO(logger, "quick brown example {} {} {} {} {} {} {}", "example1", - std::string_view("view2"), true, "example2", false, 3.0, static_cast(10)); - LOG_INFO(logger, "test dog lazy {} {} {} {} {} {} {}", 5L, std::string("str1"), 8ULL, 2, - "example2", true, false); - LOG_INFO(logger, "brown lazy example {} {} {}", "example3", "example1", std::string_view("view2")); - LOG_INFO(logger, "test logging brown {} {} {} {} {} {} {} {}", 5L, 8ULL, false, "example1", - "example3", 1, static_cast(9), std::string_view("view1")); - LOG_INFO(logger, "fox lazy over {} {} {} {} {} {} {}", 3.0, 5L, std::string_view("view2"), 2, - static_cast(10), static_cast(9), 7UL); - LOG_INFO(logger, "logging jumps over {} {} {} {}", "example2", 4.0f, 5L, std::string_view("view2")); - LOG_INFO(logger, "jumps lazy quick brown {} {} {} {} {} {} {} {} {}", "example2", 4.0f, "example3", - static_cast(9), 2, 7UL, 5L, std::string("str1"), std::string_view("view1")); - LOG_INFO(logger, "jumps example lazy dog {} {} {} {} {}", static_cast(9), - std::string("str2"), 3.0, static_cast(10), false); - LOG_INFO(logger, "lazy over example {} {} {} {} {}", 2, "example1", - static_cast(10), std::string("str2"), "example2"); - LOG_INFO(logger, "quick logging brown fox {} {}", std::string("str1"), 7UL); - LOG_INFO(logger, "over test brown quick {}", true); - LOG_INFO(logger, "lazy over dog brown {} {} {} {} {}", 2, 1, "example2", true, "example1"); - LOG_INFO(logger, "dog test fox {} {} {} {} {} {} {} {} {} {}", static_cast(10), - false, std::string_view("view2"), std::string_view("view1"), 2, "example1", - static_cast(9), "example3", "example2", std::string("str2")); - LOG_INFO(logger, "over dog quick {} {} {} {} {} {}", "example2", 5L, static_cast(9), 1, true, 3.0); - LOG_INFO(logger, "logging jumps example fox {} {} {} {} {} {}", std::string("str2"), 2, false, - "example3", "example1", static_cast(9)); - LOG_INFO(logger, "jumps dog example {}", std::string("str1")); - LOG_INFO(logger, "over logging fox {} {} {} {} {} {} {} {}", "example3", std::string_view("view2"), - 4.0f, false, 1, std::string("str2"), 5L, std::string_view("view1")); - LOG_INFO(logger, "over brown fox lazy {} {} {} {} {}", true, 8ULL, "example2", - std::string_view("view2"), static_cast(9)); - LOG_INFO(logger, "fox lazy over {} {} {} {} {} {} {} {} {} {}", "example3", std::string("str1"), false, - "example1", 1, "example2", 5L, std::string_view("view1"), static_cast(10), 6LL); - LOG_INFO(logger, "example dog brown {} {} {} {} {} {} {} {}", true, "example1", std::string_view("view1"), - std::string_view("view2"), "example2", 5L, static_cast(10), false); - LOG_INFO(logger, "jumps dog test over {} {} {} {} {}", std::string("str2"), "example2", 2, 3.0, - std::string_view("view1")); - LOG_INFO(logger, "test over brown dog {} {} {} {} {} {}", std::string("str1"), 5L, false, - static_cast(9), std::string("str2"), std::string_view("view2")); - LOG_INFO(logger, "jumps example dog logging {} {}", "example3", true); - LOG_INFO(logger, "dog quick jumps {} {} {} {}", 3.0, static_cast(9), false, 4.0f); - LOG_INFO(logger, "dog over example logging {} {}", 4.0f, std::string("str1")); - LOG_INFO(logger, "brown fox logging {} {} {} {} {} {} {}", false, 5L, 7UL, std::string_view("view1"), - static_cast(9), static_cast(10), "example3"); - LOG_INFO(logger, "brown fox quick dog {} {} {} {} {} {} {}", 4.0f, true, "example2", - std::string_view("view1"), 3.0, 7UL, 6LL); - LOG_INFO(logger, "lazy dog quick test {} {} {} {} {}", static_cast(9), std::string("str1"), - "example1", 2, std::string_view("view2")); - LOG_INFO(logger, "logging example dog {} {} {} {} {} {}", 7UL, static_cast(9), false, 1, 2, - "example2"); - LOG_INFO(logger, "jumps dog example test {} {} {} {} {} {}", 6LL, 4.0f, 7UL, "example1", false, - std::string("str1")); - LOG_INFO(logger, "jumps brown example over {} {} {}", 5L, 8ULL, static_cast(10)); - LOG_INFO(logger, "logging fox dog {} {} {} {} {} {}", true, 6LL, 3.0, 1, false, 8ULL); - LOG_INFO(logger, "example logging brown {} {}", static_cast(10), 5L); - LOG_INFO(logger, "jumps example test quick {} {} {} {} {}", 5L, std::string("str1"), - static_cast(10), 1, true); - LOG_INFO(logger, "fox jumps example test {}", "example3"); - LOG_INFO(logger, "over test quick dog {} {} {} {}", static_cast(10), 6LL, 8ULL, - "example2"); - LOG_INFO(logger, "quick example jumps dog {} {} {} {} {} {} {}", false, 7UL, 5L, - static_cast(9), "example3", std::string("str1"), true); - LOG_INFO(logger, "test logging jumps lazy {} {} {} {} {} {}", std::string_view("view1"), 7UL, 1, - 2, "example1", false); - LOG_INFO(logger, "example logging dog over {} {} {} {} {} {} {} {}", 1, 5L, "example2", - static_cast(10), 3.0, std::string_view("view1"), false, 4.0f); - LOG_INFO(logger, "test over lazy dog {} {} {} {} {} {} {} {} {}", std::string("str2"), "example1", - true, 1, "example3", 5L, static_cast(10), std::string_view("view2"), 4.0f); - LOG_INFO(logger, "quick lazy example brown {} {} {} {}", "example1", std::string("str2"), - "example3", static_cast(10)); - LOG_INFO(logger, "lazy example over {}", std::string("str2")); - LOG_INFO(logger, "jumps over dog {} {} {} {} {} {} {} {} {} {}", std::string_view("view1"), 1, - "example3", 7UL, std::string("str2"), static_cast(9), "example2", - std::string("str1"), 3.0, true); - LOG_INFO(logger, "fox jumps brown {} {} {}", std::string_view("view1"), std::string("str1"), 5L); - LOG_INFO(logger, "dog quick jumps logging {} {} {} {} {} {} {} {} {} {}", 6LL, - std::string_view("view1"), true, 8ULL, false, std::string("str1"), 3.0, - std::string("str2"), "example2", std::string_view("view2")); - LOG_INFO(logger, "example fox lazy logging {} {} {} {} {} {}", "example1", true, - std::string("str2"), 6LL, std::string_view("view2"), 4.0f); - LOG_INFO(logger, "over fox jumps brown {} {} {} {} {} {}", static_cast(9), true, false, 5L, - std::string_view("view2"), 6LL); - LOG_INFO(logger, "dog logging over lazy {} {}", "example3", 5L); - LOG_INFO(logger, "example test lazy brown {} {} {} {} {} {} {} {} {}", 8ULL, std::string_view("view2"), - "example1", "example3", static_cast(9), 3.0, std::string("str1"), 5L, 7UL); - LOG_INFO(logger, "logging quick over dog {} {} {} {} {} {} {} {} {}", std::string_view("view2"), 7UL, - "example1", false, static_cast(9), true, "example2", 5L, std::string_view("view1")); - LOG_INFO(logger, "test logging lazy fox {} {} {} {} {} {} {} {}", 6LL, 7UL, 2, "example2", - std::string("str2"), "example1", 5L, "example3"); - LOG_INFO(logger, "quick brown lazy {} {} {} {}", static_cast(9), - static_cast(10), 8ULL, 7UL); - LOG_INFO(logger, "quick logging lazy dog {} {} {}", static_cast(9), "example1", - static_cast(10)); - LOG_INFO(logger, "brown lazy logging {}", std::string("str1")); - LOG_INFO(logger, "fox example lazy test {} {} {} {} {} {} {}", 8ULL, true, "example3", - static_cast(10), false, static_cast(9), 3.0); - LOG_INFO(logger, "over fox lazy {} {} {} {} {} {} {} {}", std::string("str2"), - std::string("str1"), 5L, "example3", "example2", std::string_view("view2"), - static_cast(10), std::string_view("view1")); - LOG_INFO(logger, "lazy example dog {} {} {} {} {}", 2, 1, 8ULL, 7UL, 4.0f); - LOG_INFO(logger, "over test quick {} {} {} {} {} {} {} {} {} {}", std::string_view("view1"), 6LL, 1, - std::string("str1"), 4.0f, "example2", static_cast(10), 2, "example1", 3.0); - LOG_INFO(logger, "brown test logging jumps {} {} {} {}", 2, 3.0, false, 5L); - LOG_INFO(logger, "over lazy dog logging {} {} {} {} {} {} {} {} {}", 2, 8ULL, 4.0f, 7UL, - std::string_view("view2"), static_cast(9), 3.0, "example2", std::string_view("view1")); - LOG_INFO(logger, "dog test jumps {} {}", 6LL, static_cast(9)); - LOG_INFO(logger, "test fox example {} {} {} {}", true, 1, 6LL, std::string("str1")); - LOG_INFO(logger, "jumps logging quick example {} {} {} {} {} {}", std::string_view("view2"), 2, - 8ULL, std::string("str2"), std::string("str1"), static_cast(9)); - LOG_INFO(logger, "over logging dog {} {} {} {} {} {} {}", true, "example3", - static_cast(10), 3.0, "example2", std::string("str1"), 8ULL); - LOG_INFO(logger, "fox brown logging {} {} {} {} {} {} {} {}", "example2", 2, 6LL, "example3", - std::string_view("view1"), std::string_view("view2"), false, 7UL); - LOG_INFO(logger, "fox test over quick {} {}", std::string("str1"), 5L); - LOG_INFO(logger, "quick over brown {} {} {} {} {} {} {}", 8ULL, std::string("str2"), false, 2, - 4.0f, std::string_view("view2"), static_cast(10)); - LOG_INFO(logger, "over fox lazy logging {} {} {} {} {} {} {}", 1, 5L, std::string_view("view1"), - 6LL, 4.0f, "example3", "example2"); - LOG_INFO(logger, "quick over example {} {} {} {} {} {} {} {}", std::string_view("view2"), - "example1", false, true, std::string_view("view1"), 2, 6LL, 4.0f); - LOG_INFO(logger, "fox dog brown lazy {} {} {} {}", "example2", true, std::string("str2"), 3.0); - LOG_INFO(logger, "jumps dog test quick {} {}", 8ULL, std::string_view("view2")); - LOG_INFO(logger, "lazy quick fox jumps {} {} {} {} {} {} {}", std::string_view("view2"), - static_cast(10), 3.0, static_cast(9), 8ULL, 7UL, "example2"); - LOG_INFO(logger, "quick example dog {} {} {} {} {} {} {} {} {}", std::string("str2"), false, 2, - 6LL, std::string_view("view2"), std::string_view("view1"), 5L, 7UL, std::string("str1")); - LOG_INFO(logger, "over example lazy {} {} {} {} {} {} {}", 2, 8ULL, 5L, std::string_view("view2"), - "example2", false, std::string("str2")); - LOG_INFO(logger, "over jumps lazy test {} {} {} {}", true, std::string("str1"), - static_cast(10), std::string("str2")); - LOG_INFO(logger, "lazy dog quick {}", std::string_view("view1")); - LOG_INFO(logger, "quick brown over {} {} {} {}", 4.0f, 1, std::string_view("view1"), "example2"); - LOG_INFO(logger, "example quick jumps {} {} {} {}", 7UL, 4.0f, "example3", static_cast(9)); - LOG_INFO(logger, "jumps dog over {} {} {} {} {} {} {} {} {}", 2, 8ULL, 5L, 4.0f, - std::string_view("view2"), true, 7UL, 3.0, false); - LOG_INFO(logger, "fox lazy example dog {}", std::string("str2")); - LOG_INFO(logger, "logging over jumps {} {} {} {} {}", static_cast(10), "example3", - std::string_view("view2"), 7UL, true); - LOG_INFO(logger, "brown test jumps lazy {} {} {} {} {}", 6LL, 7UL, 2, std::string_view("view1"), 4.0f); - LOG_INFO(logger, "over fox lazy dog {} {} {} {}", "example3", 1, 3.0, static_cast(9)); - LOG_INFO(logger, "jumps dog lazy logging {} {} {} {} {} {} {} {} {}", std::string("str1"), false, - "example3", 5L, std::string_view("view2"), std::string_view("view1"), 2, - static_cast(9), true); - LOG_INFO(logger, "fox over lazy {} {} {} {} {} {} {} {}", 2, 4.0f, std::string("str2"), - "example3", 3.0, 1, 8ULL, "example2"); - LOG_INFO(logger, "logging lazy jumps {} {} {} {} {}", static_cast(9), 4.0f, 5L, 6LL, - std::string_view("view2")); - LOG_INFO(logger, "lazy logging fox {} {} {} {} {} {} {} {}", 4.0f, 6LL, static_cast(9), 2, - std::string("str1"), "example1", std::string_view("view1"), 1); - LOG_INFO(logger, "over brown quick lazy {} {} {} {} {} {} {} {}", 5L, 8ULL, true, 7UL, "example1", - std::string("str1"), static_cast(10), 1); - LOG_INFO(logger, "logging brown quick {} {} {} {} {} {} {} {}", 8ULL, false, "example2", true, - "example1", std::string_view("view1"), std::string_view("view2"), 7UL); - LOG_INFO(logger, "example logging brown {} {} {} {} {}", 7UL, false, - static_cast(10), true, 5L); - LOG_INFO(logger, "lazy test jumps logging {} {} {} {} {} {}", static_cast(9), true, - std::string("str1"), std::string_view("view2"), std::string_view("view1"), "example1"); - LOG_INFO(logger, "test logging dog over {} {} {} {}", false, static_cast(9), 3.0, true); - LOG_INFO(logger, "jumps over quick {} {} {} {} {}", 6LL, 3.0, std::string_view("view1"), - std::string_view("view2"), 7UL); - LOG_INFO(logger, "logging test quick {} {} {} {} {} {} {} {} {} {}", static_cast(10), 6LL, - std::string("str1"), static_cast(9), "example2", true, 5L, std::string("str2"), 3.0, 2); - LOG_INFO(logger, "jumps lazy test over {} {} {} {}", false, 6LL, 8ULL, std::string("str2")); - LOG_INFO(logger, "brown example fox {} {}", std::string_view("view2"), static_cast(10)); - LOG_INFO(logger, "jumps brown example quick {} {} {} {}", 7UL, 2, 1, std::string_view("view2")); - LOG_INFO(logger, "over example lazy {}", "example3"); - LOG_INFO(logger, "test jumps lazy over {} {} {} {} {} {} {}", 5L, "example3", - std::string_view("view1"), false, 2, std::string("str1"), 6LL); - LOG_INFO(logger, "logging over test brown {} {} {} {} {} {} {} {} {} {}", 8ULL, 1, - std::string("str2"), true, std::string("str1"), "example3", static_cast(9), - std::string_view("view1"), std::string_view("view2"), "example1"); - LOG_INFO(logger, "brown over test quick {} {} {} {} {} {} {} {} {} {}", 2, 7UL, - std::string_view("view1"), 1, true, false, 6LL, 5L, "example1", 8ULL); - LOG_INFO(logger, "lazy over jumps example {} {} {} {} {} {} {}", std::string_view("view2"), 3.0, - "example3", "example2", "example1", 6LL, 2); - LOG_INFO(logger, "test brown dog {} {} {} {} {} {} {} {} {} {}", static_cast(9), 2, - std::string_view("view1"), std::string("str1"), 7UL, std::string_view("view2"), - static_cast(10), "example1", "example2", 6LL); - LOG_INFO(logger, "dog fox logging quick {} {}", 5L, static_cast(9)); - LOG_INFO(logger, "jumps test quick {} {} {} {} {} {} {}", 8ULL, true, 2, - std::string_view("view2"), "example1", 1, 6LL); - LOG_INFO(logger, "lazy example quick logging {} {} {} {} {} {} {} {}", 1, std::string_view("view2"), - "example3", std::string("str1"), static_cast(9), static_cast(10), 7UL, 4.0f); - LOG_INFO(logger, "logging quick dog {} {} {}", "example2", std::string("str2"), 7UL); - LOG_INFO(logger, "jumps over quick {} {} {} {} {} {} {}", 4.0f, std::string("str2"), 6LL, false, - "example1", 5L, 8ULL); - LOG_INFO(logger, "quick test brown {} {} {} {} {} {} {}", 7UL, false, 1, 4.0f, "example3", 5L, 8ULL); - LOG_INFO(logger, "over fox example {}", std::string("str2")); - LOG_INFO(logger, "fox logging lazy {} {}", 5L, "example2"); - LOG_INFO(logger, "lazy brown quick over {} {} {} {} {} {} {} {} {} {}", static_cast(9), - std::string("str1"), 4.0f, true, 7UL, 2, "example2", 5L, false, 1); - LOG_INFO(logger, "quick dog over fox {} {} {}", false, "example2", std::string_view("view1")); - LOG_INFO(logger, "over dog quick {} {} {} {}", std::string_view("view2"), - static_cast(10), 6LL, std::string("str1")); - LOG_INFO(logger, "dog over quick fox {} {}", "example2", "example1"); - LOG_INFO(logger, "lazy fox quick {} {} {} {} {} {}", true, 2, std::string("str1"), - std::string("str2"), static_cast(10), "example1"); - LOG_INFO(logger, "lazy dog fox {}", "example3"); - LOG_INFO(logger, "over example jumps dog {} {} {} {} {} {} {} {}", 4.0f, std::string("str2"), - static_cast(10), 2, "example1", std::string_view("view2"), - std::string("str1"), static_cast(9)); - LOG_INFO(logger, "example quick test logging {} {} {} {} {} {} {} {} {}", std::string("str2"), - std::string_view("view1"), false, 1, 7UL, 2, 8ULL, "example1", "example2"); - LOG_INFO(logger, "brown test lazy {} {} {} {}", static_cast(9), 6LL, 2, 4.0f); - LOG_INFO(logger, "dog example logging {} {} {} {} {} {} {} {} {}", "example3", - std::string_view("view1"), 3.0, std::string_view("view2"), - static_cast(10), true, 4.0f, 6LL, static_cast(9)); - LOG_INFO(logger, "over jumps test quick {} {} {} {} {} {}", std::string_view("view2"), 7UL, 8ULL, - std::string("str2"), 5L, "example1"); - LOG_INFO(logger, "example brown fox {} {} {} {} {} {}", "example3", 4.0f, 7UL, 5L, 1, 2); - LOG_INFO(logger, "dog test quick {}", std::string_view("view2")); - LOG_INFO(logger, "example lazy quick {} {}", 3.0, static_cast(9)); - LOG_INFO(logger, "dog test fox {} {} {} {} {} {} {} {} {} {}", false, true, 2, std::string("str1"), 6LL, - "example2", std::string_view("view1"), std::string_view("view2"), std::string("str2"), 3.0); - LOG_INFO(logger, "brown quick example {} {}", std::string("str2"), 6LL); - LOG_INFO(logger, "dog brown quick {} {} {} {} {} {} {} {}", 1, 4.0f, 5L, true, 6LL, - std::string("str1"), "example3", false); - LOG_INFO(logger, "fox dog jumps quick {}", 8ULL); - LOG_INFO(logger, "lazy jumps test {} {} {} {} {} {}", 1, "example1", static_cast(9), 3.0, false, 8ULL); - LOG_INFO(logger, "fox logging example {} {} {} {} {} {} {} {} {}", "example2", 5L, 4.0f, 1, - std::string_view("view1"), "example3", static_cast(9), true, 6LL); - LOG_INFO(logger, "quick lazy brown {}", static_cast(9)); - LOG_INFO(logger, "test logging lazy {} {} {} {}", static_cast(10), - std::string_view("view2"), 4.0f, std::string_view("view1")); - LOG_INFO(logger, "jumps dog over {} {}", false, 8ULL); - LOG_INFO(logger, "quick test lazy {}", true); - LOG_INFO(logger, "dog example logging lazy {} {} {}", 8ULL, std::string("str2"), "example2"); - LOG_INFO(logger, "fox jumps dog over {} {} {} {} {} {}", 4.0f, "example3", 1, 8ULL, 2, true); - LOG_INFO(logger, "lazy fox over quick {} {} {} {} {} {} {} {}", std::string_view("view2"), 2, 5L, - static_cast(9), 3.0, 6LL, "example3", 4.0f); - LOG_INFO(logger, "logging jumps fox lazy {} {} {} {} {}", std::string_view("view2"), false, - static_cast(9), true, 8ULL); - LOG_INFO(logger, "lazy fox quick {} {} {}", "example2", std::string_view("view1"), true); - LOG_INFO(logger, "jumps dog lazy {} {} {}", static_cast(9), std::string("str2"), - static_cast(10)); - LOG_INFO(logger, "jumps quick logging test {} {} {} {} {} {} {}", static_cast(10), - "example1", false, 4.0f, 8ULL, std::string_view("view1"), static_cast(9)); - LOG_INFO(logger, "fox test jumps example {}", "example2"); - LOG_INFO(logger, "example fox lazy quick {} {} {} {} {} {}", 8ULL, "example2", "example1", true, - std::string_view("view2"), 6LL); - LOG_INFO(logger, "test example over quick {} {} {} {}", 5L, "example2", false, 4.0f); - LOG_INFO(logger, "over dog example {} {} {}", 6LL, std::string_view("view2"), std::string("str1")); - LOG_INFO(logger, "jumps test fox logging {} {} {} {} {} {} {}", static_cast(10), - 6LL, 7UL, std::string_view("view2"), static_cast(9), "example1", true); - LOG_INFO(logger, "dog fox over {} {} {} {} {} {} {}", true, 7UL, static_cast(10), - std::string("str1"), 3.0, std::string_view("view1"), 6LL); - LOG_INFO(logger, "over fox dog {} {} {} {} {} {} {} {} {} {}", 4.0f, "example3", true, - static_cast(9), 5L, "example1", std::string("str2"), 3.0, "example2", - static_cast(10)); - LOG_INFO(logger, "dog example brown jumps {} {} {} {} {} {}", static_cast(9), 7UL, true, - 3.0, std::string("str1"), 1); - LOG_INFO(logger, "lazy quick logging over {} {} {} {} {} {}", std::string_view("view1"), - std::string_view("view2"), "example3", std::string("str2"), 5L, static_cast(9)); - LOG_INFO(logger, "jumps test quick lazy {} {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - std::string_view("view1"), 3.0, 2, 4.0f, static_cast(9), false, 5L, - static_cast(10), "example1"); - LOG_INFO(logger, "brown lazy fox jumps {} {} {} {} {} {} {} {} {}", 8ULL, std::string("str1"), - "example1", true, std::string_view("view1"), false, 2, 7UL, 4.0f); - LOG_INFO(logger, "example lazy logging fox {} {} {} {}", "example1", 3.0, "example2", 5L); - LOG_INFO(logger, "fox lazy test brown {}", true); - LOG_INFO(logger, "dog brown jumps {} {} {} {} {} {} {}", false, "example3", 2, 8ULL, "example1", 3.0, true); - LOG_INFO(logger, "quick test logging dog {} {} {}", 3.0, false, "example1"); - LOG_INFO(logger, "test quick jumps {} {} {} {} {} {} {}", "example3", std::string("str2"), 8ULL, - std::string("str1"), std::string_view("view2"), true, static_cast(9)); - LOG_INFO(logger, "fox brown jumps {} {}", false, 3.0); - LOG_INFO(logger, "brown quick dog over {} {} {} {} {} {} {} {} {} {}", 2, - static_cast(10), 1, "example1", std::string("str2"), true, - std::string_view("view2"), 6LL, 8ULL, std::string_view("view1")); - LOG_INFO(logger, "logging quick example {} {} {} {}", 5L, "example3", 4.0f, 1); - LOG_INFO(logger, "dog brown quick {}", 8ULL); - LOG_INFO(logger, "lazy brown test {} {} {} {} {} {} {} {}", std::string("str1"), "example1", true, - 6LL, 5L, 1, "example3", 8ULL); - LOG_INFO(logger, "test example logging {} {}", 1, true); - LOG_INFO(logger, "test jumps quick fox {} {} {} {} {} {} {} {} {}", "example1", 5L, 4.0f, false, - 8ULL, 7UL, static_cast(10), 6LL, "example3"); - LOG_INFO(logger, "lazy dog logging {} {} {}", "example3", std::string("str2"), 1); - LOG_INFO(logger, "over example dog quick {}", "example3"); - LOG_INFO(logger, "test quick lazy logging {} {} {} {} {} {} {}", std::string_view("view1"), 5L, - "example3", 7UL, 3.0, true, 8ULL); - LOG_INFO(logger, "test dog lazy {} {} {} {}", static_cast(10), 2, - std::string_view("view2"), static_cast(9)); - LOG_INFO(logger, "dog example jumps brown {} {} {}", "example3", 7UL, static_cast(10)); - LOG_INFO(logger, "brown fox over dog {} {} {} {}", static_cast(10), "example2", 2, - std::string_view("view1")); - LOG_INFO(logger, "test example quick logging {} {} {} {} {} {} {} {} {} {}", "example3", - "example1", 8ULL, std::string_view("view2"), false, true, 6LL, std::string("str2"), 5L, 7UL); - LOG_INFO(logger, "over example dog fox {} {} {} {} {} {} {} {} {} {}", 3.0, "example3", true, - 4.0f, false, 8ULL, std::string("str2"), static_cast(9), 6LL, 1); - LOG_INFO(logger, "example logging over dog {} {} {} {} {} {} {}", 6LL, std::string_view("view2"), - std::string("str1"), "example3", 1, std::string_view("view1"), 5L); - LOG_INFO(logger, "brown jumps logging quick {} {} {}", 2, 1, static_cast(9)); - LOG_INFO(logger, "dog test jumps {} {} {}", 6LL, 1, 3.0); - LOG_INFO(logger, "brown test dog quick {} {} {} {} {} {}", "example3", 1, static_cast(9), - std::string_view("view1"), 8ULL, std::string_view("view2")); - LOG_INFO(logger, "quick jumps example dog {} {} {} {} {}", 2, std::string_view("view1"), 3.0, - static_cast(10), 5L); - LOG_INFO(logger, "logging brown quick {} {} {}", 5L, 1, 4.0f); - LOG_INFO(logger, "logging jumps test brown {} {}", "example3", 6LL); - LOG_INFO(logger, "brown over example {}", 6LL); - LOG_INFO(logger, "fox dog example logging {} {} {} {} {} {} {} {}", false, static_cast(9), - "example3", "example2", std::string("str2"), 8ULL, "example1", true); - LOG_INFO(logger, "logging test over brown {}", 4.0f); - LOG_INFO(logger, "over brown dog {} {} {} {} {} {} {} {} {} {}", 7UL, 4.0f, 2, - std::string_view("view1"), 3.0, 5L, 6LL, 8ULL, "example3", 1); - LOG_INFO(logger, "quick dog test {} {} {} {} {} {} {} {}", std::string_view("view1"), 6LL, 4.0f, - "example2", "example1", 1, 7UL, 3.0); - LOG_INFO(logger, "quick fox example test {} {} {} {} {} {}", "example3", - static_cast(10), 2, 4.0f, 8ULL, std::string_view("view2")); - LOG_INFO(logger, "jumps dog logging fox {} {} {} {} {}", std::string("str2"), - static_cast(10), "example3", 6LL, std::string("str1")); - LOG_INFO(logger, "lazy brown logging quick {} {} {} {} {}", static_cast(9), 8ULL, true, - static_cast(10), 1); - LOG_INFO(logger, "dog example jumps over {} {} {} {}", 2, 5L, 7UL, "example2"); - LOG_INFO(logger, "example logging fox {} {} {} {} {} {} {} {} {}", 8ULL, true, static_cast(9), - std::string("str1"), 4.0f, false, static_cast(10), 7UL, "example1"); - LOG_INFO(logger, "lazy over quick {} {} {} {} {} {} {}", false, "example2", 3.0, - std::string_view("view1"), std::string("str1"), 5L, 4.0f); - LOG_INFO(logger, "fox brown jumps {} {} {} {}", std::string("str1"), 4.0f, 5L, std::string("str2")); - LOG_INFO(logger, "logging test lazy {} {} {} {} {} {} {} {} {}", 8ULL, std::string("str1"), - std::string("str2"), std::string_view("view2"), 2, 5L, 1, 7UL, 4.0f); - LOG_INFO(logger, "brown example test {} {} {} {} {} {}", 4.0f, std::string_view("view2"), 2, - std::string("str2"), static_cast(10), static_cast(9)); - LOG_INFO(logger, "logging over test dog {} {}", "example2", static_cast(10)); - LOG_INFO(logger, "brown example over {} {} {} {} {}", static_cast(9), - std::string_view("view1"), false, true, 8ULL); - LOG_INFO(logger, "logging brown quick {} {} {} {} {}", "example2", 7UL, 8ULL, 6LL, 3.0); - LOG_INFO(logger, "example jumps dog {} {} {} {} {}", std::string_view("view2"), 7UL, 6LL, true, 5L); - LOG_INFO(logger, "test lazy example {} {} {} {} {} {} {}", std::string_view("view1"), 5L, true, - std::string("str2"), 7UL, static_cast(10), static_cast(9)); - LOG_INFO(logger, "over dog jumps {} {}", static_cast(9), 8ULL); - LOG_INFO(logger, "over test jumps {} {} {} {} {} {}", 5L, 1, std::string("str1"), "example3", - std::string("str2"), 4.0f); - LOG_INFO(logger, "brown dog logging {} {} {} {} {} {}", 3.0, 8ULL, "example2", 5L, - std::string_view("view2"), "example1"); - LOG_INFO(logger, "jumps dog example {} {} {} {} {}", "example2", 2, std::string("str2"), - "example3", 5L); - LOG_INFO(logger, "jumps dog logging fox {} {} {} {}", std::string("str1"), 3.0, false, std::string("str2")); - LOG_INFO(logger, "fox dog quick jumps {} {} {} {} {} {} {} {} {} {}", 2, "example1", 4.0f, 3.0, - 5L, "example3", true, "example2", 6LL, 7UL); - LOG_INFO(logger, "dog example test quick {} {} {} {} {} {} {} {} {} {}", std::string("str1"), - "example1", 5L, 4.0f, 8ULL, true, 7UL, std::string_view("view2"), std::string("str2"), - static_cast(10)); - LOG_INFO(logger, "quick jumps dog {} {} {} {} {} {} {} {} {}", "example3", "example2", - static_cast(10), 4.0f, true, std::string_view("view1"), 1, 2, 6LL); - LOG_INFO(logger, "example jumps over logging {} {} {} {} {} {} {}", 1, false, - static_cast(9), std::string_view("view2"), "example2", 7UL, std::string("str2")); - LOG_INFO(logger, "lazy over fox dog {} {} {} {} {} {} {} {}", 8ULL, 1, std::string("str1"), 2, - 4.0f, 3.0, static_cast(10), "example1"); - LOG_INFO(logger, "brown over quick example {} {} {} {} {} {} {} {}", false, 3.0, 4.0f, "example3", - std::string_view("view2"), 7UL, std::string("str2"), true); - LOG_INFO(logger, "fox logging test over {} {} {} {} {} {} {} {}", 7UL, 8ULL, - static_cast(10), 5L, "example1", 2, true, std::string_view("view2")); - LOG_INFO(logger, "brown example logging {} {} {} {} {} {}", true, std::string("str2"), 3.0, - "example1", std::string_view("view2"), 6LL); - LOG_INFO(logger, "brown lazy quick {} {} {} {} {} {} {} {} {}", true, 4.0f, std::string_view("view1"), - static_cast(10), 3.0, 8ULL, std::string("str2"), 6LL, std::string_view("view2")); - LOG_INFO(logger, "brown over example {} {} {} {} {} {} {}", std::string_view("view2"), "example3", - static_cast(10), 5L, std::string("str2"), static_cast(9), 1); - LOG_INFO(logger, "jumps dog logging test {} {} {} {} {}", 3.0, std::string("str1"), "example1", - "example3", static_cast(9)); - LOG_INFO(logger, "jumps fox test quick {}", "example3"); - LOG_INFO(logger, "quick dog logging lazy {} {} {} {} {}", 8ULL, "example2", static_cast(9), 4.0f, 5L); - LOG_INFO(logger, "test example over {} {} {} {} {}", 7UL, std::string("str1"), 1, 8ULL, - std::string_view("view2")); - LOG_INFO(logger, "quick lazy brown {} {}", 8ULL, 6LL); - LOG_INFO(logger, "test brown fox {}", 1); - LOG_INFO(logger, "over example lazy {} {} {} {} {} {}", 2, 6LL, 1, 4.0f, std::string("str1"), - std::string_view("view1")); - LOG_INFO(logger, "fox test jumps {} {} {} {} {} {} {}", "example3", true, "example1", - std::string_view("view2"), 7UL, 5L, std::string("str1")); - LOG_INFO(logger, "logging lazy example {} {}", std::string_view("view2"), std::string_view("view1")); - LOG_INFO(logger, "logging fox dog {} {} {}", std::string("str2"), true, std::string_view("view2")); - LOG_INFO(logger, "jumps over brown {} {} {}", 4.0f, "example1", std::string_view("view1")); - LOG_INFO(logger, "over lazy dog brown {} {} {} {} {} {} {} {} {}", false, std::string_view("view2"), - std::string_view("view1"), 1, std::string("str1"), "example3", 3.0, "example1", 4.0f); - LOG_INFO(logger, "dog test brown lazy {} {} {} {} {} {} {}", std::string("str2"), true, - "example1", 2, std::string_view("view2"), "example3", 7UL); - LOG_INFO(logger, "example lazy quick dog {} {}", 4.0f, static_cast(10)); - LOG_INFO(logger, "test brown lazy dog {}", 5L); - LOG_INFO(logger, "quick fox logging {} {} {} {} {} {}", std::string_view("view2"), "example1", - std::string_view("view1"), 8ULL, "example3", static_cast(10)); - LOG_INFO(logger, "over dog quick fox {} {} {} {} {} {} {} {} {} {}", false, 3.0, std::string_view("view1"), - "example1", 1, static_cast(10), 2, static_cast(9), 6LL, 4.0f); - LOG_INFO(logger, "jumps example brown {} {} {} {} {}", true, 1, std::string("str2"), - static_cast(9), 6LL); - LOG_INFO(logger, "over test logging quick {} {} {} {} {} {} {} {}", 4.0f, "example2", - std::string_view("view1"), 8ULL, 3.0, 5L, "example1", 2); - LOG_INFO(logger, "lazy dog test jumps {} {} {} {} {} {} {} {} {} {}", static_cast(10), - 6LL, 4.0f, 7UL, false, std::string_view("view2"), 3.0, "example2", 1, true); - LOG_INFO(logger, "example dog fox brown {} {} {} {} {}", std::string("str1"), false, 3.0, 8ULL, true); - LOG_INFO(logger, "jumps over logging test {} {}", 1, std::string("str1")); - LOG_INFO(logger, "dog test brown {}", 4.0f); - LOG_INFO(logger, "over dog test example {} {} {} {}", std::string("str1"), 8ULL, 5L, 2); - LOG_INFO(logger, "quick test lazy logging {} {} {} {} {} {} {} {} {} {}", "example1", "example2", - 2, std::string_view("view1"), std::string("str2"), false, 1, static_cast(9), - std::string_view("view2"), std::string("str1")); - LOG_INFO(logger, "example test fox over {} {} {} {} {} {} {}", 3.0, 6LL, std::string("str2"), - static_cast(9), std::string("str1"), 4.0f, 1); - LOG_INFO(logger, "test jumps logging {} {} {} {} {} {}", 3.0, 5L, std::string("str1"), - std::string("str2"), static_cast(9), 1); - LOG_INFO(logger, "dog example fox logging {} {} {} {} {} {} {}", std::string("str2"), 3.0, 7UL, - 5L, std::string_view("view2"), 8ULL, 1); - LOG_INFO(logger, "over fox lazy {} {} {} {} {} {}", 1, 6LL, 2, std::string("str1"), "example1", false); - LOG_INFO(logger, "logging test lazy dog {} {} {} {} {} {} {} {} {} {}", - static_cast(10), 8ULL, false, std::string("str1"), - std::string_view("view2"), "example1", std::string_view("view1"), 2, 1, 5L); - LOG_INFO(logger, "quick dog jumps {} {} {}", static_cast(9), std::string("str2"), 8ULL); - LOG_INFO(logger, "fox test dog over {} {} {} {} {} {} {}", 4.0f, true, false, 3.0, 7UL, 8ULL, - "example3"); - LOG_INFO(logger, "jumps over logging quick {}", static_cast(10)); - LOG_INFO(logger, "jumps logging fox example {} {} {} {} {} {} {} {} {} {}", "example3", - "example1", static_cast(10), std::string("str2"), 8ULL, - static_cast(9), 4.0f, std::string("str1"), std::string_view("view2"), 7UL); - LOG_INFO(logger, "fox over quick test {}", false); - LOG_INFO(logger, "brown dog quick test {} {} {} {} {} {} {}", std::string("str2"), - std::string("str1"), static_cast(9), true, false, "example1", 3.0); - LOG_INFO(logger, "over example brown {} {} {} {} {} {} {} {}", 7UL, 8ULL, "example3", - static_cast(9), "example1", std::string("str1"), std::string_view("view1"), true); - LOG_INFO(logger, "jumps test example {}", 8ULL); - LOG_INFO(logger, "over test example brown {} {} {} {} {} {} {} {} {}", true, 4.0f, - std::string_view("view1"), "example3", std::string("str2"), 3.0, static_cast(9), - 1, static_cast(10)); - LOG_INFO(logger, "logging jumps test example {} {} {} {} {}", 7UL, "example2", 1, 2, 5L); - LOG_INFO(logger, "lazy jumps brown {} {}", "example2", std::string_view("view2")); - LOG_INFO(logger, "brown over quick {} {} {} {} {} {} {}", std::string_view("view1"), 5L, - static_cast(10), std::string_view("view2"), "example1", 4.0f, 2); - LOG_INFO(logger, "test example fox over {} {} {} {} {}", 4.0f, false, "example2", true, 8ULL); - LOG_INFO(logger, "quick fox lazy over {} {} {} {} {} {}", std::string("str1"), static_cast(9), - 5L, static_cast(10), std::string_view("view2"), 8ULL); - LOG_INFO(logger, "test logging lazy {} {} {}", "example1", 7UL, 1); - LOG_INFO(logger, "fox dog example {} {} {} {} {} {}", "example3", std::string_view("view2"), 8ULL, - false, std::string("str2"), "example2"); - LOG_INFO(logger, "over fox dog example {} {} {} {} {} {}", std::string_view("view1"), "example3", - "example2", 2, "example1", 6LL); - LOG_INFO(logger, "dog brown example quick {} {} {} {} {} {} {} {} {} {}", 3.0, "example3", 2, 8ULL, - 4.0f, std::string_view("view1"), 5L, 7UL, static_cast(10), "example2"); - LOG_INFO(logger, "test fox dog jumps {} {} {} {} {}", "example1", static_cast(10), - "example3", 7UL, 1); - LOG_INFO(logger, "fox dog over {} {} {} {} {}", std::string("str1"), - static_cast(10), 4.0f, 2, static_cast(9)); - LOG_INFO(logger, "logging brown fox {}", 3.0); - LOG_INFO(logger, "example fox over brown {} {} {}", 3.0, "example3", 1); - LOG_INFO(logger, "quick dog lazy jumps {} {} {} {} {} {} {} {} {} {}", 8ULL, "example2", - "example3", 1, 5L, false, 3.0, std::string_view("view2"), "example1", true); - LOG_INFO(logger, "jumps dog test {} {} {} {} {} {} {} {} {} {}", 5L, 2, "example1", 1, 7UL, false, - "example2", static_cast(10), true, std::string("str1")); - LOG_INFO(logger, "quick logging lazy example {} {}", false, "example3"); - LOG_INFO(logger, "example logging test {} {} {} {} {} {} {} {} {} {}", 6LL, 1, - std::string("str1"), "example2", 3.0, 8ULL, "example1", 5L, 2, "example3"); - LOG_INFO(logger, "example jumps dog quick {} {} {} {} {} {} {}", 7UL, static_cast(10), - 6LL, "example1", std::string_view("view2"), std::string("str1"), std::string("str2")); - LOG_INFO(logger, "quick logging jumps example {} {}", "example3", static_cast(10)); - LOG_INFO(logger, "dog example lazy test {} {} {} {} {}", std::string("str2"), - std::string_view("view1"), 6LL, static_cast(9), static_cast(10)); - LOG_INFO(logger, "lazy logging jumps dog {} {} {} {} {} {} {} {} {}", 1, "example2", - std::string_view("view2"), true, static_cast(9), 5L, std::string("str1"), - "example3", static_cast(10)); - LOG_INFO(logger, "logging jumps dog lazy {} {} {} {} {} {} {} {} {}", false, std::string("str1"), - std::string_view("view2"), "example2", 2, static_cast(9), - std::string_view("view1"), 6LL, 7UL); - LOG_INFO(logger, "test lazy example {} {} {} {} {}", static_cast(9), true, std::string("str1"), 1, 2); - LOG_INFO(logger, "quick lazy test {} {}", std::string("str2"), 8ULL); - LOG_INFO(logger, "logging quick example dog {} {} {} {} {}", 1, 3.0, static_cast(9), 6LL, - std::string("str2")); - LOG_INFO(logger, "logging quick test {} {} {} {} {} {} {}", 8ULL, 7UL, - static_cast(10), 1, "example3", 4.0f, "example1"); - LOG_INFO(logger, "quick logging over jumps {} {}", 3.0, 1); - LOG_INFO(logger, "over example brown jumps {}", 8ULL); - LOG_INFO(logger, "dog jumps brown logging {} {} {} {} {} {} {} {}", "example2", std::string_view("view2"), - std::string_view("view1"), 8ULL, static_cast(10), 5L, std::string("str2"), 7UL); - LOG_INFO(logger, "test example brown jumps {} {} {}", 6LL, 5L, 8ULL); - LOG_INFO(logger, "jumps example quick over {} {} {} {} {} {} {} {} {} {}", 5L, "example1", false, - 3.0, "example3", std::string("str2"), 2, std::string("str1"), true, 4.0f); - LOG_INFO(logger, "dog brown jumps lazy {} {} {} {} {} {} {} {} {} {}", 1, 3.0, - static_cast(10), "example1", std::string("str2"), - std::string_view("view1"), std::string_view("view2"), 4.0f, "example2", false); - LOG_INFO(logger, "fox dog over {} {} {} {} {} {} {} {} {} {}", 5L, 6LL, true, "example3", - static_cast(10), "example2", std::string("str1"), false, std::string("str2"), 8ULL); - LOG_INFO(logger, "lazy jumps test dog {} {} {} {} {} {} {} {} {} {}", 5L, 8ULL, false, 7UL, 2, - static_cast(9), "example2", static_cast(10), "example3", 6LL); - LOG_INFO(logger, "over lazy example {} {} {}", std::string("str2"), "example2", std::string("str1")); - LOG_INFO(logger, "fox dog example logging {} {} {} {} {}", std::string_view("view1"), "example1", - 3.0, 7UL, 2); - LOG_INFO(logger, "example logging lazy {} {} {} {} {} {}", 4.0f, true, "example3", - std::string_view("view1"), std::string("str2"), std::string("str1")); - LOG_INFO(logger, "lazy fox quick over {} {} {} {} {}", 1, 7UL, 4.0f, 3.0, 2); - LOG_INFO(logger, "logging quick brown fox {} {} {} {} {} {} {} {} {} {}", false, - std::string_view("view2"), std::string("str1"), std::string_view("view1"), 3.0, - "example2", 4.0f, 7UL, static_cast(9), std::string("str2")); - LOG_INFO(logger, "quick example fox {} {} {} {} {} {} {} {}", 5L, 8ULL, - static_cast(10), false, std::string("str2"), "example2", 7UL, 6LL); - LOG_INFO(logger, "logging fox example {} {} {} {} {} {} {} {}", 2, 8ULL, 4.0f, true, - static_cast(10), 5L, 1, 6LL); - LOG_INFO(logger, "over example fox test {} {} {} {} {} {}", 6LL, 7UL, std::string_view("view2"), 2, 3.0, true); - LOG_INFO(logger, "lazy test brown {} {} {}", 8ULL, "example1", false); - LOG_INFO(logger, "dog over jumps {} {} {}", std::string_view("view1"), 3.0, 6LL); - LOG_INFO(logger, "over dog fox {} {} {} {} {}", std::string_view("view2"), "example2", false, - static_cast(10), std::string("str1")); - LOG_INFO(logger, "over dog jumps {} {} {} {} {} {} {} {}", 7UL, 2, true, std::string("str1"), - static_cast(10), "example2", 3.0, 6LL); - LOG_INFO(logger, "brown quick over {} {} {} {} {} {}", std::string_view("view1"), - static_cast(10), 5L, 6LL, "example1", std::string_view("view2")); - LOG_INFO(logger, "logging jumps example brown {} {}", static_cast(10), false); - LOG_INFO(logger, "fox quick test brown {} {} {} {} {} {} {} {}", 7UL, static_cast(9), - "example1", false, 6LL, std::string_view("view1"), std::string("str2"), - static_cast(10)); - LOG_INFO(logger, "jumps test brown lazy {} {} {} {} {}", 1, 2, std::string("str1"), - static_cast(9), "example1"); - LOG_INFO(logger, "logging test lazy {} {} {} {} {} {} {}", false, static_cast(9), 3.0, - std::string("str1"), true, 6LL, static_cast(10)); - LOG_INFO(logger, "dog logging fox lazy {} {} {} {} {} {}", 4.0f, 6LL, 1, 2, std::string("str1"), - std::string_view("view2")); - LOG_INFO(logger, "lazy dog logging test {} {} {} {} {}", "example1", 8ULL, - std::string_view("view1"), 7UL, std::string_view("view2")); - LOG_INFO(logger, "quick jumps dog over {} {} {} {} {} {}", 7UL, "example1", 2, false, true, 1); - LOG_INFO(logger, "logging jumps lazy {} {} {} {} {} {} {} {}", std::string_view("view2"), 1, 2, - std::string_view("view1"), "example3", "example2", 3.0, true); - LOG_INFO(logger, "jumps example over {} {} {} {} {} {} {} {} {} {}", 1, std::string_view("view2"), - std::string_view("view1"), 3.0, 8ULL, static_cast(10), "example1", false, - std::string("str1"), 6LL); - LOG_INFO(logger, "test quick example brown {}", "example3"); - LOG_INFO(logger, "jumps over example lazy {} {} {} {} {}", static_cast(9), 5L, "example1", - "example3", std::string("str2")); - LOG_INFO(logger, "dog fox over {} {} {}", "example3", 3.0, "example1"); - LOG_INFO(logger, "over logging jumps {} {} {} {} {} {} {} {} {}", std::string_view("view2"), 8ULL, - "example3", true, "example2", 3.0, std::string_view("view1"), std::string("str1"), false); - LOG_INFO(logger, "dog lazy brown {} {} {} {} {} {} {}", "example1", std::string_view("view1"), - static_cast(10), std::string("str1"), false, 3.0, true); - LOG_INFO(logger, "logging quick fox {} {} {} {} {} {}", 7UL, 3.0, static_cast(10), - 4.0f, "example1", std::string_view("view1")); - LOG_INFO(logger, "lazy quick example jumps {} {} {} {} {} {}", static_cast(9), false, - "example2", 7UL, 1, "example1"); - LOG_INFO(logger, "quick brown example {} {}", 4.0f, 7UL); - LOG_INFO(logger, "over brown logging {} {} {} {} {}", std::string_view("view2"), - std::string_view("view1"), 7UL, 2, static_cast(10)); - LOG_INFO(logger, "brown over jumps logging {} {} {} {} {} {} {} {} {} {}", true, std::string("str1"), 1, - static_cast(9), false, 4.0f, static_cast(10), 2, 6LL, "example1"); - LOG_INFO(logger, "jumps fox lazy test {} {} {} {} {} {} {} {} {} {}", 2, true, "example2", false, - std::string("str1"), 5L, 4.0f, std::string_view("view2"), static_cast(9), 7UL); - LOG_INFO(logger, "example fox test {} {} {} {} {} {}", false, 8ULL, std::string("str2"), true, - 7UL, std::string_view("view1")); - LOG_INFO(logger, "logging fox over {} {} {} {} {} {} {}", static_cast(10), 8ULL, - std::string_view("view2"), 6LL, std::string("str1"), 4.0f, 3.0); - LOG_INFO(logger, "test dog lazy {} {} {} {} {} {}", std::string_view("view1"), - static_cast(9), std::string_view("view2"), 5L, false, 2); - LOG_INFO(logger, "brown over quick {} {} {}", 8ULL, 7UL, false); - LOG_INFO(logger, "lazy quick dog {} {} {} {} {}", "example1", "example2", "example3", - std::string_view("view1"), 8ULL); - LOG_INFO(logger, "over dog example {} {} {} {} {} {} {}", "example2", 6LL, false, "example1", 2, - static_cast(10), 7UL); - LOG_INFO(logger, "brown test jumps {} {} {}", 4.0f, true, 6LL); - LOG_INFO(logger, "jumps over logging quick {} {} {} {} {} {} {}", 6LL, 7UL, - static_cast(10), 3.0, 5L, 8ULL, 4.0f); - LOG_INFO(logger, "lazy quick fox test {} {} {} {} {} {}", static_cast(10), 4.0f, - std::string_view("view1"), 1, 2, true); - LOG_INFO(logger, "test example dog {} {}", "example2", 1); - LOG_INFO(logger, "fox over brown quick {} {} {} {} {} {} {} {} {} {}", 2, "example3", 8ULL, - "example2", std::string("str1"), static_cast(10), std::string("str2"), - static_cast(9), std::string_view("view2"), 4.0f); - LOG_INFO(logger, "test dog quick fox {} {} {} {} {} {} {} {} {}", 5L, "example2", true, - "example1", "example3", false, 4.0f, 3.0, std::string_view("view2")); - LOG_INFO(logger, "example fox dog over {} {} {} {} {} {} {}", true, static_cast(9), - std::string_view("view1"), 1, 5L, 4.0f, std::string("str2")); - LOG_INFO(logger, "lazy brown fox over {}", std::string("str1")); - LOG_INFO(logger, "test over dog logging {} {} {} {} {} {}", false, 8ULL, - static_cast(10), 2, 4.0f, "example1"); - LOG_INFO(logger, "brown fox over {} {} {} {} {} {} {} {} {} {}", std::string_view("view1"), 8ULL, - 6LL, false, "example3", 5L, std::string("str1"), "example2", "example1", 3.0); - LOG_INFO(logger, "over test example {} {} {}", false, 8ULL, 3.0); - LOG_INFO(logger, "example fox dog brown {} {} {} {} {} {} {}", std::string("str2"), "example1", - 4.0f, 1, static_cast(10), 3.0, 6LL); - LOG_INFO(logger, "brown fox lazy example {} {}", 4.0f, 2); - LOG_INFO(logger, "over logging example {} {} {} {} {} {} {} {}", 2, std::string("str1"), - "example1", 6LL, 3.0, std::string("str2"), "example2", true); - LOG_INFO(logger, "dog logging test lazy {} {} {} {} {} {} {} {} {} {}", 1, std::string("str2"), - "example1", "example3", std::string_view("view2"), std::string_view("view1"), - static_cast(9), 4.0f, 7UL, 3.0); - LOG_INFO(logger, "jumps over test {} {} {} {} {} {} {} {} {}", 3.0, 4.0f, - static_cast(10), std::string("str1"), std::string("str2"), 5L, 7UL, true, false); - LOG_INFO(logger, "over example quick brown {} {}", 6LL, true); - LOG_INFO(logger, "logging over brown quick {} {} {}", "example2", static_cast(9), 7UL); - LOG_INFO(logger, "logging brown test fox {} {} {} {} {} {} {} {} {}", true, 7UL, - std::string("str1"), std::string_view("view2"), static_cast(10), 4.0f, - std::string_view("view1"), "example3", false); - LOG_INFO(logger, "example dog over {} {} {} {} {} {} {}", 2, 6LL, false, 7UL, - static_cast(10), 1, std::string_view("view1")); - LOG_INFO(logger, "over quick lazy test {} {} {} {} {} {} {} {} {}", std::string_view("view2"), 1, - 5L, "example3", std::string("str1"), static_cast(10), - static_cast(9), 4.0f, 6LL); - LOG_INFO(logger, "jumps over example {}", static_cast(10)); - LOG_INFO(logger, "logging quick lazy {} {}", 4.0f, 8ULL); - LOG_INFO(logger, "over test logging dog {}", 7UL); - LOG_INFO(logger, "test jumps brown quick {} {} {} {} {}", std::string("str1"), - static_cast(9), 3.0, std::string("str2"), std::string_view("view2")); - LOG_INFO(logger, "test logging over {} {} {} {} {} {} {} {} {} {}", std::string_view("view1"), - "example1", "example2", 2, false, "example3", 8ULL, 1, true, 7UL); - LOG_INFO(logger, "lazy dog logging {} {} {} {} {} {} {} {} {} {}", std::string("str2"), 2, - "example2", 4.0f, "example1", static_cast(10), std::string("str1"), 7UL, - static_cast(9), std::string_view("view2")); - LOG_INFO(logger, "jumps example quick {} {} {} {} {} {} {}", 8ULL, std::string("str1"), - static_cast(10), false, static_cast(9), "example1", 4.0f); - LOG_INFO(logger, "logging fox dog {} {} {} {} {} {} {} {} {}", 4.0f, "example1", 1, 7UL, true, - std::string_view("view1"), false, static_cast(10), std::string_view("view2")); - LOG_INFO(logger, "logging example dog test {} {} {} {} {}", false, static_cast(9), 7UL, - static_cast(10), 8ULL); - LOG_INFO(logger, "jumps brown test example {} {} {}", false, std::string_view("view2"), std::string("str2")); - LOG_INFO(logger, "quick test lazy dog {} {} {} {} {} {} {} {} {} {}", std::string_view("view2"), 6LL, 3.0, - std::string("str2"), static_cast(10), 4.0f, 5L, true, false, "example3"); - LOG_INFO(logger, "quick brown fox {} {} {} {} {} {} {} {} {}", 8ULL, "example1", false, - "example2", 3.0, 4.0f, 6LL, true, 5L); - LOG_INFO(logger, "test brown over {}", std::string_view("view1")); - LOG_INFO(logger, "logging brown quick over {}", static_cast(10)); - LOG_INFO(logger, "jumps lazy over {}", std::string_view("view2")); - LOG_INFO(logger, "brown dog jumps over {} {} {}", std::string_view("view1"), 8ULL, "example3"); - LOG_INFO(logger, "quick test dog fox {} {} {} {} {} {} {} {} {}", true, false, static_cast(9), - std::string("str1"), "example1", 8ULL, std::string_view("view1"), 4.0f, std::string_view("view2")); - LOG_INFO(logger, "test logging brown dog {} {} {} {} {} {} {} {} {} {}", 7UL, 6LL, 2, - static_cast(10), 4.0f, std::string_view("view2"), 1, false, - static_cast(9), "example2"); - LOG_INFO(logger, "lazy fox brown quick {}", "example2"); - LOG_INFO(logger, "dog fox example quick {} {} {} {} {}", static_cast(9), false, true, 3.0, - std::string_view("view1")); - LOG_INFO(logger, "over jumps example quick {} {} {} {} {} {} {} {} {} {}", static_cast(10), - false, "example3", 1, 7UL, 2, true, 4.0f, "example1", static_cast(9)); - LOG_INFO(logger, "fox dog brown {}", 8ULL); - LOG_INFO(logger, "example fox dog {} {} {} {} {} {}", false, std::string_view("view2"), - static_cast(9), std::string("str1"), "example3", "example2"); - LOG_INFO(logger, "lazy test jumps {} {}", "example2", 6LL); - LOG_INFO(logger, "logging example fox {} {} {} {} {} {} {} {}", static_cast(9), 3.0, - "example3", 1, std::string_view("view1"), std::string("str1"), - static_cast(10), "example2"); - LOG_INFO(logger, "lazy over fox example {} {} {} {} {} {} {} {} {} {}", static_cast(9), 7UL, false, - 3.0, 4.0f, std::string_view("view1"), "example2", std::string_view("view2"), "example1", 8ULL); - LOG_INFO(logger, "quick lazy logging {} {} {} {} {} {} {}", false, std::string_view("view1"), - "example1", true, "example3", std::string_view("view2"), static_cast(9)); - LOG_INFO(logger, "dog lazy jumps {} {} {} {}", 3.0, std::string("str2"), 1, 6LL); - LOG_INFO(logger, "dog example brown test {} {} {} {} {} {}", 6LL, 2, 8ULL, - static_cast(10), "example2", 1); - LOG_INFO(logger, "lazy jumps dog {} {} {} {} {} {} {} {} {} {}", 3.0, static_cast(9), 6LL, - std::string_view("view2"), true, 5L, std::string("str2"), "example2", "example3", - std::string_view("view1")); - LOG_INFO(logger, "fox dog logging quick {} {}", "example1", "example2"); - LOG_INFO(logger, "dog jumps example over {} {} {} {} {} {} {}", "example1", 2, 5L, 8ULL, - std::string("str2"), 6LL, "example3"); - LOG_INFO(logger, "dog lazy quick {} {} {} {} {} {} {} {} {}", 8ULL, std::string("str1"), - "example3", 3.0, std::string_view("view1"), true, static_cast(9), 1, - static_cast(10)); - LOG_INFO(logger, "jumps brown lazy {} {} {} {} {} {} {}", std::string("str2"), 2, - static_cast(10), true, "example3", std::string_view("view2"), 6LL); - LOG_INFO(logger, "brown dog example {} {} {}", std::string("str2"), static_cast(10), true); - LOG_INFO(logger, "fox brown lazy {} {} {} {} {} {}", 6LL, "example1", std::string("str1"), true, - std::string("str2"), "example3"); - LOG_INFO(logger, "quick over jumps logging {} {}", 4.0f, std::string("str1")); - LOG_INFO(logger, "dog fox brown quick {} {} {} {} {} {} {} {} {}", "example2", std::string("str2"), 7UL, - static_cast(10), 6LL, 8ULL, std::string_view("view2"), "example1", 4.0f); - LOG_INFO(logger, "quick example dog {} {} {} {} {} {}", false, "example1", true, 5L, 3.0, - static_cast(10)); - LOG_INFO(logger, "test brown lazy dog {} {}", std::string("str2"), 2); - LOG_INFO(logger, "dog logging example {} {} {} {} {} {} {} {} {}", 7UL, std::string("str1"), 8ULL, - 6LL, 2, false, "example3", std::string_view("view1"), std::string("str2")); - LOG_INFO(logger, "dog test quick {} {} {} {} {}", std::string_view("view2"), 2, - static_cast(10), "example3", 8ULL); - LOG_INFO(logger, "lazy example dog {}", static_cast(9)); - LOG_INFO(logger, "example dog logging {} {} {} {} {} {} {} {}", 5L, 8ULL, 2, false, "example2", - true, static_cast(9), 4.0f); - LOG_INFO(logger, "test logging example brown {} {} {} {} {} {} {} {} {}", "example3", 4.0f, 5L, - static_cast(9), 2, std::string_view("view1"), std::string_view("view2"), true, 6LL); - LOG_INFO(logger, "over example brown {} {} {} {} {}", 1, "example2", std::string_view("view2"), - std::string_view("view1"), "example3"); - LOG_INFO(logger, "over example lazy quick {}", 8ULL); - LOG_INFO(logger, "logging dog fox {} {} {} {} {} {} {} {}", static_cast(10), - std::string_view("view2"), 8ULL, 1, "example3", static_cast(9), std::string("str2"), true); - LOG_INFO(logger, "quick dog example {} {} {} {} {} {} {} {}", 1, 3.0, std::string("str2"), - static_cast(9), std::string_view("view1"), static_cast(10), - "example3", 4.0f); - LOG_INFO(logger, "dog quick logging jumps {} {} {} {} {}", 2, std::string("str1"), "example2", 1, true); - LOG_INFO(logger, "dog fox logging test {} {} {} {} {} {} {} {} {} {}", 1, static_cast(9), - std::string_view("view2"), "example1", 3.0, 5L, true, 2, std::string_view("view1"), 8ULL); - LOG_INFO(logger, "dog jumps fox quick {} {}", true, 2); - LOG_INFO(logger, "jumps over dog quick {} {} {} {} {} {} {} {} {} {}", "example2", 6LL, 8ULL, 1, - 4.0f, 7UL, 2, std::string_view("view1"), false, 5L); - LOG_INFO(logger, "logging example quick lazy {} {} {} {} {} {} {} {} {} {}", "example3", 2, false, - std::string("str1"), 1, "example2", std::string_view("view2"), 6LL, true, 7UL); - LOG_INFO(logger, "fox quick jumps logging {} {} {} {} {} {} {} {} {} {}", - static_cast(10), 1, std::string_view("view1"), static_cast(9), - false, true, std::string("str2"), 3.0, 5L, std::string("str1")); - LOG_INFO(logger, "fox dog brown {} {}", std::string("str1"), static_cast(10)); - LOG_INFO(logger, "fox jumps lazy {} {} {} {}", std::string_view("view1"), "example3", false, - std::string("str2")); - LOG_INFO(logger, "brown lazy example fox {} {}", "example2", 1); - LOG_INFO(logger, "quick lazy example jumps {} {}", true, std::string_view("view1")); - LOG_INFO(logger, "test quick fox {} {} {} {}", 6LL, std::string("str1"), 8ULL, std::string("str2")); - LOG_INFO(logger, "dog logging test lazy {}", std::string("str1")); - LOG_INFO(logger, "lazy over dog example {} {} {} {} {} {} {}", 7UL, 8ULL, std::string_view("view1"), - "example2", std::string("str2"), static_cast(10), 5L); - LOG_INFO(logger, "example logging brown jumps {} {} {} {} {} {} {} {}", 5L, 6LL, - std::string_view("view2"), std::string_view("view1"), 2, true, 7UL, std::string("str1")); - LOG_INFO(logger, "fox brown lazy over {} {} {} {} {} {} {} {} {} {}", 2, "example1", 6LL, 4.0f, 5L, - true, std::string_view("view2"), std::string_view("view1"), "example3", std::string("str2")); - LOG_INFO(logger, "logging dog brown lazy {} {} {} {} {} {} {} {} {} {}", 4.0f, "example3", - "example2", std::string_view("view2"), 5L, false, std::string("str2"), - std::string_view("view1"), 7UL, std::string("str1")); - LOG_INFO(logger, "test fox quick brown {} {} {} {} {} {} {} {} {}", false, static_cast(10), - std::string("str1"), true, "example2", 2, 7UL, std::string_view("view1"), 4.0f); - LOG_INFO(logger, "over brown jumps {} {} {} {} {} {} {} {} {}", 6LL, static_cast(9), false, - "example3", 5L, 8ULL, 1, std::string("str1"), static_cast(10)); - LOG_INFO(logger, "example brown dog lazy {} {} {} {} {} {} {} {} {} {}", std::string_view("view2"), - false, static_cast(9), true, 1, 6LL, 8ULL, 7UL, 3.0, "example2"); - LOG_INFO(logger, "lazy dog over {} {} {} {} {} {}", std::string("str2"), "example3", - std::string_view("view1"), "example2", static_cast(9), static_cast(10)); - LOG_INFO(logger, "fox example quick lazy {} {} {} {}", 8ULL, 2, static_cast(9), true); - LOG_INFO(logger, "test over fox {} {} {} {} {} {} {}", false, "example2", "example1", 2, 1, - "example3", 5L); - LOG_INFO(logger, "test lazy example {} {} {} {} {} {} {}", 8ULL, std::string("str1"), - std::string_view("view2"), "example2", std::string("str2"), static_cast(9), 4.0f); - LOG_INFO(logger, "jumps example over dog {} {} {} {} {} {} {} {} {} {}", std::string_view("view1"), 3.0, - std::string("str2"), "example2", true, static_cast(9), 4.0f, 5L, "example3", false); - LOG_INFO(logger, "logging example test {} {} {} {}", static_cast(10), "example1", - static_cast(9), "example2"); - LOG_INFO(logger, "quick fox test brown {} {} {}", 6LL, true, 7UL); - LOG_INFO(logger, "over logging test lazy {} {} {} {}", 1, 8ULL, static_cast(9), "example1"); - LOG_INFO(logger, "example lazy quick {} {} {} {} {} {} {} {}", "example2", "example1", 7UL, 1, - std::string("str2"), std::string("str1"), 6LL, 4.0f); - LOG_INFO(logger, "lazy brown dog {}", static_cast(9)); - LOG_INFO(logger, "test quick jumps example {}", 6LL); - LOG_INFO(logger, "dog quick lazy {} {} {} {} {} {} {}", static_cast(10), - std::string("str1"), 5L, 8ULL, "example3", 3.0, "example2"); - LOG_INFO(logger, "brown logging lazy quick {} {} {} {} {} {}", 2, 7UL, "example2", true, - "example3", static_cast(9)); - LOG_INFO(logger, "test brown fox dog {} {} {} {} {}", std::string("str1"), "example3", false, - std::string_view("view1"), 6LL); - LOG_INFO(logger, "logging test over dog {}", std::string_view("view1")); - LOG_INFO(logger, "test dog brown {} {} {} {}", 3.0, 1, 6LL, std::string_view("view1")); - LOG_INFO(logger, "example test quick {}", std::string_view("view2")); - LOG_INFO(logger, "dog over fox {} {} {} {} {}", 6LL, static_cast(9), 4.0f, 2, true); - LOG_INFO(logger, "logging test fox {} {} {}", 1, 3.0, 7UL); - LOG_INFO(logger, "over lazy dog jumps {} {} {} {} {}", std::string("str1"), false, - std::string_view("view2"), 6LL, static_cast(10)); - LOG_INFO(logger, "test quick over example {} {} {} {} {} {} {} {}", std::string_view("view1"), - 3.0, 6LL, 5L, static_cast(9), 2, 7UL, false); - LOG_INFO(logger, "example test lazy logging {}", 3.0); - LOG_INFO(logger, "jumps lazy quick over {} {} {} {} {} {} {}", std::string_view("view2"), false, - std::string("str1"), true, 6LL, 1, 2); - LOG_INFO(logger, "fox jumps quick {} {} {} {} {}", true, static_cast(10), - "example3", 1, "example2"); - LOG_INFO(logger, "jumps dog lazy {} {} {} {} {} {} {} {}", false, std::string_view("view2"), 4.0f, - "example2", static_cast(9), std::string("str2"), 3.0, std::string_view("view1")); - LOG_INFO(logger, "fox lazy logging jumps {}", 1); - LOG_INFO(logger, "brown fox example {} {}", "example3", static_cast(9)); - LOG_INFO(logger, "fox lazy jumps logging {} {} {} {} {} {}", std::string_view("view2"), 4.0f, 2, 6LL, 5L, 3.0); - LOG_INFO(logger, "fox lazy logging jumps {} {} {} {} {} {} {}", std::string("str2"), - std::string_view("view1"), 6LL, 1, std::string_view("view2"), 5L, static_cast(9)); - LOG_INFO(logger, "quick dog jumps {} {}", std::string("str1"), 6LL); - LOG_INFO(logger, "dog quick jumps example {} {} {} {} {} {} {} {}", 1, 3.0, false, 6LL, - static_cast(9), "example2", 4.0f, static_cast(10)); - LOG_INFO(logger, "quick example logging brown {} {} {} {} {} {} {}", 5L, "example3", 4.0f, 7UL, - static_cast(10), "example2", false); - LOG_INFO(logger, "lazy jumps test {} {} {} {} {} {} {} {}", 2, true, 4.0f, 8ULL, - std::string_view("view1"), 6LL, "example2", std::string_view("view2")); - LOG_INFO(logger, "lazy jumps dog {} {} {} {} {} {} {}", std::string_view("view1"), "example3", - "example2", static_cast(9), "example1", 6LL, std::string_view("view2")); - LOG_INFO(logger, "jumps quick test {} {} {} {} {} {} {} {}", 2, 8ULL, std::string("str1"), false, - 1, std::string_view("view1"), static_cast(9), std::string("str2")); - LOG_INFO(logger, "example jumps lazy {} {} {} {} {}", 7UL, "example2", 3.0, std::string("str2"), true); - LOG_INFO(logger, "jumps quick over example {} {} {}", 6LL, 7UL, std::string("str2")); - LOG_INFO(logger, "lazy dog jumps test {} {}", 7UL, true); - LOG_INFO(logger, "lazy jumps example {} {} {} {} {} {} {} {} {}", false, 7UL, true, 5L, - "example3", std::string("str2"), "example2", 1, static_cast(9)); - LOG_INFO(logger, "dog logging fox lazy {} {} {} {} {}", 8ULL, static_cast(10), - std::string("str1"), 7UL, 6LL); - LOG_INFO(logger, "logging over fox lazy {} {} {} {} {} {} {} {}", 2, std::string_view("view2"), - true, 6LL, std::string("str2"), 8ULL, std::string("str1"), 1); - LOG_INFO(logger, "lazy fox brown {} {}", "example1", "example3"); - LOG_INFO(logger, "fox quick test over {} {} {}", "example3", 1, std::string("str2")); - LOG_INFO(logger, "lazy over brown {} {} {} {} {} {} {} {}", true, std::string_view("view1"), 7UL, - 5L, std::string("str1"), std::string("str2"), 4.0f, static_cast(9)); - LOG_INFO(logger, "test jumps brown dog {} {} {} {} {} {} {} {} {} {}", 8ULL, "example1", - "example3", 1, static_cast(9), std::string_view("view2"), 4.0f, - std::string_view("view1"), 3.0, 7UL); - LOG_INFO(logger, "fox example jumps {}", static_cast(10)); - LOG_INFO(logger, "dog lazy quick {} {} {} {} {} {}", false, static_cast(9), - std::string_view("view1"), 1, "example3", std::string("str1")); - LOG_INFO(logger, "jumps fox over logging {} {}", 1, "example1"); - LOG_INFO(logger, "lazy example test {} {} {}", 4.0f, 7UL, 8ULL); - LOG_INFO(logger, "fox brown example {} {} {} {} {}", std::string_view("view1"), - std::string("str1"), std::string("str2"), std::string_view("view2"), 4.0f); - LOG_INFO(logger, "logging lazy jumps {} {} {} {} {} {} {}", 4.0f, 5L, static_cast(9), 6LL, - false, std::string_view("view2"), static_cast(10)); - LOG_INFO(logger, "fox over logging {} {} {} {} {} {} {} {} {} {}", std::string_view("view2"), 5L, - 8ULL, "example3", 6LL, false, 2, "example1", 7UL, static_cast(9)); - LOG_INFO(logger, "over example logging dog {} {} {} {} {} {}", 4.0f, 8ULL, "example2", true, - static_cast(10), static_cast(9)); - LOG_INFO(logger, "example lazy dog {} {} {} {} {}", 8ULL, std::string_view("view2"), - std::string("str2"), std::string("str1"), 1); - LOG_INFO(logger, "fox example quick dog {} {} {} {} {} {} {} {} {}", "example2", false, 5L, 7UL, - std::string("str2"), static_cast(9), true, "example1", "example3"); - LOG_INFO(logger, "logging quick over {} {} {} {} {} {} {} {} {} {}", 2, 4.0f, "example3", std::string("str2"), - std::string("str1"), 7UL, static_cast(10), "example2", 8ULL, 3.0); - LOG_INFO(logger, "fox over jumps brown {} {} {} {} {} {} {} {}", std::string_view("view2"), - std::string("str2"), "example2", 3.0, 5L, false, "example3", 6LL); - LOG_INFO(logger, "test logging quick dog {} {} {} {} {} {} {} {} {}", 6LL, 3.0, "example2", true, - false, static_cast(10), std::string("str2"), std::string("str1"), 8ULL); - LOG_INFO(logger, "test logging quick lazy {} {}", std::string_view("view2"), 4.0f); - LOG_INFO(logger, "logging brown example {} {} {}", 4.0f, "example1", std::string("str2")); - LOG_INFO(logger, "jumps test over {} {}", std::string("str1"), std::string("str2")); - LOG_INFO(logger, "fox jumps quick {} {} {} {} {} {}", 6LL, std::string("str2"), false, 7UL, - std::string_view("view2"), 4.0f); - LOG_INFO(logger, "quick over jumps logging {}", false); - LOG_INFO(logger, "test dog logging {} {} {} {} {}", std::string("str2"), 5L, "example2", - static_cast(10), 1); - LOG_INFO(logger, "example dog jumps lazy {} {} {} {} {}", "example2", 2, 7UL, false, static_cast(9)); - LOG_INFO(logger, "example test logging {} {} {} {} {} {} {} {} {} {}", 6LL, 1, 3.0, - static_cast(10), std::string("str1"), "example2", 5L, "example3", 4.0f, - static_cast(9)); - LOG_INFO(logger, "lazy brown over logging {}", 7UL); - LOG_INFO(logger, "over lazy quick fox {} {} {} {} {}", 8ULL, 1, 7UL, 5L, "example3"); - LOG_INFO(logger, "over example fox {} {} {}", true, 2, static_cast(9)); - LOG_INFO(logger, "fox over brown jumps {} {} {}", std::string_view("view2"), 5L, 4.0f); - LOG_INFO(logger, "brown jumps quick {}", "example1"); - LOG_INFO(logger, "test jumps lazy {} {} {} {} {}", 6LL, 8ULL, 4.0f, "example1", 2); - LOG_INFO(logger, "dog fox lazy {} {}", 3.0, false); - LOG_INFO(logger, "jumps test quick brown {} {} {} {} {} {} {} {}", "example3", 7UL, 2, - std::string_view("view1"), false, true, "example1", "example2"); - LOG_INFO(logger, "dog over quick {} {} {} {} {} {} {} {} {} {}", 2, 5L, "example2", 7UL, - "example3", std::string_view("view1"), std::string_view("view2"), std::string("str1"), - false, "example1"); - LOG_INFO(logger, "quick dog over brown {} {} {} {} {}", 6LL, 4.0f, "example1", 3.0, 1); - LOG_INFO(logger, "logging over fox {} {}", 2, "example3"); - LOG_INFO(logger, "quick logging example {} {} {} {}", 7UL, 4.0f, 1, 8ULL); - LOG_INFO(logger, "quick fox brown {} {} {} {} {}", 5L, 3.0, 2, false, "example3"); - LOG_INFO(logger, "quick lazy logging test {} {} {}", static_cast(10), 7UL, 2); - LOG_INFO(logger, "example lazy logging {} {} {} {} {}", static_cast(10), 1, 8ULL, - 7UL, static_cast(9)); - LOG_INFO(logger, "lazy quick logging brown {} {} {} {} {} {} {} {}", static_cast(9), 3.0, - 7UL, true, 5L, std::string_view("view2"), std::string("str1"), "example2"); - LOG_INFO(logger, "over fox test {} {} {}", false, std::string_view("view2"), 8ULL); - LOG_INFO(logger, "test dog example jumps {} {} {} {}", "example2", 2, true, 8ULL); - LOG_INFO(logger, "quick lazy dog test {} {} {} {} {} {} {} {} {} {}", 6LL, - std::string_view("view2"), false, "example2", std::string_view("view1"), - static_cast(9), "example3", static_cast(10), 1, std::string("str2")); - LOG_INFO(logger, "over example quick {} {} {} {} {} {} {} {} {} {}", static_cast(10), - "example3", "example2", 2, 4.0f, std::string_view("view2"), "example1", false, 8ULL, true); - LOG_INFO(logger, "lazy test fox dog {} {} {} {} {} {}", std::string_view("view1"), 5L, 2, 4.0f, - static_cast(9), 1); - LOG_INFO(logger, "jumps lazy test brown {}", true); - LOG_INFO(logger, "brown fox over {} {} {} {} {} {} {} {}", 4.0f, 8ULL, 3.0, 5L, 2, 6LL, - std::string_view("view1"), 1); - LOG_INFO(logger, "logging over quick test {} {} {} {} {} {} {}", 4.0f, static_cast(9), 1, - 6LL, "example2", 5L, std::string_view("view1")); - LOG_INFO(logger, "logging test dog {} {} {} {} {} {} {}", static_cast(10), - "example3", 2, false, 3.0, 6LL, 4.0f); - LOG_INFO(logger, "example brown dog test {} {} {} {} {}", 6LL, 8ULL, true, 3.0, std::string_view("view1")); - LOG_INFO(logger, "logging test jumps quick {} {} {} {}", "example3", 3.0, std::string("str1"), 7UL); - LOG_INFO(logger, "dog lazy quick {} {} {}", 2, true, static_cast(9)); - LOG_INFO(logger, "quick over example fox {} {} {} {} {} {} {}", 8ULL, static_cast(9), 6LL, - 3.0, 7UL, "example1", 1); - LOG_INFO(logger, "jumps example fox {} {} {} {} {} {}", std::string_view("view2"), true, 8ULL, - static_cast(10), "example2", false); - LOG_INFO(logger, "jumps logging brown {} {} {} {}", true, std::string_view("view2"), 7UL, std::string("str1")); - LOG_INFO(logger, "test fox jumps {} {} {}", 2, "example3", static_cast(9)); - LOG_INFO(logger, "jumps lazy quick {}", "example2"); - LOG_INFO(logger, "logging brown over {} {} {} {} {}", "example1", 5L, 3.0, 7UL, 4.0f); - LOG_INFO(logger, "dog lazy quick test {} {} {} {}", "example3", std::string_view("view1"), 6LL, - std::string_view("view2")); - LOG_INFO(logger, "jumps lazy dog {} {} {}", static_cast(9), std::string_view("view2"), - "example2"); - LOG_INFO(logger, "over fox brown lazy {} {} {} {} {} {} {}", 7UL, 2, "example1", "example3", 5L, - std::string("str2"), 6LL); - LOG_INFO(logger, "logging over test {} {} {} {} {} {}", std::string_view("view2"), 1, false, 2, true, 8ULL); - LOG_INFO(logger, "jumps dog over test {} {} {} {} {} {} {} {} {} {}", 1, "example3", false, 2, - 8ULL, 3.0, 7UL, 5L, static_cast(10), std::string_view("view2")); - LOG_INFO(logger, "brown test lazy {} {} {} {} {} {} {} {} {}", std::string("str2"), 4.0f, 5L, 2, - "example3", static_cast(10), 8ULL, static_cast(9), - std::string_view("view1")); - LOG_INFO(logger, "over dog brown {} {}", "example2", 5L); - LOG_INFO(logger, "fox lazy over logging {} {} {} {} {} {} {} {} {} {}", std::string("str1"), - "example2", 2, 1, std::string_view("view1"), 5L, 3.0, true, 8ULL, 7UL); - LOG_INFO(logger, "fox example over logging {} {} {} {} {}", 2, std::string_view("view1"), - static_cast(9), 5L, std::string("str2")); - LOG_INFO(logger, "lazy dog over fox {} {} {} {} {} {} {}", std::string("str1"), 3.0, false, 7UL, - 1, std::string("str2"), 2); - LOG_INFO(logger, "brown fox quick lazy {} {}", 8ULL, std::string_view("view1")); - LOG_INFO(logger, "example logging brown lazy {} {} {} {} {} {} {} {} {}", 8ULL, 6LL, 2, true, - std::string("str2"), static_cast(9), 7UL, "example2", "example3"); - LOG_INFO(logger, "quick over logging brown {} {} {} {}", true, static_cast(10), 1, 4.0f); - LOG_INFO(logger, "brown over fox {} {}", std::string("str2"), 8ULL); - LOG_INFO(logger, "over jumps quick {} {}", false, static_cast(9)); - LOG_INFO(logger, "quick test example {} {} {} {} {} {} {} {} {} {}", static_cast(9), - std::string("str2"), 3.0, 2, 1, std::string_view("view1"), "example2", false, 8ULL, 5L); - LOG_INFO(logger, "brown lazy dog test {} {}", static_cast(10), 3.0); - LOG_INFO(logger, "jumps fox dog {}", std::string_view("view1")); - LOG_INFO(logger, "dog fox brown {} {} {} {} {} {} {}", 1, 4.0f, 5L, 8ULL, 3.0, "example1", - "example3"); - LOG_INFO(logger, "test lazy over {} {} {} {} {} {} {} {}", false, true, std::string_view("view2"), - 3.0, "example3", 7UL, 1, "example1"); - LOG_INFO(logger, "fox dog brown logging {} {} {} {} {}", false, true, 7UL, "example3", std::string("str2")); - LOG_INFO(logger, "over dog lazy example {} {}", false, "example3"); - LOG_INFO(logger, "lazy jumps dog {} {} {} {}", 4.0f, std::string("str1"), "example2", false); - LOG_INFO(logger, "lazy test fox {} {} {} {} {} {} {}", 7UL, true, std::string_view("view2"), 2, - 3.0, std::string_view("view1"), 4.0f); - LOG_INFO(logger, "example jumps test {} {} {} {} {} {} {} {} {} {}", static_cast(9), - static_cast(10), 4.0f, std::string("str2"), true, "example3", - std::string_view("view2"), false, 6LL, 3.0); - LOG_INFO(logger, "logging brown fox {} {}", std::string_view("view2"), 8ULL); - LOG_INFO(logger, "lazy test dog jumps {} {} {}", 2, 8ULL, 4.0f); - LOG_INFO(logger, "fox dog jumps {} {} {} {} {} {} {} {} {} {}", 8ULL, std::string("str2"), false, - static_cast(9), std::string_view("view2"), static_cast(10), - std::string_view("view1"), "example1", 3.0, 7UL); - - return 0; -} \ No newline at end of file diff --git a/subprojects/quill-4.2.0/benchmarks/compile_time/gen_log_messages.py b/subprojects/quill-4.2.0/benchmarks/compile_time/gen_log_messages.py deleted file mode 100644 index d7f4a02..0000000 --- a/subprojects/quill-4.2.0/benchmarks/compile_time/gen_log_messages.py +++ /dev/null @@ -1,57 +0,0 @@ -import random - - -def generate_log_statements(num_statements): - argument_types = [ - '1', '2', '3.0', '4.0f', '5L', '6LL', '7UL', '8ULL', 'true', 'false', - '"example1"', '"example2"', '"example3"', 'std::string("str1")', - 'std::string("str2")', 'std::string_view("view1")', 'std::string_view("view2")', - 'static_cast(9)', 'static_cast(10)' - ] - random_words = ["quick", "brown", "fox", "jumps", "over", "lazy", "dog", "logging", "test", "example"] - - statements = [] - for i in range(num_statements): - num_args = random.randint(1, 10) # Number of arguments for the log statement - args = random.sample(argument_types, num_args) - placeholders = ' '.join(["{}" for _ in args]) - num_words = random.randint(3, 4) # Number of random words in the log message - words = ' '.join(random.sample(random_words, num_words)) - statement = f' LOG_INFO(logger, "{words} {placeholders}", {", ".join(args)});' - statements.append(statement) - - return statements - - -def write_to_file(filename, statements): - with open(filename, 'w') as f: - f.write('#include "quill/Backend.h"\n') - f.write('#include "quill/Frontend.h"\n') - f.write('#include "quill/LogMacros.h"\n') - f.write('#include "quill/Logger.h"\n') - f.write('#include "quill/sinks/ConsoleSink.h"\n') - f.write('#include \n') - f.write('#include \n\n') - f.write('/**\n') - f.write(' * Trivial logging example to console\n') - f.write(' */\n\n') - f.write('int main()\n') - f.write('{\n') - f.write(' // Start the backend thread\n') - f.write(' quill::BackendOptions backend_options;\n') - f.write(' quill::Backend::start(backend_options);\n\n') - f.write(' // Frontend\n') - f.write(' auto console_sink = quill::Frontend::create_or_get_sink("sink_id_1");\n') - f.write(' quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(console_sink));\n\n') - - for statement in statements: - f.write(f'{statement}\n') - - f.write('\n return 0;\n') - f.write('}\n') - - -if __name__ == '__main__': - num_statements = 2000 - statements = generate_log_statements(num_statements) - write_to_file('log_benchmark.cpp', statements) diff --git a/subprojects/quill-4.2.0/benchmarks/compile_time/qwrapper/CMakeLists.txt b/subprojects/quill-4.2.0/benchmarks/compile_time/qwrapper/CMakeLists.txt deleted file mode 100644 index 1f814a8..0000000 --- a/subprojects/quill-4.2.0/benchmarks/compile_time/qwrapper/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(LIB_NAME qwrapper_compile_time_bench) - -add_library(${LIB_NAME} STATIC - include/qwrapper/qwrapper.h - include/qwrapper/qwrapper.cpp) - -# Add include directories for this library -target_include_directories(${LIB_NAME} - PUBLIC - $ - $ - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}) - -# Link quill dependency -target_link_libraries(${LIB_NAME} PUBLIC quill::quill) \ No newline at end of file diff --git a/subprojects/quill-4.2.0/benchmarks/compile_time/qwrapper/include/qwrapper/qwrapper.cpp b/subprojects/quill-4.2.0/benchmarks/compile_time/qwrapper/include/qwrapper/qwrapper.cpp deleted file mode 100644 index 2a217eb..0000000 --- a/subprojects/quill-4.2.0/benchmarks/compile_time/qwrapper/include/qwrapper/qwrapper.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "qwrapper.h" - -#include "quill/Backend.h" -#include "quill/Frontend.h" -#include "quill/Logger.h" -#include "quill/sinks/ConsoleSink.h" - -void setup_quill(char const* log_file) -{ - quill::Backend::start(); - - auto console_sink = quill::Frontend::create_or_get_sink("s1"); - - quill::Frontend::create_or_get_logger("root", std::move(console_sink), - "%(time) [%(thread_id)] %(short_source_location:<28) " - "LOG_%(log_level:<9) %(logger:<12) %(message)", - "%H:%M:%S.%Qns", quill::Timezone::GmtTime); -} \ No newline at end of file diff --git a/subprojects/quill-4.2.0/benchmarks/compile_time/qwrapper/include/qwrapper/qwrapper.h b/subprojects/quill-4.2.0/benchmarks/compile_time/qwrapper/include/qwrapper/qwrapper.h deleted file mode 100644 index c71a95e..0000000 --- a/subprojects/quill-4.2.0/benchmarks/compile_time/qwrapper/include/qwrapper/qwrapper.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void setup_quill(char const* log_file); \ No newline at end of file diff --git a/subprojects/quill-4.2.0/benchmarks/hot_path_latency/CMakeLists.txt b/subprojects/quill-4.2.0/benchmarks/hot_path_latency/CMakeLists.txt deleted file mode 100644 index cd521cf..0000000 --- a/subprojects/quill-4.2.0/benchmarks/hot_path_latency/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -add_executable(BENCHMARK_quill_hot_path_rdtsc_clock hot_path_bench_config.h hot_path_bench.h quill_hot_path_rdtsc_clock.cpp) -set_common_compile_options(BENCHMARK_quill_hot_path_rdtsc_clock) -target_link_libraries(BENCHMARK_quill_hot_path_rdtsc_clock quill) - -add_executable(BENCHMARK_quill_hot_path_system_clock hot_path_bench_config.h hot_path_bench.h quill_hot_path_system_clock.cpp) -set_common_compile_options(BENCHMARK_quill_hot_path_system_clock) -target_link_libraries(BENCHMARK_quill_hot_path_system_clock quill) \ No newline at end of file diff --git a/subprojects/quill-4.2.0/benchmarks/hot_path_latency/hot_path_bench.h b/subprojects/quill-4.2.0/benchmarks/hot_path_latency/hot_path_bench.h deleted file mode 100644 index f38297d..0000000 --- a/subprojects/quill-4.2.0/benchmarks/hot_path_latency/hot_path_bench.h +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Copyright(c) 2020-present, Odysseas Georgoudis & quill contributors. - * Distributed under the MIT License (http://opensource.org/licenses/MIT) - */ - -#pragma once - -#include "hot_path_bench_config.h" - -#include "quill/backend/BackendUtilities.h" -#include "quill/backend/RdtscClock.h" -#include "quill/core/Rdtsc.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_WIN32) - #include -#else - #include -#endif - -inline uint16_t get_cpu_to_pin_thread(uint16_t thread_num) -{ - auto const num_cores = static_cast(std::thread::hardware_concurrency()); - - // If hardware_concurrency feature is not supported, zero value is returned. - if (num_cores == 0) - return 0; - - return thread_num % num_cores; -} - -// Instead of sleep -inline void wait(std::chrono::nanoseconds min, std::chrono::nanoseconds max) -{ -#ifdef PERF_ENABLED - // when in perf use sleep as the other variables add noise - std::this_thread::sleep_for(max); -#else - static std::random_device rd; - static std::mt19937 gen(rd()); - static std::uniform_int_distribution<> dis(static_cast(min.count()), static_cast(max.count())); - - auto const start_time = std::chrono::steady_clock::now(); - auto const end_time = start_time.time_since_epoch() + std::chrono::nanoseconds{dis(gen)}; - std::chrono::nanoseconds time_now; - do - { - time_now = std::chrono::steady_clock::now().time_since_epoch(); - } while (time_now < end_time); -#endif -} - -#ifdef PERF_ENABLED -/***/ -inline void run_log_benchmark(size_t num_iterations, size_t messages_per_iteration, - std::function on_thread_start, - std::function log_func, - std::function on_thread_exit, size_t current_thread_num) -{ - // running thread affinity - quill::detail::set_cpu_affinity(get_cpu_to_pin_thread(current_thread_num)); - - on_thread_start(); - - unsigned int aux; - // Main Benchmark - for (size_t iteration = 0; iteration < num_iterations; ++iteration) - { - double const d = iteration + (0.1 * iteration); - - auto const start = __rdtscp(&aux); - for (size_t i = 0; i < messages_per_iteration; ++i) - { - log_func(iteration, i, d); - } - auto const end = __rdtscp(&aux); - - // send the next batch of messages after x time - wait(MIN_WAIT_DURATION, MAX_WAIT_DURATION); - } - - on_thread_exit(); -} -#else -/***/ -inline void run_log_benchmark(size_t num_iterations, size_t messages_per_iteration, - std::function const& on_thread_start, - std::function const& log_func, - std::function const& on_thread_exit, uint16_t current_thread_num, - std::vector& latencies, double rdtsc_ns_per_tick) -{ - // running thread affinity - quill::detail::set_cpu_affinity(get_cpu_to_pin_thread(current_thread_num)); - - on_thread_start(); - - unsigned int aux; - // Main Benchmark - for (size_t iteration = 0; iteration < num_iterations; ++iteration) - { - double const d = static_cast(iteration) + (0.1 * static_cast(iteration)); - - auto const start = __rdtscp(&aux); - for (size_t i = 0; i < messages_per_iteration; ++i) - { - log_func(iteration, i, d); - } - auto const end = __rdtscp(&aux); - - uint64_t const latency{static_cast( - static_cast((end - start)) / static_cast(messages_per_iteration) * rdtsc_ns_per_tick)}; - latencies.push_back(latency); - - // send the next batch of messages after x time - wait(MIN_WAIT_DURATION, MAX_WAIT_DURATION); - } - - on_thread_exit(); -} -#endif - -/***/ -inline void run_benchmark(char const* benchmark_name, uint16_t thread_count, size_t num_iterations, - size_t messages_per_iteration, std::function const& on_thread_start, - std::function const& log_func, - std::function const& on_thread_exit) -{ - // main thread affinity - quill::detail::set_cpu_affinity(0); - -#ifndef PERF_ENABLED - std::cout << "running for " << thread_count << " thread(s)" << std::endl; - - quill::detail::RdtscClock rdtsc_clock{std::chrono::minutes{30}}; - - // each thread gets a vector of latencies - std::vector> latencies; - latencies.resize(thread_count); - for (auto& elem : latencies) - { - elem.reserve(num_iterations); - } -#endif - - std::vector threads; - threads.reserve(thread_count); - for (uint16_t thread_num = 0; thread_num < thread_count; ++thread_num) - { -#ifdef PERF_ENABLED - // Spawn num threads - threads.emplace_back(run_log_benchmark, num_iterations, (messages_per_iteration / thread_count), - on_thread_start, log_func, on_thread_exit, thread_num + 1); -#else - // Spawn num threads - threads.emplace_back(run_log_benchmark, num_iterations, - static_cast(messages_per_iteration / thread_count), - std::ref(on_thread_start), std::ref(log_func), std::ref(on_thread_exit), - static_cast(thread_num + 1u), std::ref(latencies[thread_num]), - rdtsc_clock.nanoseconds_per_tick()); -#endif - } - - // Wait for threads to finish - for (uint16_t i = 0; i < thread_count; ++i) - { - threads[i].join(); - } - -#ifndef PERF_ENABLED - // All threads have finished we can read all latencies - std::vector latencies_combined; - latencies_combined.reserve(num_iterations * thread_count); - for (auto const& elem : latencies) - { - latencies_combined.insert(latencies_combined.end(), elem.begin(), elem.end()); - } - - // Sort all latencies - std::sort(latencies_combined.begin(), latencies_combined.end()); - - std::cout - << "Thread Count " << thread_count << " - Total messages " << latencies_combined.size() * messages_per_iteration - << " - " << benchmark_name << "\n | 50th | 75th | 90th | 95th | 99th | 99.9th | Worst |\n" - << " | " - << latencies_combined[static_cast(static_cast(num_iterations * thread_count) * 0.5)] << " | " - << latencies_combined[static_cast(static_cast(num_iterations * thread_count) * 0.75)] - << " | " - << latencies_combined[static_cast(static_cast(num_iterations * thread_count) * 0.9)] << " | " - << latencies_combined[static_cast(static_cast(num_iterations * thread_count) * 0.95)] - << " | " - << latencies_combined[static_cast(static_cast(num_iterations * thread_count) * 0.99)] - << " | " - << latencies_combined[static_cast(static_cast(num_iterations * thread_count) * 0.999)] - << " | " << latencies_combined[static_cast(latencies_combined.size() - 1)] << " |\n\n"; -#endif -} \ No newline at end of file diff --git a/subprojects/quill-4.2.0/benchmarks/hot_path_latency/hot_path_bench_config.h b/subprojects/quill-4.2.0/benchmarks/hot_path_latency/hot_path_bench_config.h deleted file mode 100644 index ab7113a..0000000 --- a/subprojects/quill-4.2.0/benchmarks/hot_path_latency/hot_path_bench_config.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright(c) 2020-present, Odysseas Georgoudis & quill contributors. - * Distributed under the MIT License (http://opensource.org/licenses/MIT) - */ - -#pragma once -#include - -/** - * When running the benchmark using e.g. perf, enable this definition to remove extra noise - * from calculating and printing the results. - * - * To see shared cached lines : - * perf c2c record -g --call-graph dwarf,8192 ./benchmark_quill_call_site_latency - * perf c2c report -NN -g --call-graph -c pid,iaddr --stdio - */ -// #define PERF_ENABLED - -#define THREAD_LIST_COUNT \ - std::vector { 1, 4 } - -#define MESSAGES_PER_ITERATION \ - std::size_t { 20 } - -#define ITERATIONS \ - std::size_t { 100000 } - -/** - * Min-Max wait duration between each iteration - This lets the backend thread catch up - * a little bit with the caller thread, because the caller thread is so much faster. - * When the backend thread can't catch up it will cause the caller thread on the hot path - * to reallocate more space in the queue slowing it down. - * This benchmark is measuring latency not high throughput - * **/ -#define MIN_WAIT_DURATION \ - std::chrono::microseconds { 2000 } - -#define MAX_WAIT_DURATION \ - std::chrono::microseconds { 2200 } diff --git a/subprojects/quill-4.2.0/benchmarks/hot_path_latency/quill_hot_path_rdtsc_clock.cpp b/subprojects/quill-4.2.0/benchmarks/hot_path_latency/quill_hot_path_rdtsc_clock.cpp deleted file mode 100644 index 05aa0c4..0000000 --- a/subprojects/quill-4.2.0/benchmarks/hot_path_latency/quill_hot_path_rdtsc_clock.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Adding a benchmark for a another logger should be straight forward by duplicating and modifying - * this file. - */ - -#include "hot_path_bench.h" - -#include "quill/Backend.h" -#include "quill/Frontend.h" -#include "quill/LogMacros.h" -#include "quill/sinks/FileSink.h" - -struct FrontendOptions -{ - static constexpr quill::QueueType queue_type = quill::QueueType::UnboundedBlocking; - static constexpr uint32_t initial_queue_capacity = 131'072; - static constexpr uint32_t blocking_queue_retry_interval_ns = 800; - static constexpr bool huge_pages_enabled = false; -}; - -using Frontend = quill::FrontendImpl; -using Logger = quill::LoggerImpl; - -/***/ -void quill_benchmark(std::vector const& thread_count_array, - size_t num_iterations_per_thread, size_t messages_per_iteration) -{ - /** - MAIN THREAD START - Logger setup if any **/ - - /** - Setup Quill **/ - // main thread affinity - quill::detail::set_cpu_affinity(0); - - quill::BackendOptions backend_options; - backend_options.backend_cpu_affinity = 5; - - // Start the logging backend thread and give it some tiem to init - quill::Backend::start(backend_options); - - std::this_thread::sleep_for(std::chrono::milliseconds{100}); - - // wait for the backend thread to start - std::this_thread::sleep_for(std::chrono::seconds(1)); - - // Create a file sink to write to a file - std::shared_ptr file_sink = Frontend::create_or_get_sink( - "quill_hot_path_rdtsc_clock.log", - []() - { - quill::FileSinkConfig cfg; - cfg.set_open_mode('w'); - return cfg; - }(), - quill::FileEventNotifier{}); - - Logger* logger = Frontend::create_or_get_logger( - "bench_logger", std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)"); - - /** LOGGING THREAD FUNCTIONS - on_start, on_exit, log_func must be implemented **/ - /** those run on a several thread(s). It can be one or multiple threads based on THREAD_LIST_COUNT config */ - auto on_start = []() { - // on thread start - Frontend::preallocate(); - }; - - auto on_exit = [logger]() - { - // on thread exit we block flush, so the next benchmark starts with the backend thread ready - // to process the messages - logger->flush_log(); - }; - - // on main - auto log_func = [logger](uint64_t k, uint64_t i, double d) { - // Main logging function - // This will get called MESSAGES_PER_ITERATION * ITERATIONS for each caller thread. - // MESSAGES_PER_ITERATION will get averaged to a single number - - LOG_INFO(logger, "Logging iteration: {}, message: {}, double: {}", k, i, d); - }; - - /** ALWAYS REQUIRED **/ - // Run the benchmark for n threads - for (auto thread_count : thread_count_array) - { - run_benchmark("Logger: Quill - Benchmark: Hot Path Latency / Nanoseconds", thread_count, - num_iterations_per_thread, messages_per_iteration, on_start, log_func, on_exit); - } -} - -/***/ -int main(int, char**) { quill_benchmark(THREAD_LIST_COUNT, ITERATIONS, MESSAGES_PER_ITERATION); } \ No newline at end of file diff --git a/subprojects/quill-4.2.0/benchmarks/hot_path_latency/quill_hot_path_system_clock.cpp b/subprojects/quill-4.2.0/benchmarks/hot_path_latency/quill_hot_path_system_clock.cpp deleted file mode 100644 index 41f8b1c..0000000 --- a/subprojects/quill-4.2.0/benchmarks/hot_path_latency/quill_hot_path_system_clock.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Adding a benchmark for a another logger should be straight forward by duplicating and modifying - * this file. - */ - -#include "hot_path_bench.h" - -#include "quill/Backend.h" -#include "quill/Frontend.h" -#include "quill/LogMacros.h" -#include "quill/sinks/FileSink.h" - -struct FrontendOptions -{ - static constexpr quill::QueueType queue_type = quill::QueueType::UnboundedBlocking; - static constexpr uint32_t initial_queue_capacity = 131'072; - static constexpr uint32_t blocking_queue_retry_interval_ns = 800; - static constexpr bool huge_pages_enabled = false; -}; - -using Frontend = quill::FrontendImpl; -using Logger = quill::LoggerImpl; - -/***/ -void quill_benchmark(std::vector const& thread_count_array, - size_t num_iterations_per_thread, size_t messages_per_iteration) -{ - /** - MAIN THREAD START - Logger setup if any **/ - - /** - Setup Quill **/ - // main thread affinity - quill::detail::set_cpu_affinity(0); - - quill::BackendOptions backend_options; - backend_options.backend_cpu_affinity = 5; - - // Start the logging backend thread and give it some tiem to init - quill::Backend::start(backend_options); - - std::this_thread::sleep_for(std::chrono::milliseconds{100}); - - // wait for the backend thread to start - std::this_thread::sleep_for(std::chrono::seconds(1)); - - // Create a file sink to write to a file - std::shared_ptr file_sink = Frontend::create_or_get_sink( - "quill_hot_path_rdtsc_clock.log", - []() - { - quill::FileSinkConfig cfg; - cfg.set_open_mode('w'); - return cfg; - }(), - quill::FileEventNotifier{}); - - Logger* logger = Frontend::create_or_get_logger( - "bench_logger", std::move(file_sink), - "%(time) [%(thread_id)] %(short_source_location) %(log_level) %(message)", "%H:%M:%S.%Qns", - quill::Timezone::LocalTime, quill::ClockSourceType::System); - - /** LOGGING THREAD FUNCTIONS - on_start, on_exit, log_func must be implemented **/ - /** those run on a several thread(s). It can be one or multiple threads based on THREAD_LIST_COUNT config */ - auto on_start = []() - { - // on thread start - Frontend::preallocate(); - }; - - auto on_exit = [logger]() - { - // on thread exit we block flush, so the next benchmark starts with the backend thread ready - // to process the messages - logger->flush_log(); - }; - - // on main - auto log_func = [logger](uint64_t k, uint64_t i, double d) - { - // Main logging function - // This will get called MESSAGES_PER_ITERATION * ITERATIONS for each caller thread. - // MESSAGES_PER_ITERATION will get averaged to a single number - - LOG_INFO(logger, "Logging iteration: {}, message: {}, double: {}", k, i, d); - }; - - /** ALWAYS REQUIRED **/ - // Run the benchmark for n threads - for (auto thread_count : thread_count_array) - { - run_benchmark("Logger: Quill - Benchmark: Hot Path Latency / Nanoseconds", thread_count, - num_iterations_per_thread, messages_per_iteration, on_start, log_func, on_exit); - } -} - -/***/ -int main(int, char**) { quill_benchmark(THREAD_LIST_COUNT, ITERATIONS, MESSAGES_PER_ITERATION); } \ No newline at end of file diff --git a/subprojects/quill-4.2.0/cmake/FindSphinx.cmake b/subprojects/quill-4.2.0/cmake/FindSphinx.cmake deleted file mode 100644 index 24bf486..0000000 --- a/subprojects/quill-4.2.0/cmake/FindSphinx.cmake +++ /dev/null @@ -1,11 +0,0 @@ -#Look for an executable called sphinx-build -find_program(SPHINX_EXECUTABLE - NAMES sphinx-build - DOC "Path to sphinx-build executable") - -include(FindPackageHandleStandardArgs) - -#Handle standard arguments to find_package like REQUIRED and QUIET -find_package_handle_standard_args(Sphinx - "Failed to find sphinx-build executable" - SPHINX_EXECUTABLE) \ No newline at end of file diff --git a/subprojects/quill-4.2.0/cmake/SetCommonCompileOptions.cmake b/subprojects/quill-4.2.0/cmake/SetCommonCompileOptions.cmake deleted file mode 100644 index 8ba5bf6..0000000 --- a/subprojects/quill-4.2.0/cmake/SetCommonCompileOptions.cmake +++ /dev/null @@ -1,21 +0,0 @@ -# Define the function to set common compile options -function(set_common_compile_options target_name) - cmake_parse_arguments(COMPILE_OPTIONS "" "VISIBILITY" "" ${ARGN}) - - # Set default visibility to PRIVATE if not provided - if (NOT DEFINED COMPILE_OPTIONS_VISIBILITY) - set(COMPILE_OPTIONS_VISIBILITY PRIVATE) - endif () - - target_compile_options(${target_name} ${COMPILE_OPTIONS_VISIBILITY} - $<$,$,$>: - -Wall -Wextra -Wconversion -pedantic -Wfatal-errors -Wno-unused-private-field -Wno-gnu-zero-variadic-macro-arguments -Wno-unused-parameter> - $<$:/bigobj /WX /W4 /wd4324 /wd4189 /wd4996 /wd4100 /wd4127 /wd4702>) - - # Additional MSVC specific options - if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - if (NOT QUILL_NO_EXCEPTIONS) - target_compile_options(${target_name} ${COMPILE_OPTIONS_VISIBILITY} /EHsc) - endif () - endif () -endfunction() \ No newline at end of file diff --git a/subprojects/quill-4.2.0/cmake/doctest.cmake b/subprojects/quill-4.2.0/cmake/doctest.cmake deleted file mode 100644 index 169bbcd..0000000 --- a/subprojects/quill-4.2.0/cmake/doctest.cmake +++ /dev/null @@ -1,189 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -#[=======================================================================[.rst: -doctest ------ - -This module defines a function to help use the doctest test framework. - -The :command:`doctest_discover_tests` discovers tests by asking the compiled test -executable to enumerate its tests. This does not require CMake to be re-run -when tests change. However, it may not work in a cross-compiling environment, -and setting test properties is less convenient. - -This command is intended to replace use of :command:`add_test` to register -tests, and will create a separate CTest test for each doctest test case. Note -that this is in some cases less efficient, as common set-up and tear-down logic -cannot be shared by multiple test cases executing in the same instance. -However, it provides more fine-grained pass/fail information to CTest, which is -usually considered as more beneficial. By default, the CTest test name is the -same as the doctest name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``. - -.. command:: doctest_discover_tests - - Automatically add tests with CTest by querying the compiled test executable - for available tests:: - - doctest_discover_tests(target - [TEST_SPEC arg1...] - [EXTRA_ARGS arg1...] - [WORKING_DIRECTORY dir] - [TEST_PREFIX prefix] - [TEST_SUFFIX suffix] - [PROPERTIES name1 value1...] - [ADD_LABELS value] - [TEST_LIST var] - [JUNIT_OUTPUT_DIR dir] - ) - - ``doctest_discover_tests`` sets up a post-build command on the test executable - that generates the list of tests by parsing the output from running the test - with the ``--list-test-cases`` argument. This ensures that the full - list of tests is obtained. Since test discovery occurs at build time, it is - not necessary to re-run CMake when the list of tests changes. - However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set - in order to function in a cross-compiling environment. - - Additionally, setting properties on tests is somewhat less convenient, since - the tests are not available at CMake time. Additional test properties may be - assigned to the set of tests as a whole using the ``PROPERTIES`` option. If - more fine-grained test control is needed, custom content may be provided - through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES` - directory property. The set of discovered tests is made accessible to such a - script via the ``_TESTS`` variable. - - The options are: - - ``target`` - Specifies the doctest executable, which must be a known CMake executable - target. CMake will substitute the location of the built executable when - running the test. - - ``TEST_SPEC arg1...`` - Specifies test cases, wildcarded test cases, tags and tag expressions to - pass to the doctest executable with the ``--list-test-cases`` argument. - - ``EXTRA_ARGS arg1...`` - Any extra arguments to pass on the command line to each test case. - - ``WORKING_DIRECTORY dir`` - Specifies the directory in which to run the discovered test cases. If this - option is not provided, the current binary directory is used. - - ``TEST_PREFIX prefix`` - Specifies a ``prefix`` to be prepended to the name of each discovered test - case. This can be useful when the same test executable is being used in - multiple calls to ``doctest_discover_tests()`` but with different - ``TEST_SPEC`` or ``EXTRA_ARGS``. - - ``TEST_SUFFIX suffix`` - Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of - every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may - be specified. - - ``PROPERTIES name1 value1...`` - Specifies additional properties to be set on all tests discovered by this - invocation of ``doctest_discover_tests``. - - ``ADD_LABELS value`` - Specifies if the test labels should be set automatically. - - ``TEST_LIST var`` - Make the list of tests available in the variable ``var``, rather than the - default ``_TESTS``. This can be useful when the same test - executable is being used in multiple calls to ``doctest_discover_tests()``. - Note that this variable is only available in CTest. - - ``JUNIT_OUTPUT_DIR dir`` - If specified, the parameter is passed along with ``--reporters=junit`` - and ``--out=`` to the test executable. The actual file name is the same - as the test target, including prefix and suffix. This should be used - instead of EXTRA_ARGS to avoid race conditions writing the XML result - output when using parallel test execution. - -#]=======================================================================] - -#------------------------------------------------------------------------------ -function(doctest_discover_tests TARGET) - cmake_parse_arguments( - "" - "" - "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;JUNIT_OUTPUT_DIR" - "TEST_SPEC;EXTRA_ARGS;PROPERTIES;ADD_LABELS" - ${ARGN} - ) - - if(NOT _WORKING_DIRECTORY) - set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - endif() - if(NOT _TEST_LIST) - set(_TEST_LIST ${TARGET}_TESTS) - endif() - - ## Generate a unique name based on the extra arguments - string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}") - string(SUBSTRING ${args_hash} 0 7 args_hash) - - # Define rule to generate test list for aforementioned test executable - set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake") - set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake") - get_property(crosscompiling_emulator - TARGET ${TARGET} - PROPERTY CROSSCOMPILING_EMULATOR - ) - add_custom_command( - TARGET ${TARGET} POST_BUILD - BYPRODUCTS "${ctest_tests_file}" - COMMAND "${CMAKE_COMMAND}" - -D "TEST_TARGET=${TARGET}" - -D "TEST_EXECUTABLE=$" - -D "TEST_EXECUTOR=${crosscompiling_emulator}" - -D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}" - -D "TEST_SPEC=${_TEST_SPEC}" - -D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}" - -D "TEST_PROPERTIES=${_PROPERTIES}" - -D "TEST_ADD_LABELS=${_ADD_LABELS}" - -D "TEST_PREFIX=${_TEST_PREFIX}" - -D "TEST_SUFFIX=${_TEST_SUFFIX}" - -D "TEST_LIST=${_TEST_LIST}" - -D "TEST_JUNIT_OUTPUT_DIR=${_JUNIT_OUTPUT_DIR}" - -D "CTEST_FILE=${ctest_tests_file}" - -P "${_DOCTEST_DISCOVER_TESTS_SCRIPT}" - VERBATIM - ) - - file(WRITE "${ctest_include_file}" - "if(EXISTS \"${ctest_tests_file}\")\n" - " include(\"${ctest_tests_file}\")\n" - "else()\n" - " add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n" - "endif()\n" - ) - - if(NOT CMAKE_VERSION VERSION_LESS 3.10) - # Add discovered tests to directory TEST_INCLUDE_FILES - set_property(DIRECTORY - APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}" - ) - else() - # Add discovered tests as directory TEST_INCLUDE_FILE if possible - get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET) - if(NOT ${test_include_file_set}) - set_property(DIRECTORY - PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}" - ) - else() - message(FATAL_ERROR - "Cannot set more than one TEST_INCLUDE_FILE" - ) - endif() - endif() - -endfunction() - -############################################################################### - -set(_DOCTEST_DISCOVER_TESTS_SCRIPT - ${CMAKE_CURRENT_LIST_DIR}/doctestAddTests.cmake - ) diff --git a/subprojects/quill-4.2.0/cmake/doctestAddTests.cmake b/subprojects/quill-4.2.0/cmake/doctestAddTests.cmake deleted file mode 100644 index ec7f21b..0000000 --- a/subprojects/quill-4.2.0/cmake/doctestAddTests.cmake +++ /dev/null @@ -1,120 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -set(prefix "${TEST_PREFIX}") -set(suffix "${TEST_SUFFIX}") -set(spec ${TEST_SPEC}) -set(extra_args ${TEST_EXTRA_ARGS}) -set(properties ${TEST_PROPERTIES}) -set(add_labels ${TEST_ADD_LABELS}) -set(junit_output_dir "${TEST_JUNIT_OUTPUT_DIR}") -set(script) -set(suite) -set(tests) - -function(add_command NAME) - set(_args "") - foreach(_arg ${ARGN}) - if(_arg MATCHES "[^-./:a-zA-Z0-9_]") - set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument - else() - set(_args "${_args} ${_arg}") - endif() - endforeach() - set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE) -endfunction() - -# Run test executable to get list of available tests -if(NOT EXISTS "${TEST_EXECUTABLE}") - message(FATAL_ERROR - "Specified test executable '${TEST_EXECUTABLE}' does not exist" - ) -endif() - -if("${spec}" MATCHES .) - set(spec "--test-case=${spec}") -endif() - -execute_process( - COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-cases - OUTPUT_VARIABLE output - RESULT_VARIABLE result - WORKING_DIRECTORY "${TEST_WORKING_DIR}" -) -if(NOT ${result} EQUAL 0) - message(FATAL_ERROR - "Error running test executable '${TEST_EXECUTABLE}':\n" - " Result: ${result}\n" - " Output: ${output}\n" - ) -endif() - -string(REPLACE "\n" ";" output "${output}") - -# Parse output -foreach(line ${output}) - if("${line}" STREQUAL "===============================================================================" OR "${line}" MATCHES [==[^\[doctest\] ]==]) - continue() - endif() - set(test ${line}) - set(labels "") - if(${add_labels}) - # get test suite that test belongs to - execute_process( - COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" --test-case=${test} --list-test-suites - OUTPUT_VARIABLE labeloutput - RESULT_VARIABLE labelresult - WORKING_DIRECTORY "${TEST_WORKING_DIR}" - ) - if(NOT ${labelresult} EQUAL 0) - message(FATAL_ERROR - "Error running test executable '${TEST_EXECUTABLE}':\n" - " Result: ${labelresult}\n" - " Output: ${labeloutput}\n" - ) - endif() - - string(REPLACE "\n" ";" labeloutput "${labeloutput}") - foreach(labelline ${labeloutput}) - if("${labelline}" STREQUAL "===============================================================================" OR "${labelline}" MATCHES [==[^\[doctest\] ]==]) - continue() - endif() - list(APPEND labels ${labelline}) - endforeach() - endif() - - if(NOT "${junit_output_dir}" STREQUAL "") - # turn testname into a valid filename by replacing all special characters with "-" - string(REGEX REPLACE "[/\\:\"|<>]" "-" test_filename "${test}") - set(TEST_JUNIT_OUTPUT_PARAM "--reporters=junit" "--out=${junit_output_dir}/${prefix}${test_filename}${suffix}.xml") - else() - unset(TEST_JUNIT_OUTPUT_PARAM) - endif() - # use escape commas to handle properly test cases with commas inside the name - string(REPLACE "," "\\," test_name ${test}) - # ...and add to script - add_command(add_test - "${prefix}${test}${suffix}" - ${TEST_EXECUTOR} - "${TEST_EXECUTABLE}" - "--test-case=${test_name}" - "${TEST_JUNIT_OUTPUT_PARAM}" - ${extra_args} - ) - add_command(set_tests_properties - "${prefix}${test}${suffix}" - PROPERTIES - WORKING_DIRECTORY "${TEST_WORKING_DIR}" - ${properties} - LABELS ${labels} - ) - unset(labels) - list(APPEND tests "${prefix}${test}${suffix}") -endforeach() - -# Create a list of all discovered tests, which users may use to e.g. set -# properties on the tests -add_command(set ${TEST_LIST} ${tests}) - -# Write CTest script -file(WRITE "${CTEST_FILE}" "${script}") \ No newline at end of file diff --git a/subprojects/quill-4.2.0/docs/CMakeLists.txt b/subprojects/quill-4.2.0/docs/CMakeLists.txt deleted file mode 100644 index 1df3edf..0000000 --- a/subprojects/quill-4.2.0/docs/CMakeLists.txt +++ /dev/null @@ -1,55 +0,0 @@ -find_package(Doxygen REQUIRED) - -# Find all the public headers -get_target_property(QUILL_PUBLIC_HEADER_DIR quill INTERFACE_INCLUDE_DIRECTORIES) -file(GLOB_RECURSE QUILL_PUBLIC_HEADERS ${QUILL_PUBLIC_HEADER_DIR}/*.h) - -set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/quill) -set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doxygen) -set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/xml/index.xml) -set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) -set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - -#Replace variables inside @@ with the current values -configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY) - -file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR}) #Doxygen won't create this for us -add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE} - DEPENDS ${QUILL_PUBLIC_HEADERS} - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} - MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN} - COMMENT "Generating docs") - -add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE}) - -find_package(Sphinx REQUIRED) - -set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}) -set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx) -set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html) - -# Only regenerate Sphinx when: -# - Doxygen has rerun -# - Our doc files have been updated -# - The Sphinx config has been updated -add_custom_command(OUTPUT ${SPHINX_INDEX_FILE} - COMMAND - ${SPHINX_EXECUTABLE} -b html - # Tell Breathe where to find the Doxygen output - -Dbreathe_projects.Quill=${DOXYGEN_OUTPUT_DIR}/xml - ${SPHINX_SOURCE} ${SPHINX_BUILD} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS - # Other docs files you want to track should go here (or in some variable) - ${CMAKE_CURRENT_SOURCE_DIR}/index.rst - ${CMAKE_CURRENT_SOURCE_DIR}/users-api.rst - ${CMAKE_CURRENT_SOURCE_DIR}/install.rst - ${CMAKE_CURRENT_SOURCE_DIR}/usage.rst - ${CMAKE_CURRENT_SOURCE_DIR}/tutorial.rst - ${CMAKE_CURRENT_SOURCE_DIR}/features.rst - ${DOXYGEN_INDEX_FILE} - MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py - COMMENT "Generating documentation with Sphinx") - -# Nice named target so we can run the job easily -add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE}) \ No newline at end of file diff --git a/subprojects/quill-4.2.0/docs/Doxyfile.in b/subprojects/quill-4.2.0/docs/Doxyfile.in deleted file mode 100644 index d30e770..0000000 --- a/subprojects/quill-4.2.0/docs/Doxyfile.in +++ /dev/null @@ -1,2660 +0,0 @@ -# Doxyfile 1.9.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a double hash (##) is considered a comment and is placed in -# front of the TAG it is preceding. -# -# All text after a single hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists, items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (\" \"). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the configuration -# file that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# https://www.gnu.org/software/libiconv/ for the list of possible encodings. -# The default value is: UTF-8. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by -# double-quotes, unless you are using Doxywizard) that should identify the -# project for which the documentation is generated. This name is used in the -# title of most generated pages and in a few other places. -# The default value is: My Project. - -PROJECT_NAME = "My Project" - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. This -# could be handy for archiving the generated documentation or if some version -# control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a -# quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify a logo or an icon that is included -# in the documentation. The maximum height of the logo should not exceed 55 -# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy -# the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path -# into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If -# left blank the current directory will be used. - -OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIR@" - -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where -# putting all generated files in the same directory would otherwise causes -# performance problems for the file system. -# The default value is: NO. - -CREATE_SUBDIRS = NO - -# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII -# characters to appear in the names of generated files. If set to NO, non-ASCII -# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode -# U+3044. -# The default value is: NO. - -ALLOW_UNICODE_NAMES = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. -# The default value is: English. - -OUTPUT_LANGUAGE = English - -# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all generated output in the proper direction. -# Possible values are: None, LTR, RTL and Context. -# The default value is: None. - -OUTPUT_TEXT_DIRECTION = None - -# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member -# descriptions after the members that are listed in the file and class -# documentation (similar to Javadoc). Set to NO to disable this. -# The default value is: YES. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief -# description of a member or function before the detailed description -# -# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. -# The default value is: YES. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator that is -# used to form the text in various listings. Each string in this list, if found -# as the leading text of the brief description, will be stripped from the text -# and the result, after processing the whole list, is used as the annotated -# text. Otherwise, the brief description is used as-is. If left blank, the -# following values are used ($name is automatically replaced with the name of -# the entity):The $name class, The $name widget, The $name file, is, provides, -# specifies, contains, represents, a, an and the. - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief -# description. -# The default value is: NO. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. -# The default value is: NO. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path -# before files name in the file list and in the header files. If set to NO the -# shortest path that makes the file name unique will be used -# The default value is: YES. - -FULL_PATH_NAMES = YES - -# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. -# Stripping is only done if one of the specified strings matches the left-hand -# part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to -# strip. -# -# Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. -# This tag requires that the tag FULL_PATH_NAMES is set to YES. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the -# path mentioned in the documentation of a class, which tells the reader which -# header file to include in order to use a class. If left blank only the name of -# the header file containing the class definition is used. Otherwise one should -# specify the list of include paths that are normally passed to the compiler -# using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but -# less readable) file names. This can be useful is your file systems doesn't -# support long names like on DOS, Mac, or CD-ROM. -# The default value is: NO. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the -# first line (until the first dot) of a Javadoc-style comment as the brief -# description. If set to NO, the Javadoc-style will behave just like regular Qt- -# style comments (thus requiring an explicit @brief command for a brief -# description.) -# The default value is: NO. - -JAVADOC_AUTOBRIEF = NO - -# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line -# such as -# /*************** -# as being the beginning of a Javadoc-style comment "banner". If set to NO, the -# Javadoc-style will behave just like regular comments and it will not be -# interpreted by doxygen. -# The default value is: NO. - -JAVADOC_BANNER = NO - -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first -# line (until the first dot) of a Qt-style comment as the brief description. If -# set to NO, the Qt-style will behave just like regular Qt-style comments (thus -# requiring an explicit \brief command for a brief description.) -# The default value is: NO. - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a -# multi-line C++ special comment block (i.e. a block of //! or /// comments) as -# a brief description. This used to be the default behavior. The new default is -# to treat a multi-line C++ comment block as a detailed description. Set this -# tag to YES if you prefer the old behavior instead. -# -# Note that setting this tag to YES also means that rational rose comments are -# not recognized any more. -# The default value is: NO. - -MULTILINE_CPP_IS_BRIEF = NO - -# By default Python docstrings are displayed as preformatted text and doxygen's -# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the -# doxygen's special commands can be used and the contents of the docstring -# documentation blocks is shown as doxygen documentation. -# The default value is: YES. - -PYTHON_DOCSTRING = YES - -# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the -# documentation from any documented member that it re-implements. -# The default value is: YES. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new -# page for each member. If set to NO, the documentation of a member will be part -# of the file/class/namespace that contains it. -# The default value is: NO. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen -# uses this value to replace tabs by spaces in code fragments. -# Minimum value: 1, maximum value: 16, default value: 4. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that act as commands in -# the documentation. An alias has the form: -# name=value -# For example adding -# "sideeffect=@par Side Effects:\n" -# will allow you to put the command \sideeffect (or @sideeffect) in the -# documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. For -# instance, some of the names that are used will be different. The list of all -# members will be omitted, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or -# Python sources only. Doxygen will then generate output that is more tailored -# for that language. For instance, namespaces will be presented as packages, -# qualified scopes will look different, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources. Doxygen will then generate output that is tailored for Fortran. -# The default value is: NO. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for VHDL. -# The default value is: NO. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice -# sources only. Doxygen will then generate output that is more tailored for that -# language. For instance, namespaces will be presented as modules, types will be -# separated into more groups, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_SLICE = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: -# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser -# tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files). For instance to make doxygen treat .inc files -# as Fortran files (default is PHP), and .f files as C (default is Fortran), -# use: inc=Fortran f=C. -# -# Note: For files without extension you can use no_extension as a placeholder. -# -# Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. When specifying no_extension you should add -# * to the FILE_PATTERNS. -# -# Note see also the list of default file extension mappings. - -EXTENSION_MAPPING = - -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments -# according to the Markdown format, which allows for more readable -# documentation. See https://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in -# case of backward compatibilities issues. -# The default value is: YES. - -MARKDOWN_SUPPORT = YES - -# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up -# to that level are automatically included in the table of contents, even if -# they do not have an id attribute. -# Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 5. -# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. - -TOC_INCLUDE_HEADINGS = 5 - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by putting a % sign in front of the word or -# globally by setting AUTOLINK_SUPPORT to NO. -# The default value is: YES. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. -# The default value is: NO. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. -# The default value is: NO. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. -# The default value is: NO. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. -# This will only work if the methods are indeed getting or setting a simple -# type. If this is not the case, or you want to show the methods anyway, you -# should set this option to NO. -# The default value is: YES. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. -# The default value is: NO. - -DISTRIBUTE_GROUP_DOC = NO - -# If one adds a struct or class to a group and this option is enabled, then also -# any nested class or struct is added to the same group. By default this option -# is disabled and one has to add nested compounds explicitly via \ingroup. -# The default value is: NO. - -GROUP_NESTED_COMPOUNDS = NO - -# Set the SUBGROUPING tag to YES to allow class member groups of the same type -# (for instance a group of public functions) to be put as a subgroup of that -# type (e.g. under the Public Functions section). Set it to NO to prevent -# subgrouping. Alternatively, this can be done per class using the -# \nosubgrouping command. -# The default value is: YES. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions -# are shown inside the group in which they are included (e.g. using \ingroup) -# instead of on a separate page (for HTML and Man pages) or section (for LaTeX -# and RTF). -# -# Note that this feature does not work in combination with -# SEPARATE_MEMBER_PAGES. -# The default value is: NO. - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions -# with only public data fields or simple typedef fields will be shown inline in -# the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO, structs, classes, and unions are shown on a separate page (for HTML and -# Man pages) or section (for LaTeX and RTF). -# The default value is: NO. - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or -# enum is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically be -# useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. -# The default value is: NO. - -TYPEDEF_HIDES_STRUCT = NO - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can be -# an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The -# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range -# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest -# the optimal cache size from a speed point of view. -# Minimum value: 0, maximum value: 9, default value: 0. - -LOOKUP_CACHE_SIZE = 0 - -# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use -# during processing. When set to 0 doxygen will based this on the number of -# cores available in the system. You can set it explicitly to a value larger -# than 0 to get more control over the balance between CPU load and processing -# speed. At this moment only the input processing can be done using multiple -# threads. Since this is still an experimental feature the default is set to 1, -# which efficively disables parallel processing. Please report any issues you -# encounter. Generating dot graphs in parallel is controlled by the -# DOT_NUM_THREADS setting. -# Minimum value: 0, maximum value: 32, default value: 1. - -NUM_PROC_THREADS = 1 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in -# documentation are documented, even if no documentation was available. Private -# class members and static file members will be hidden unless the -# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. -# Note: This will also disable the warnings about undocumented members that are -# normally produced when WARNINGS is set to YES. -# The default value is: NO. - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will -# be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIVATE = YES - -# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual -# methods of a class will be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIV_VIRTUAL = NO - -# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal -# scope will be included in the documentation. -# The default value is: NO. - -EXTRACT_PACKAGE = YES - -# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be -# included in the documentation. -# The default value is: NO. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO, -# only classes defined in header files are included. Does not have any effect -# for Java sources. -# The default value is: YES. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. If set to YES, local methods, -# which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO, only methods in the interface are -# included. -# The default value is: NO. - -EXTRACT_LOCAL_METHODS = YES - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base name of -# the file that contains the anonymous namespace. By default anonymous namespace -# are hidden. -# The default value is: NO. - -EXTRACT_ANON_NSPACES = NO - -# If this flag is set to YES, the name of an unnamed parameter in a declaration -# will be determined by the corresponding definition. By default unnamed -# parameters remain unnamed in the output. -# The default value is: YES. - -RESOLVE_UNNAMED_PARAMS = YES - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all -# undocumented members inside documented classes or files. If set to NO these -# members will be included in the various overviews, but no documentation -# section is generated. This option has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. If set -# to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# declarations. If set to NO, these declarations will be included in the -# documentation. -# The default value is: NO. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO, these -# blocks will be appended to the function's detailed documentation block. -# The default value is: NO. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation that is typed after a -# \internal command is included. If the tag is set to NO then the documentation -# will be excluded. Set it to YES to include the internal documentation. -# The default value is: NO. - -INTERNAL_DOCS = NO - -# With the correct setting of option CASE_SENSE_NAMES doxygen will better be -# able to match the capabilities of the underlying filesystem. In case the -# filesystem is case sensitive (i.e. it supports files in the same directory -# whose names only differ in casing), the option must be set to YES to properly -# deal with such files in case they appear in the input. For filesystems that -# are not case sensitive the option should be be set to NO to properly deal with -# output files written for symbols that only differ in casing, such as for two -# classes, one named CLASS and the other named Class, and to also support -# references to files without having to specify the exact matching casing. On -# Windows (including Cygwin) and MacOS, users should typically set this option -# to NO, whereas on Linux or other Unix flavors it should typically be set to -# YES. -# The default value is: system dependent. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES, the -# scope will be hidden. -# The default value is: NO. - -HIDE_SCOPE_NAMES = NO - -# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will -# append additional text to a page's title, such as Class Reference. If set to -# YES the compound reference will be hidden. -# The default value is: NO. - -HIDE_COMPOUND_REFERENCE= NO - -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of -# the files that are included by a file in the documentation of that file. -# The default value is: YES. - -SHOW_INCLUDE_FILES = YES - -# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each -# grouped member an include statement to the documentation, telling the reader -# which file to include in order to use the member. -# The default value is: NO. - -SHOW_GROUPED_MEMB_INC = NO - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include -# files with double quotes in the documentation rather than with sharp brackets. -# The default value is: NO. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the -# documentation for inline members. -# The default value is: YES. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the -# (detailed) documentation of file and class members alphabetically by member -# name. If set to NO, the members will appear in declaration order. -# The default value is: YES. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief -# descriptions of file, namespace and class members alphabetically by member -# name. If set to NO, the members will appear in declaration order. Note that -# this will also influence the order of the classes in the class list. -# The default value is: NO. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the -# (brief and detailed) documentation of class members so that constructors and -# destructors are listed first. If set to NO the constructors will appear in the -# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. -# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief -# member documentation. -# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting -# detailed member documentation. -# The default value is: NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy -# of group names into alphabetical order. If set to NO the group names will -# appear in their defined order. -# The default value is: NO. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by -# fully-qualified names, including namespaces. If set to NO, the class list will -# be sorted only by class name, not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the alphabetical -# list. -# The default value is: NO. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper -# type resolution of all parameters of a function it will reject a match between -# the prototype and the implementation of a member function even if there is -# only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still -# accept a match between prototype and implementation in such cases. -# The default value is: NO. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo -# list. This list is created by putting \todo commands in the documentation. -# The default value is: YES. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test -# list. This list is created by putting \test commands in the documentation. -# The default value is: YES. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug -# list. This list is created by putting \bug commands in the documentation. -# The default value is: YES. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) -# the deprecated list. This list is created by putting \deprecated commands in -# the documentation. -# The default value is: YES. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional documentation -# sections, marked by \if ... \endif and \cond -# ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the -# initial value of a variable or macro / define can have for it to appear in the -# documentation. If the initializer consists of more lines than specified here -# it will be hidden. Use a value of 0 to hide initializers completely. The -# appearance of the value of individual variables and macros / defines can be -# controlled using \showinitializer or \hideinitializer command in the -# documentation regardless of this setting. -# Minimum value: 0, maximum value: 10000, default value: 30. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES, the -# list will mention the files that were used to generate the documentation. -# The default value is: YES. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This -# will remove the Files entry from the Quick Index and from the Folder Tree View -# (if specified). -# The default value is: YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces -# page. This will remove the Namespaces entry from the Quick Index and from the -# Folder Tree View (if specified). -# The default value is: YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command command input-file, where command is the value of the -# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file -# version. For an example see the documentation. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can -# optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. -# -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE -# tag is left empty. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files containing -# the reference definitions. This must be a list of .bib files. The .bib -# extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. -# For LaTeX the style of the bibliography can be controlled using -# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. See also \cite for info how to create references. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the -# messages are off. -# The default value is: NO. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES -# this implies that the warnings are on. -# -# Tip: Turn warnings on while writing the documentation. -# The default value is: YES. - -WARNINGS = YES - -# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate -# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag -# will automatically be disabled. -# The default value is: YES. - -WARN_IF_UNDOCUMENTED = YES - -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. -# The default value is: YES. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that -# are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. -# The default value is: NO. - -WARN_NO_PARAMDOC = NO - -# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS -# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but -# at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. -# The default value is: NO. - -WARN_AS_ERROR = NO - -# The WARN_FORMAT tag determines the format of the warning messages that doxygen -# can produce. The string should contain the $file, $line, and $text tags, which -# will be replaced by the file and line number from which the warning originated -# and the warning text. Optionally the format may contain $version, which will -# be replaced by the version of the file (if it could be obtained via -# FILE_VERSION_FILTER) -# The default value is: $file:$line: $text. - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning and error -# messages should be written. If left blank the output is written to standard -# error (stderr). - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag is used to specify the files and/or directories that contain -# documented source files. You may enter file names like myfile.cpp or -# directories like /usr/src/myproject. Separate the files or directories with -# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING -# Note: If this tag is empty the current directory is searched. - -INPUT = "@DOXYGEN_INPUT_DIR@" - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses -# libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: -# https://www.gnu.org/software/libiconv/) for the list of possible encodings. -# The default value is: UTF-8. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# read by doxygen. -# -# Note the list of default checked file patterns might differ from the list of -# default file extension mappings. -# -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), -# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, -# *.ucf, *.qsf and *.ice. - -FILE_PATTERNS = *.c \ - *.cc \ - *.cxx \ - *.cpp \ - *.c++ \ - *.java \ - *.ii \ - *.ixx \ - *.ipp \ - *.i++ \ - *.inl \ - *.idl \ - *.ddl \ - *.odl \ - *.h \ - *.hh \ - *.hxx \ - *.hpp \ - *.h++ \ - *.cs \ - *.d \ - *.php \ - *.php4 \ - *.php5 \ - *.phtml \ - *.inc \ - *.m \ - *.markdown \ - *.md \ - *.mm \ - *.dox \ - *.py \ - *.pyw \ - *.f90 \ - *.f95 \ - *.f03 \ - *.f08 \ - *.f18 \ - *.f \ - *.for \ - *.vhd \ - *.vhdl \ - *.ucf \ - *.qsf \ - *.ice - -# The RECURSIVE tag can be used to specify whether or not subdirectories should -# be searched for input files as well. -# The default value is: NO. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. -# The default value is: NO. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories for example use the pattern */test/* - -EXCLUDE_PATTERNS = */quill/bundled/* */src/bundled/* */test/* - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or directories -# that contain example code fragments that are included (see the \include -# command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank all -# files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude commands -# irrespective of the value of the RECURSIVE tag. -# The default value is: NO. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or directories -# that contain images that are to be included in the documentation (see the -# \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command: -# -# -# -# where is the value of the INPUT_FILTER tag, and is the -# name of an input file. Doxygen will then use the output that the filter -# program writes to standard output. If FILTER_PATTERNS is specified, this tag -# will be ignored. -# -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: pattern=filter -# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how -# filters are used. If the FILTER_PATTERNS tag is empty or if none of the -# patterns match the file name, INPUT_FILTER is applied. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will also be used to filter the input files that are used for -# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). -# The default value is: NO. - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and -# it is also possible to disable source filtering for a specific pattern using -# *.ext= (so without naming a filter). -# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = - -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will be -# generated. Documented entities will be cross-referenced with these sources. -# -# Note: To get rid of all source code in the generated output, make sure that -# also VERBATIM_HEADERS is set to NO. -# The default value is: NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. -# The default value is: NO. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any -# special comment blocks from generated source code fragments. Normal C, C++ and -# Fortran comments will always remain visible. -# The default value is: YES. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# entity all documented functions referencing it will be listed. -# The default value is: NO. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES then for each documented function -# all documented entities called/used by that function will be listed. -# The default value is: NO. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES then the hyperlinks from functions in REFERENCES_RELATION and -# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will -# link to the documentation. -# The default value is: YES. - -REFERENCES_LINK_SOURCE = YES - -# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the -# source code will show a tooltip with additional information such as prototype, -# brief description and links to the definition and documentation. Since this -# will make the HTML file larger and loading of large files a bit slower, you -# can opt to disable this feature. -# The default value is: YES. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -SOURCE_TOOLTIPS = YES - -# If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in -# source browser. The htags tool is part of GNU's global source tagging system -# (see https://www.gnu.org/software/global/global.html). You will need version -# 4.8.6 or higher. -# -# To use it do the following: -# - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file -# - Make sure the INPUT points to the root of the source tree -# - Run doxygen as normal -# -# Doxygen will invoke htags (and that will in turn invoke gtags), so these -# tools must be available from the command line (i.e. in the search path). -# -# The result: instead of the source browser generated by doxygen, the links to -# source code will now point to the output of htags. -# The default value is: NO. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a -# verbatim copy of the header file for each class for which an include is -# specified. Set to NO to disable this. -# See also: Section \class. -# The default value is: YES. - -VERBATIM_HEADERS = YES - -# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: -# http://clang.llvm.org/) for more accurate parsing at the cost of reduced -# performance. This can be particularly helpful with template rich C++ code for -# which doxygen's built-in parser lacks the necessary type information. -# Note: The availability of this option depends on whether or not doxygen was -# generated with the -Duse_libclang=ON option for CMake. -# The default value is: NO. - -CLANG_ASSISTED_PARSING = NO - -# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to -# YES then doxygen will add the directory of each input to the include path. -# The default value is: YES. - -CLANG_ADD_INC_PATHS = YES - -# If clang assisted parsing is enabled you can provide the compiler with command -# line options that you would normally use when invoking the compiler. Note that -# the include paths will already be set by doxygen for the files and directories -# specified with INPUT and INCLUDE_PATH. -# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. - -CLANG_OPTIONS = - -# If clang assisted parsing is enabled you can provide the clang parser with the -# path to the directory containing a file called compile_commands.json. This -# file is the compilation database (see: -# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the -# options used when the source files were built. This is equivalent to -# specifying the -p option to a clang tool, such as clang-check. These options -# will then be passed to the parser. Any options specified with CLANG_OPTIONS -# will be added as well. -# Note: The availability of this option depends on whether or not doxygen was -# generated with the -Duse_libclang=ON option for CMake. - -CLANG_DATABASE_PATH = - -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all -# compounds will be generated. Enable this if the project contains a lot of -# classes, structs, unions or interfaces. -# The default value is: YES. - -ALPHABETICAL_INDEX = YES - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output -# The default value is: YES. - -GENERATE_HTML = NO - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a -# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of -# it. -# The default directory is: html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each -# generated HTML page (for example: .htm, .php, .asp). -# The default value is: .html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a -# standard header. -# -# To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. -# the setting GENERATE_TREEVIEW). It is highly recommended to start with a -# default header using -# doxygen -w html new_header.html new_footer.html new_stylesheet.css -# YourConfigFile -# and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally -# uses. -# Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description -# of the possible markers and block names see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard -# footer. See HTML_HEADER for more information on how to generate a default -# footer and what special commands can be used inside the footer. See also -# section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style -# sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. -# See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. -# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as -# it is more robust and this tag (HTML_STYLESHEET) will in the future become -# obsolete. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined -# cascading style sheets that are included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. -# This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefore more robust against future updates. -# Doxygen will copy the style sheet files to the output directory. -# Note: The order of the extra style sheet files is of importance (e.g. the last -# style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that the -# files will be copied as-is; there are no commands or markers available. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# https://en.wikipedia.org/wiki/Hue for more information. For instance the value -# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 -# purple, and 360 is red again. -# Minimum value: 0, maximum value: 359, default value: 220. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A -# value of 255 will produce the most vivid colors. -# Minimum value: 0, maximum value: 255, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the -# luminance component of the colors in the HTML output. Values below 100 -# gradually make the output lighter, whereas values above 100 make the output -# darker. The value divided by 100 is the actual gamma applied, so 80 represents -# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not -# change the gamma. -# Minimum value: 40, maximum value: 240, default value: 80. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - -# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML -# documentation will contain a main index with vertical navigation menus that -# are dynamically created via JavaScript. If disabled, the navigation index will -# consists of multiple levels of tabs that are statically embedded in every HTML -# page. Disable this option to support browsers that do not have JavaScript, -# like the Qt help browser. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_MENUS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries -# shown in the various tree structured indices initially; the user can expand -# and collapse entries dynamically later on. Doxygen will expand the tree to -# such a level that at most the specified number of entries are visible (unless -# a fully collapsed tree already exceeds this amount). So setting the number of -# entries 1 will produce a full collapsed tree by default. 0 is a special value -# representing an infinite number of entries and will result in a full expanded -# tree by default. -# Minimum value: 0, maximum value: 9999, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files will be -# generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: -# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To -# create a documentation set, doxygen will generate a Makefile in the HTML -# output directory. Running make will produce the docset in that directory and -# running make install will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy -# genXcode/_index.html for more information. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_DOCSET = NO - -# This tag determines the name of the docset feed. A documentation feed provides -# an umbrella under which multiple documentation sets from a single provider -# (such as a company or product suite) can be grouped. -# The default value is: Doxygen generated docs. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# This tag specifies a string that should uniquely identify the documentation -# set bundle. This should be a reverse domain-name style string, e.g. -# com.mycompany.MyDocSet. Doxygen will append .docset to the name. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. -# The default value is: org.doxygen.Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. -# The default value is: Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three -# additional HTML index files: index.hhp, index.hhc, and index.hhk. The -# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: -# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. -# -# The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML -# files are now used as the Windows 98 help format, and will replace the old -# Windows help format (.hlp) on all Windows platforms in the future. Compressed -# HTML files also contain an index, a table of contents, and you can search for -# words in the documentation. The HTML workshop also contains a viewer for -# compressed HTML files. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_HTMLHELP = NO - -# The CHM_FILE tag can be used to specify the file name of the resulting .chm -# file. You can add a path in front of the file if the result should not be -# written to the html output directory. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_FILE = - -# The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler (hhc.exe). If non-empty, -# doxygen will try to run the HTML help compiler on the generated index.hhp. -# The file has to be specified with full path. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -HHC_LOCATION = - -# The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the main .chm file (NO). -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -GENERATE_CHI = NO - -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) -# and project file content. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_INDEX_ENCODING = - -# The BINARY_TOC flag controls whether a binary table of contents is generated -# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it -# enables the Previous and Next buttons. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members to -# the table of contents of the HTML help documentation and to the tree view. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that -# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help -# (.qch) of the generated HTML documentation. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify -# the file name of the resulting .qch file. The path specified is relative to -# the HTML output folder. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help -# Project output. For more information please see Qt Help Project / Namespace -# (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt -# Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). -# The default value is: doc. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_VIRTUAL_FOLDER = doc - -# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom -# filter to add. For more information please see Qt Help Project / Custom -# Filters (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's filter section matches. Qt Help Project / Filter Attributes (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_SECT_FILTER_ATTRS = - -# The QHG_LOCATION tag can be used to specify the location (absolute path -# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to -# run qhelpgenerator on the generated .qhp file. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be -# generated, together with the HTML files, they form an Eclipse help plugin. To -# install this plugin and make it available under the help contents menu in -# Eclipse, the contents of the directory containing the HTML and XML files needs -# to be copied into the plugins directory of eclipse. The name of the directory -# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. -# After copying Eclipse needs to be restarted before the help appears. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the Eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have this -# name. Each documentation set should have its own identifier. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# If you want full control over the layout of the generated HTML pages it might -# be necessary to disable the index and replace it with your own. The -# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top -# of each HTML page. A value of NO enables the index and the value YES disables -# it. Since the tabs in the index contain the same information as the navigation -# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. If the tag -# value is set to YES, a side panel will be generated containing a tree-like -# index structure (just like the one that is generated for HTML Help). For this -# to work a browser that supports JavaScript, DHTML, CSS and frames is required -# (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. -# -# Note that a value of 0 will completely suppress the enum values from appearing -# in the overview section. -# Minimum value: 0, maximum value: 20, default value: 4. -# This tag requires that the tag GENERATE_HTML is set to YES. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used -# to set the initial width (in pixels) of the frame in which the tree is shown. -# Minimum value: 0, maximum value: 1500, default value: 250. -# This tag requires that the tag GENERATE_HTML is set to YES. - -TREEVIEW_WIDTH = 250 - -# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to -# external symbols imported via tag files in a separate window. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -EXT_LINKS_IN_WINDOW = NO - -# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg -# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see -# https://inkscape.org) to generate formulas as SVG images instead of PNGs for -# the HTML output. These images will generally look nicer at scaled resolutions. -# Possible values are: png (the default) and svg (looks nicer but requires the -# pdf2svg or inkscape tool). -# The default value is: png. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FORMULA_FORMAT = png - -# Use this tag to change the font size of LaTeX formulas included as images in -# the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML -# output directory to force them to be regenerated. -# Minimum value: 8, maximum value: 50, default value: 10. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - -# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands -# to create new LaTeX commands to be used in formulas as building blocks. See -# the section "Including formulas" for details. - -FORMULA_MACROFILE = - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# https://www.mathjax.org) which uses client side JavaScript for the rendering -# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX -# installed or if you want to formulas look prettier in the HTML output. When -# enabled you may also need to install MathJax separately and configure the path -# to it using the MATHJAX_RELPATH option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. -# Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. -# The default value is: HTML-CSS. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the HTML -# output directory using the MATHJAX_RELPATH option. The destination directory -# should contain the MathJax.js script. For instance, if the mathjax directory -# is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax -# Content Delivery Network so you can quickly see the result without installing -# MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 - -# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax -# extension names that should be enabled during MathJax rendering. For example -# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces -# of code that will be used on startup of the MathJax code. See the MathJax site -# (see: -# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an -# example see the documentation. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and -# should work on any modern browser. Note that when using HTML help -# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) -# there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then -# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to -# search using the keyboard; to jump to the search box use + S -# (what the is depends on the OS and browser, but it is typically -# , /