diff --git a/nano/core_test/CMakeLists.txt b/nano/core_test/CMakeLists.txt index 623e6f2601..0fd4003130 100644 --- a/nano/core_test/CMakeLists.txt +++ b/nano/core_test/CMakeLists.txt @@ -33,6 +33,7 @@ add_executable( network.cpp network_filter.cpp node.cpp + object_stream.cpp optimistic_scheduler.cpp processing_queue.cpp processor_service.cpp diff --git a/nano/core_test/object_stream.cpp b/nano/core_test/object_stream.cpp new file mode 100644 index 0000000000..1b280b3150 --- /dev/null +++ b/nano/core_test/object_stream.cpp @@ -0,0 +1,293 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +TEST (object_stream, primitive) +{ + // Spacing + std::cout << std::endl; + + { + nano::object_stream obs{ std::cout }; + obs.write ("field_name", "field_value"); + + std::cout << std::endl; + } + + { + nano::object_stream obs{ std::cout }; + obs.write ("bool_field", true); + obs.write ("bool_field", false); + + std::cout << std::endl; + } + + { + nano::object_stream obs{ std::cout }; + obs.write ("int_field", 1234); + obs.write ("int_field", -1234); + obs.write ("int_field", std::numeric_limits::max ()); + obs.write ("int_field", std::numeric_limits::min ()); + + std::cout << std::endl; + } + + { + nano::object_stream obs{ std::cout }; + obs.write ("uint64_field", (uint64_t)1234); + obs.write ("uint64_field", (uint64_t)-1234); + obs.write ("uint64_field", std::numeric_limits::max ()); + obs.write ("uint64_field", std::numeric_limits::min ()); + + std::cout << std::endl; + } + + { + nano::object_stream obs{ std::cout }; + obs.write ("float_field", 1234.5678f); + obs.write ("float_field", -1234.5678f); + obs.write ("float_field", std::numeric_limits::max ()); + obs.write ("float_field", std::numeric_limits::min ()); + obs.write ("float_field", std::numeric_limits::lowest ()); + + std::cout << std::endl; + } + + { + nano::object_stream obs{ std::cout }; + obs.write ("double_field", 1234.5678f); + obs.write ("double_field", -1234.5678f); + obs.write ("double_field", std::numeric_limits::max ()); + obs.write ("double_field", std::numeric_limits::min ()); + obs.write ("double_field", std::numeric_limits::lowest ()); + + std::cout << std::endl; + } + + // Spacing + std::cout << std::endl; +} + +TEST (object_stream, object_writer_basic) +{ + // Spacing + std::cout << std::endl; + + { + nano::object_stream obs{ std::cout }; + obs.write ("object_field", [] (nano::object_stream & obs) { + obs.write ("field1", "value1"); + obs.write ("field2", "value2"); + obs.write ("field3", true); + obs.write ("field4", 1234); + }); + + std::cout << std::endl; + } + + // Spacing + std::cout << std::endl; +} + +TEST (object_stream, object_writer_nested) +{ + // Spacing + std::cout << std::endl; + + { + nano::object_stream obs{ std::cout }; + obs.write ("object_field", [] (nano::object_stream & obs) { + obs.write ("field1", "value1"); + + obs.write ("nested_object", [] (nano::object_stream & obs) { + obs.write ("nested_field1", "nested_value1"); + obs.write ("nested_field2", false); + obs.write ("nested_field3", -1234); + }); + + obs.write ("field2", "value2"); + obs.write ("field3", true); + obs.write ("field4", 1234); + }); + + std::cout << std::endl; + } + + // Spacing + std::cout << std::endl; +} + +namespace +{ +class test_class_basic +{ +public: + nano::uint256_union uint256_union_field{ 0 }; + nano::block_hash block_hash{ 0 }; + + void operator() (nano::object_stream & obs) const + { + obs.write ("uint256_union_field", uint256_union_field); + obs.write ("block_hash", block_hash); + } +}; +} + +TEST (object_stream, object_basic) +{ + // Spacing + std::cout << std::endl; + + { + nano::object_stream obs{ std::cout }; + + test_class_basic test_object{}; + obs.write ("test_object", test_object); + + std::cout << std::endl; + } + + // Spacing + std::cout << std::endl; +} + +namespace +{ +class test_class_nested +{ +public: + nano::uint256_union uint256_union_field{ 0 }; + nano::block_hash block_hash{ 0 }; + + test_class_basic nested_object; + + void operator() (nano::object_stream & obs) const + { + obs.write ("uint256_union_field", uint256_union_field); + obs.write ("block_hash", block_hash); + obs.write ("nested_object", nested_object); + } +}; +} + +TEST (object_stream, object_nested) +{ + // Spacing + std::cout << std::endl; + + { + nano::object_stream obs{ std::cout }; + + test_class_nested test_object{}; + obs.write ("test_object", test_object); + + std::cout << std::endl; + } + + // Spacing + std::cout << std::endl; +} + +TEST (object_stream, array_writer_basic) +{ + // Spacing + std::cout << std::endl; + + { + nano::object_stream obs{ std::cout }; + obs.write ("array_field", [] (nano::array_stream & ars) { + for (int n = 0; n < 10; ++n) + { + ars.write (n); + } + }); + + std::cout << std::endl; + } + + // Spacing + std::cout << std::endl; +} + +TEST (object_stream, array_writer_objects) +{ + // Spacing + std::cout << std::endl; + + { + nano::object_stream obs{ std::cout }; + obs.write ("array_field", [] (nano::array_stream & ars) { + for (int n = 0; n < 3; ++n) + { + test_class_basic test_object{}; + ars.write (test_object); + } + }); + + std::cout << std::endl; + } + + // Spacing + std::cout << std::endl; +} + +TEST (object_stream, vote) +{ + // Spacing + std::cout << std::endl; + + { + nano::object_stream obs{ std::cout }; + + nano::vote vote{}; + vote.hashes.push_back (nano::test::random_hash ()); + vote.hashes.push_back (nano::test::random_hash ()); + vote.hashes.push_back (nano::test::random_hash ()); + + obs.write ("vote", vote); + } + + // Spacing + std::cout << std::endl; +} + +TEST (object_stream, string_view) +{ + // Spacing + std::cout << std::endl; + + nano::object_stream obs{ std::cout }; + + nano::networks network{ nano::networks::nano_live_network }; + obs.write ("network", nano::to_string (network)); + + // Spacing + std::cout << std::endl; +} + +TEST (object_stream, ostream_adapter) +{ + using namespace nano; + + // Spacing + std::cout << std::endl; + + nano::vote vote{}; + vote.hashes.push_back (nano::test::random_hash ()); + vote.hashes.push_back (nano::test::random_hash ()); + vote.hashes.push_back (nano::test::random_hash ()); + + std::cout << "vote: " << vote << std::endl; + + // Spacing + std::cout << std::endl; +} \ No newline at end of file diff --git a/nano/lib/CMakeLists.txt b/nano/lib/CMakeLists.txt index 3253fa0369..e290cd765d 100644 --- a/nano/lib/CMakeLists.txt +++ b/nano/lib/CMakeLists.txt @@ -58,7 +58,9 @@ add_library( memory.cpp numbers.hpp numbers.cpp - object_stream.hpp + object_stream.hpp + object_stream_adapters.hpp + object_stream_writers.hpp observer_set.hpp optional_ptr.hpp processing_queue.hpp diff --git a/nano/lib/object_stream.hpp b/nano/lib/object_stream.hpp index a7554657d0..0cda51209d 100644 --- a/nano/lib/object_stream.hpp +++ b/nano/lib/object_stream.hpp @@ -1,7 +1,10 @@ #pragma once +#include + +#include + #include -#include #include #include #include @@ -13,30 +16,6 @@ namespace nano { -struct object_stream_config -{ - std::string_view field_begin{ "" }; - std::string_view field_end{ "" }; - std::string_view field_assignment{ ": " }; - std::string_view field_separator{ ", " }; - - std::string_view object_begin{ "{ " }; - std::string_view object_end{ " }" }; - - std::string_view array_begin{ "[ " }; - std::string_view array_end{ " ]" }; - - std::string_view array_element_begin{ "" }; - std::string_view array_element_end{ "" }; - std::string_view array_element_separator{ ", " }; - - std::string_view string_begin{ "\"" }; - std::string_view string_end{ "\"" }; - - /** Number of decimal places to show for `float` and `double` */ - int precision{ 2 }; -}; - class object_stream; class array_stream; @@ -47,140 +26,202 @@ class array_stream; template concept object_streamable = requires (T const & obj, object_stream & obs) { { - obj (obs) + stream_as (obj, obs) }; }; template concept array_streamable = requires (T const & obj, array_stream & ars) { { - obj (ars) + stream_as (obj, ars) }; }; class object_stream_base { - static constexpr object_stream_config DEFAULT_CONFIG = {}; - public: - explicit object_stream_base (std::ostream & stream_a, object_stream_config const & config_a = DEFAULT_CONFIG) : - stream{ stream_a }, - config{ config_a } + explicit object_stream_base (object_stream_context & ctx) : + ctx{ ctx } { } -protected: - std::ostream & stream; - const object_stream_config & config; - -protected: // Writing - template - void write_impl (Value const & value); - - template - void write_impl (Value const & value); - - template - void write_impl (Value const & value); - - template - void write_impl (Range const & container); - -protected: // Writing special cases - inline void write_impl (bool const & value); - inline void write_impl (int8_t const & value); - inline void write_impl (uint8_t const & value); - inline void write_impl (int16_t const & value); - inline void write_impl (uint16_t const & value); - inline void write_impl (int32_t const & value); - inline void write_impl (uint32_t const & value); - inline void write_impl (int64_t const & value); - inline void write_impl (uint64_t const & value); - inline void write_impl (float const & value); - inline void write_impl (double const & value); - - inline void write_impl (std::string const & value); - inline void write_impl (std::string_view const & value); - inline void write_impl (const char * value); - - template - inline void write_impl (std::shared_ptr const & value); - template - inline void write_impl (std::unique_ptr const & value); - template - inline void write_impl (std::weak_ptr const & value); - template - inline void write_impl (std::optional const & value); - -private: - template - inline void write_optional (Opt const & opt); - - template - inline void write_string (Str const & str); + explicit object_stream_base (std::ostream & os, object_stream_config const & config = object_stream_config::default_config ()) : + ctx{ os, config } + { + } protected: - inline void begin_field (std::string_view name, bool first); - inline void end_field (); - - inline void begin_object (); - inline void end_object (); - - inline void begin_array (); - inline void end_array (); - - inline void begin_array_element (bool first); - inline void end_array_element (); - - inline void begin_string (); - inline void end_string (); + object_stream_context ctx; }; +/** + * Used to serialize an object. + * Outputs: `field1: value1, field2: value2, ...` (without enclosing `{}`) + */ class object_stream : private object_stream_base { public: - // Inherit constructor + // Inherit default constructors using object_stream_base::object_stream_base; - object_stream (object_stream const &) = delete; + object_stream (object_stream const &) = delete; // Disallow copying public: template - void write (std::string_view name, Value const & value); + void write (std::string_view name, Value const & value) + { + ctx.begin_field (name, std::exchange (first_field, false)); + stream_as (value, ctx); + ctx.end_field (); + } + + // Handle `.write ("name", container, [] (auto const & entry) { ... })` + template + requires (std::is_invocable_v) + void write (std::string_view name, Container const & container, Transform transform) + { + write (name, std::views::transform (container, transform)); + } + + // Handle `.write ("name", container, [] (auto const & entry, nano::object_stream & obs) { ... })` + template + requires (std::is_invocable_v) + void write (std::string_view name, Container const & container, Writer writer) + { + write (name, container, [&writer] (auto const & el) { + return [&writer, &el] (object_stream & obs) { + writer (el, obs); + }; + }); + } + + // Handle `.write ("name", container, [] (auto const & entry, nano::array_stream & obs) { ... })` + template + requires (std::is_invocable_v) + void write (std::string_view name, Container const & container, Writer writer) + { + write (name, container, [&writer] (auto const & el) { + return [&writer, &el] (array_stream & obs) { + writer (el, obs); + }; + }); + } private: bool first_field{ true }; }; +/** + * Used to serialize an array of objects. + * Outputs: `[value1, value2, ...]` + */ class array_stream : private object_stream_base { public: - // Inherit constructor + // Inherit default constructors using object_stream_base::object_stream_base; - array_stream (array_stream const &) = delete; + array_stream (array_stream const &) = delete; // Disallow copying public: template - void write (Value const & value); + void write (Value const & value) + { + ctx.begin_array_element (std::exchange (first_element, false)); + stream_as (value, ctx); + ctx.end_array_element (); + } + + // Handle `.write (container, [] (auto const & entry) { ... })` + template + requires (std::is_invocable_v) + void write (Container const & container, Transform transform) + { + write (std::views::transform (container, transform)); + } + + // Handle `.write (container, [] (auto const & entry, nano::object_stream & obs) { ... })` + template + requires (std::is_invocable_v) + void write (Container const & container, Writer writer) + { + write (container, [&writer] (auto const & el) { + return [&writer, &el] (object_stream & obs) { + writer (el, obs); + }; + }); + } + + // Handle `.write (container, [] (auto const & entry, nano::array_stream & obs) { ... })` + template + requires (std::is_invocable_v) + void write (Container const & container, Writer writer) + { + write (container, [&writer] (auto const & el) { + return [&writer, &el] (array_stream & obs) { + writer (el, obs); + }; + }); + } private: bool first_element{ true }; }; +/** + * Used for human readable object serialization. Should be used to serialize a single object. + * Includes the type of the value before writing the value itself. + * Outputs: `type_name{ field1: value1, field2: value2, ... }` + */ class root_object_stream : private object_stream_base { public: - // Inherit constructor + // Inherit default constructors using object_stream_base::object_stream_base; public: template - void write (Value const & value); + void write (Value const & value) + { + ctx.os << boost::typeindex::type_id ().pretty_name (); + stream_as (value, ctx); + } + + // Handle `.write (container, [] (auto const & entry) { ... })` + template + requires (std::is_invocable_v) + void write (Container const & container, Transform transform) + { + write (std::views::transform (container, transform)); + } + + // Handle `.write (container, [] (auto const & entry, nano::object_stream & obs) { ... })` + template + requires (std::is_invocable_v) + void write (Container const & container, Writer writer) + { + write (container, [&writer] (auto const & el) { + return [&writer, &el] (object_stream & obs) { + writer (el, obs); + }; + }); + } + + // Handle `.write (container, [] (auto const & entry, nano::array_stream & obs) { ... })` + template + requires (std::is_invocable_v) + void write (Container const & container, Writer writer) + { + write (container, [&writer] (auto const & el) { + return [&writer, &el] (array_stream & obs) { + writer (el, obs); + }; + }); + } }; /** - * Wraps `Args &&... args` and provides a `<< (std::ostream &, ...)` operator that writes the arguments to the stream in a lazy manner. + * Wraps {name,value} args and provides a `<< (std::ostream &, ...)` operator that writes the arguments to the stream in a lazy manner. */ template struct object_stream_formatter @@ -194,305 +235,102 @@ struct object_stream_formatter friend std::ostream & operator<< (std::ostream & os, object_stream_formatter const & self) { - object_stream obs{ os }; + nano::object_stream_context ctx{ os }; + nano::object_stream obs{ ctx }; std::apply ([&obs] (auto &&... args) { ((obs.write (args.name, args.value)), ...); }, self.args); return os; } -}; -// Needed for fmt formatting, uses the ostream operator under the hood -template -auto format_as (object_stream_formatter const & val) -{ - return fmt::streamed (val); -} + // Needed for fmt formatting, uses the ostream operator under the hood + friend auto format_as (object_stream_formatter const & val) + { + return fmt::streamed (val); + } +}; /* - * implementation + * Writers */ template -void object_stream_base::write_impl (Value const & value) +inline void stream_as (Value const & value, object_stream_context & ctx) { using magic_enum::ostream_operators::operator<<; // Support ostream operator for all enums - begin_string (); + ctx.begin_string (); - stream << value; + // Write using type specific ostream operator + ctx.os << value; - end_string (); + ctx.end_string (); } template -void object_stream_base::write_impl (Value const & value) +inline void stream_as (Value const & value, object_stream_context & ctx) { - begin_object (); + ctx.begin_object (); - object_stream obs{ stream, config }; - value (obs); + // Write as object + nano::object_stream obs{ ctx }; + stream_as (value, obs); - end_object (); + ctx.end_object (); } template -void object_stream_base::write_impl (Value const & value) +inline void stream_as (Value const & value, object_stream_context & ctx) { - begin_array (); + ctx.begin_array (); - array_stream ars{ stream, config }; - value (ars); + // Write as array + nano::array_stream ars{ ctx }; + stream_as (value, ars); - end_array (); + ctx.end_array (); } template -void object_stream_base::write_impl (Range const & container) +inline void stream_as (Range const & container, object_stream_context & ctx) { - write_impl ([&container] (array_stream & ars) { + stream_as ([&container] (nano::array_stream & ars) { for (auto const & el : container) { ars.write (el); } - }); -} - -void object_stream_base::write_impl (bool const & value) -{ - stream << (value ? "true" : "false"); -} - -void object_stream_base::write_impl (const int8_t & value) -{ - stream << static_cast (value); // Avoid printing as char -} - -void object_stream_base::write_impl (const uint8_t & value) -{ - stream << static_cast (value); // Avoid printing as char -} - -void object_stream_base::write_impl (const int16_t & value) -{ - stream << value; -} - -void object_stream_base::write_impl (const uint16_t & value) -{ - stream << value; -} - -void object_stream_base::write_impl (const int32_t & value) -{ - stream << value; -} - -void object_stream_base::write_impl (const uint32_t & value) -{ - stream << value; -} - -void object_stream_base::write_impl (const int64_t & value) -{ - stream << value; -} - -void object_stream_base::write_impl (const uint64_t & value) -{ - stream << value; -} - -void object_stream_base::write_impl (const float & value) -{ - stream << std::fixed << std::setprecision (config.precision) << value; -} - -void object_stream_base::write_impl (const double & value) -{ - stream << std::fixed << std::setprecision (config.precision) << value; -} - -template -void object_stream_base::write_impl (std::shared_ptr const & value) -{ - write_optional (value); -} - -template -void object_stream_base::write_impl (std::unique_ptr const & value) -{ - write_optional (value); -} - -template -void object_stream_base::write_impl (std::weak_ptr const & value) -{ - write_optional (value.lock ()); -} - -template -void object_stream_base::write_impl (std::optional const & value) -{ - write_optional (value); -} - -template -void object_stream_base::write_optional (const Opt & opt) -{ - if (opt) - { - write_impl (*opt); - } - else - { - stream << "null"; - } -} - -inline void object_stream_base::write_impl (std::string const & value) -{ - write_string (value); -} - -inline void object_stream_base::write_impl (std::string_view const & value) -{ - write_string (value); -} - -inline void object_stream_base::write_impl (const char * value) -{ - write_string (value); -} - -template -void object_stream_base::write_string (const Str & str) -{ - begin_string (); - stream << str; - end_string (); + }, + ctx); } /* - * object_stream_base + * Adapters for types implementing convenience `obj(object_stream &)` & `obj(array_stream &)` functions */ -void object_stream_base::begin_field (std::string_view name, bool first) -{ - if (!first) +template +concept simple_object_streamable = requires (T const & obj, object_stream & obs) { { - stream << config.field_separator; - } - stream << config.field_begin << name << config.field_assignment; -} - -void object_stream_base::end_field () -{ - stream << config.field_end; -} - -void object_stream_base::begin_object () -{ - stream << config.object_begin; -} - -void object_stream_base::end_object () -{ - stream << config.object_end; -} - -void object_stream_base::begin_array () -{ - stream << config.array_begin; -} - -void object_stream_base::end_array () -{ - stream << config.array_end; -} + obj (obs) + }; +}; -void object_stream_base::begin_array_element (bool first) -{ - if (!first) +template +concept simple_array_streamable = requires (T const & obj, array_stream & ars) { { - stream << config.array_element_separator; - } - stream << config.array_element_begin; -} - -void object_stream_base::end_array_element () -{ - stream << config.array_element_end; -} - -void object_stream_base::begin_string () -{ - stream << config.string_begin; -} - -void object_stream_base::end_string () -{ - stream << config.string_end; -} - -/* - * object_stream - */ - -template -void object_stream::write (std::string_view name, Value const & value) -{ - begin_field (name, std::exchange (first_field, false)); - - write_impl (value); - - end_field (); -} - -/* - * array_stream - */ - -template -void array_stream::write (Value const & value) -{ - begin_array_element (std::exchange (first_element, false)); - - write_impl (value); - - end_array_element (); -} - -/* - * root_object_stream - */ - -template -void root_object_stream::write (Value const & value) -{ - write_impl (value); -} -} + obj (ars) + }; +}; -/* - * Adapters that allow for printing using '<<' operator for all classes that implement object streaming - */ -namespace nano -{ -template -std::ostream & operator<< (std::ostream & os, Value const & value) +template +inline void stream_as (Value const & value, object_stream & obs) { - nano::root_object_stream obs{ os }; - obs.write (value); - return os; + value (obs); } -template -std::ostream & operator<< (std::ostream & os, Value const & value) +template +inline void stream_as (Value const & value, array_stream & ars) { - nano::root_object_stream obs{ os }; - obs.write (value); - return os; + value (ars); } } \ No newline at end of file diff --git a/nano/lib/object_stream_adapters.hpp b/nano/lib/object_stream_adapters.hpp new file mode 100644 index 0000000000..f291865172 --- /dev/null +++ b/nano/lib/object_stream_adapters.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include + +/* + * Adapters that allow for printing using '<<' operator for all classes that implement object streaming + */ +namespace nano +{ +template +std::ostream & operator<< (std::ostream & os, Value const & value) +{ + nano::object_stream_context ctx{ os }; + nano::root_object_stream obs{ ctx }; + obs.write (value); + return os; +} + +template +std::ostream & operator<< (std::ostream & os, Value const & value) +{ + nano::object_stream_context ctx{ os }; + nano::root_object_stream obs{ ctx }; + obs.write (value); + return os; +} +} \ No newline at end of file diff --git a/nano/lib/object_stream_writers.hpp b/nano/lib/object_stream_writers.hpp new file mode 100644 index 0000000000..002cfebbee --- /dev/null +++ b/nano/lib/object_stream_writers.hpp @@ -0,0 +1,226 @@ +#pragma once + +#include +#include + +namespace nano +{ +struct object_stream_config +{ + std::string field_begin{ "" }; + std::string field_end{ "" }; + std::string field_assignment{ ": " }; + std::string field_separator{ ", " }; + + std::string object_begin{ "{ " }; + std::string object_end{ " }" }; + + std::string array_begin{ "[ " }; + std::string array_end{ " ]" }; + + std::string array_element_begin{ "" }; + std::string array_element_end{ "" }; + std::string array_element_separator{ ", " }; + + std::string string_begin{ "\"" }; + std::string string_end{ "\"" }; + + std::string true_value{ "true" }; + std::string false_value{ "false" }; + std::string null_value{ "null" }; + + /** Number of decimal places to show for `float` and `double` */ + int precision{ 2 }; + + static object_stream_config const & default_config () + { + static object_stream_config const config{}; + return config; + } +}; + +struct object_stream_context +{ + object_stream_config const & config; + std::ostream & os; + + explicit object_stream_context (std::ostream & os, object_stream_config const & config = object_stream_config::default_config ()) : + os{ os }, + config{ config } + { + } + + void begin_field (std::string_view name, bool first) + { + if (!first) + { + os << config.field_separator; + } + os << config.field_begin << name << config.field_assignment; + } + + void end_field () + { + os << config.field_end; + } + + void begin_object () + { + os << config.object_begin; + } + + void end_object () + { + os << config.object_end; + } + + void begin_array () + { + os << config.array_begin; + } + + void end_array () + { + os << config.array_end; + } + + void begin_array_element (bool first) + { + if (!first) + { + os << config.array_element_separator; + } + os << config.array_element_begin; + } + + void end_array_element () + { + os << config.array_element_end; + } + + void begin_string () + { + os << config.string_begin; + } + + void end_string () + { + os << config.string_end; + } +}; + +inline void stream_as (bool const & value, object_stream_context & ctx) +{ + ctx.os << (value ? ctx.config.true_value : ctx.config.false_value); +} + +inline void stream_as (const int8_t & value, object_stream_context & ctx) +{ + ctx.os << static_cast (value); // Avoid printing as char +} + +inline void stream_as (const uint8_t & value, object_stream_context & ctx) +{ + ctx.os << static_cast (value); // Avoid printing as char +} + +inline void stream_as (const int16_t & value, object_stream_context & ctx) +{ + ctx.os << value; +} + +inline void stream_as (const uint16_t & value, object_stream_context & ctx) +{ + ctx.os << value; +} + +inline void stream_as (const int32_t & value, object_stream_context & ctx) +{ + ctx.os << value; +} + +inline void stream_as (const uint32_t & value, object_stream_context & ctx) +{ + ctx.os << value; +} + +inline void stream_as (const int64_t & value, object_stream_context & ctx) +{ + ctx.os << value; +} + +inline void stream_as (const uint64_t & value, object_stream_context & ctx) +{ + ctx.os << value; +} + +inline void stream_as (const float & value, object_stream_context & ctx) +{ + ctx.os << std::fixed << std::setprecision (ctx.config.precision) << value; +} + +inline void stream_as (const double & value, object_stream_context & ctx) +{ + ctx.os << std::fixed << std::setprecision (ctx.config.precision) << value; +} + +template +inline void stream_as_optional (const Opt & opt, object_stream_context & ctx) +{ + if (opt) + { + stream_as (*opt, ctx); + } + else + { + ctx.os << ctx.config.null_value; + } +} + +template +inline void stream_as (std::shared_ptr const & value, object_stream_context & ctx) +{ + stream_as_optional (value, ctx); +} + +template +inline void stream_as (std::unique_ptr const & value, object_stream_context & ctx) +{ + stream_as_optional (value, ctx); +} + +template +inline void stream_as (std::weak_ptr const & value, object_stream_context & ctx) +{ + stream_as_optional (value.lock (), ctx); +} + +template +inline void stream_as (std::optional const & value, object_stream_context & ctx) +{ + stream_as_optional (value, ctx); +} + +template +inline void stream_as_string (const Str & str, object_stream_context & ctx) +{ + ctx.begin_string (); + ctx.os << str; + ctx.end_string (); +} + +inline void stream_as (std::string const & value, object_stream_context & ctx) +{ + stream_as_string (value, ctx); +} + +inline void stream_as (std::string_view const & value, object_stream_context & ctx) +{ + stream_as_string (value, ctx); +} + +inline void stream_as (const char * value, object_stream_context & ctx) +{ + stream_as_string (value, ctx); +} +} \ No newline at end of file diff --git a/nano/node/election.cpp b/nano/node/election.cpp index 87e0956346..4d57ea2643 100644 --- a/nano/node/election.cpp +++ b/nano/node/election.cpp @@ -761,28 +761,24 @@ void nano::election::operator() (nano::object_stream & obs) const obs.write ("tally_amount", status.tally.to_string_dec ()); obs.write ("final_tally_amount", status.final_tally.to_string_dec ()); - obs.write ("blocks", std::views::transform (last_blocks, [] (auto const & entry) { + obs.write ("blocks", last_blocks, [] (auto const & entry) { auto [hash, block] = entry; return block; - })); - - obs.write ("votes", std::views::transform (last_votes, [] (auto const & entry) { - return [&entry] (nano::object_stream & obs) { - auto & [account, info] = entry; - obs.write ("account", account.to_account ()); - obs.write ("time", info.time.time_since_epoch ().count ()); - obs.write ("timestamp", info.timestamp); - obs.write ("hash", info.hash.to_string ()); - }; - })); + }); + + obs.write ("votes", last_votes, [] (auto const & entry, nano::object_stream & obs) { + auto & [account, info] = entry; + obs.write ("account", account.to_account ()); + obs.write ("time", info.time.time_since_epoch ().count ()); + obs.write ("timestamp", info.timestamp); + obs.write ("hash", info.hash.to_string ()); + }); auto tally = tally_impl (); - obs.write ("tally", std::views::transform (tally, [] (auto const & entry) { - return [&entry] (nano::object_stream & obs) { - auto & [amount, block] = entry; - obs.write ("amount", amount); - obs.write ("hash", block->hash ().to_string ()); - }; - })); + obs.write ("tally", tally, [] (auto const & entry, nano::object_stream & obs) { + auto & [amount, block] = entry; + obs.write ("amount", amount); + obs.write ("hash", block->hash ().to_string ()); + }); }