From 78dd28313c481cb91807d3db7021c7c7987ecea4 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Tue, 25 Oct 2022 20:26:39 +0100 Subject: [PATCH 01/21] Ensure disabled MacOS build --- .github/workflows/cmake.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 09d4668a..f0bc421f 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -36,6 +36,7 @@ jobs: os: windows-latest, compiler: { type: VISUAL, version: 16, cc: "cl", cxx: "cl", std: 20 }, } +<<<<<<< Updated upstream - { name: "MacOS Apple Clang 14", os: macos-12, @@ -50,6 +51,22 @@ jobs: }, lib: "libc++", } +======= +# - { +# name: "MacOS Apple Clang 14", # https://github.com/actions/runner-images/issues/6225 +# os: macos-latest, +# compiler: +# { +# type: APPLE_CLANG, +# version: "14.0", +# conan: "apple-clang", +# cc: "clang", +# cxx: "clang++", +# std: 20 +# }, +# lib: "libc++", +# } +>>>>>>> Stashed changes steps: - uses: actions/checkout@v2 # - uses: lhotari/action-upterm@v1 From 2020f157dc8dfbca9ba6d57b5306900020f44a72 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Tue, 25 Oct 2022 20:28:50 +0100 Subject: [PATCH 02/21] Functional wrappers for serilisation --- libraries/core/core/CMakeLists.txt | 11 ++++-- .../core/serialisation/adapters/std/pair.hpp | 9 +++-- .../serialisation/adapters/std/ranges.hpp | 38 +++++++++++++++++++ .../core/serialisation/adapters/std/tuple.hpp | 7 ++-- .../serialisation/adapters/std/variant.hpp | 25 ++++++------ .../core/serialisation/read_serialiser.hpp | 21 ++++++++++ .../serialisation/read_serialiser_decl.hpp | 25 ++++++++++++ .../core/serialisation/write_serialiser.hpp | 30 +++++++++++++-- .../serialisation/write_serialiser_decl.hpp | 23 ++++++++--- 9 files changed, 157 insertions(+), 32 deletions(-) create mode 100644 libraries/core/core/serialisation/adapters/std/ranges.hpp diff --git a/libraries/core/core/CMakeLists.txt b/libraries/core/core/CMakeLists.txt index 3f410187..7eb94ed8 100644 --- a/libraries/core/core/CMakeLists.txt +++ b/libraries/core/core/CMakeLists.txt @@ -37,6 +37,7 @@ add_subdirectory(conformance) add_subdirectory(concurrency) add_subdirectory(gfx) add_subdirectory(functional) +add_subdirectory(memory) add_subdirectory(meta) add_subdirectory(serialisation) @@ -49,14 +50,18 @@ target_include_directories(MorpheusCoreTests ${CMAKE_CURRENT_LIST_DIR}/.. ) -#target_compile_definitions(MorpheusCore -# PUBLIC +target_compile_definitions(MorpheusCore + PUBLIC # MORPHEUS_SHARED_BUILD=1 # MORPHEUS_DLL_EXPORTS=1 -#) +# HAS_ITERATOR_DEBUGGING=0 +# _ITERATOR_DEBUG_LEVEL=0 +) target_compile_options(MorpheusCore PRIVATE +# $<$:/fsanitize=address> +# $<$:-fsanitize=address> # -enable-hosted-libstdcxx $<$:/wd4251> # class 'foo' needs to have dll-interface to be used by clients of class 'bar' ) diff --git a/libraries/core/core/serialisation/adapters/std/pair.hpp b/libraries/core/core/serialisation/adapters/std/pair.hpp index 7d415727..d55adfe8 100644 --- a/libraries/core/core/serialisation/adapters/std/pair.hpp +++ b/libraries/core/core/serialisation/adapters/std/pair.hpp @@ -17,10 +17,11 @@ concept IsStdPair = meta::IsSpecialisationOf; template void serialise(Serialiser& serialiser, std::pair const& value) { - serialiser.writer().beginSequence(std::tuple_size>::value); - serialiser.serialise(value.first); - serialiser.serialise(value.second); - serialiser.writer().endSequence(); + serialiser.serialise(std::tuple_size>::value, [&]() + { + serialiser.serialise(value.first); + serialiser.serialise(value.second); + }); } template diff --git a/libraries/core/core/serialisation/adapters/std/ranges.hpp b/libraries/core/core/serialisation/adapters/std/ranges.hpp new file mode 100644 index 00000000..62d58bab --- /dev/null +++ b/libraries/core/core/serialisation/adapters/std/ranges.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "core/conformance/ranges.hpp" +#include "core/serialisation/concepts/read_serialiser.hpp" +#include "core/serialisation/concepts/read_serialisable.hpp" +#include "core/serialisation/concepts/write_serialiser.hpp" +#include "core/serialisation/concepts/write_serialisable.hpp" + +namespace morpheus::serialisation::detail +{ + +//template +//concept IsRange = meta::IsSpecialisationOf; + +template +void serialise(Serialiser& serialiser, auto const& range) +{ + serialiser.serialise(ranges::size(range), [&]() + { + ranges::for_each(range, [&serialiser](auto const& element) { serialiser.serialise(element); }); + }); +} + +template +T deserialise(Serialiser& serialiser) +{ + constexpr std::size_t size = std::tuple_size::value; + + auto const scope = makeScopedSequence(serialiser.reader(), std::tuple_size::value); + return[&serialiser](std::index_sequence ) + { + // More work required to support std::tuples containing references. + static_assert((!std::is_reference_v> || ...)); + return T{ serialiser.template deserialise>()... }; + }(std::make_index_sequence()); +} + +} // morpheus::serialisation \ No newline at end of file diff --git a/libraries/core/core/serialisation/adapters/std/tuple.hpp b/libraries/core/core/serialisation/adapters/std/tuple.hpp index dbc8ce43..84ec6801 100644 --- a/libraries/core/core/serialisation/adapters/std/tuple.hpp +++ b/libraries/core/core/serialisation/adapters/std/tuple.hpp @@ -16,9 +16,10 @@ concept IsStdTuple = meta::IsSpecialisationOf; template void serialise(Serialiser& serialiser, std::tuple const& value) { - serialiser.writer().beginSequence(std::tuple_size>::value); - std::apply([&serialiser](auto const&... ts) { (serialiser.serialise(ts), ...); }, value); - serialiser.writer().endSequence(); + serialiser.serialise(std::tuple_size>::value, [&]() + { + std::apply([&serialiser](auto const&... ts) { (serialiser.serialise(ts), ...); }, value); + }); } template diff --git a/libraries/core/core/serialisation/adapters/std/variant.hpp b/libraries/core/core/serialisation/adapters/std/variant.hpp index 0089e913..97ff3cd7 100644 --- a/libraries/core/core/serialisation/adapters/std/variant.hpp +++ b/libraries/core/core/serialisation/adapters/std/variant.hpp @@ -45,23 +45,24 @@ struct TypeListNames> template void serialise(Serialiser& serialiser, std::variant const& value) { - serialiser.writer().beginComposite(); - if (value.valueless_by_exception()) [[unlikely]] + serialiser.serialise([&]() { - serialiser.serialise("index", static_cast(std::variant_npos)); - } - else - { - if (serialiser.writer().isTextual()) + if (value.valueless_by_exception()) [[unlikely]] { - serialiser.serialise("type", TypeListNames>::name(value.index())); + serialiser.serialise("index", static_cast(std::variant_npos)); } else - serialiser.serialise("index", static_cast(value.index())); + { + if (serialiser.writer().isTextual()) + { + serialiser.serialise("type", TypeListNames>::name(value.index())); + } + else + serialiser.serialise("index", static_cast(value.index())); - std::visit([&serialiser](auto const& value) { return serialiser.serialise("value", value); }, value); - } - serialiser.writer().endComposite(); + std::visit([&serialiser](auto const& value) { return serialiser.serialise("value", value); }, value); + } + }); } template diff --git a/libraries/core/core/serialisation/read_serialiser.hpp b/libraries/core/core/serialisation/read_serialiser.hpp index 9a1b9c56..640309e8 100644 --- a/libraries/core/core/serialisation/read_serialiser.hpp +++ b/libraries/core/core/serialisation/read_serialiser.hpp @@ -27,5 +27,26 @@ template return serialisation::deserialise.template operator(), T>(*this); } +template +template +[[nodiscard]] T ReadSerialiser::deserialise(std::size_t size, std::invocable auto f) +{ + auto const sequence = makeScopedSequence(*this, size); + +} + +template +template +[[nodiscard]] T ReadSerialiser::deserialise(std::invocable auto f) +{ + +} + +template +template +[[nodiscard]] T ReadSerialiser::deserialise(bool const null, std::invocable auto f) +{ + +} } \ No newline at end of file diff --git a/libraries/core/core/serialisation/read_serialiser_decl.hpp b/libraries/core/core/serialisation/read_serialiser_decl.hpp index d5333494..2e618d2c 100644 --- a/libraries/core/core/serialisation/read_serialiser_decl.hpp +++ b/libraries/core/core/serialisation/read_serialiser_decl.hpp @@ -46,8 +46,13 @@ class ReadSerialiser : mReader(std::forward(args)...) {} +#if (__cpp_explicit_this_parameter >= 202110) + template + [[nodiscard]] auto& reader(this Self&& self) noexcept { return self.mReader; } +#else [[nodiscard]] ReaderType& reader() noexcept { return mReader; } [[nodiscard]] ReaderType const& reader() const noexcept { return mReader; } +#endif // (__cpp_explicit_this_parameter >= 202110) /// \name Deserialise /// Custom deserialise function specialisations should deserialise sub-members via the readers deserialisers @@ -68,6 +73,26 @@ class ReadSerialiser /// \return The deserialises value. template [[nodiscard]] T deserialise(std::string_view const key); + + /// Deserialise a sequence of values + /// \tparam T The underlying type of sequence to deserialise. + /// \param[in] size The number of entries in the sequence to serialise. + /// \param[in] f The command deserialising the sequence of values. + template + [[nodiscard]] T deserialise(std::size_t size, std::invocable auto f); + + /// Deserialise a related set of values in a composite. + /// \tparam T The underlying type of composite to deserialise. + /// \param[in] f The command deserialising the composite values. + template + [[nodiscard]] T deserialise(std::invocable auto f); + + /// Deserialise a nullable value + /// \tparam T The underlying type of nullable to deserialise. + /// \param[in] null If the nullable value is null or set. + /// \param[in] f The command deserialising the nullable values. + template + [[nodiscard]] T deserialise(bool const null, std::invocable auto f = []{}); ///@} private: ReaderType mReader; diff --git a/libraries/core/core/serialisation/write_serialiser.hpp b/libraries/core/core/serialisation/write_serialiser.hpp index 6847cf30..e1104c3d 100644 --- a/libraries/core/core/serialisation/write_serialiser.hpp +++ b/libraries/core/core/serialisation/write_serialiser.hpp @@ -7,19 +7,41 @@ namespace morpheus::serialisation { template -template -void WriteSerialiser::serialise(T const& value) +void WriteSerialiser::serialise(auto const& value) { serialisation::serialise(*this, value); } template -template -void WriteSerialiser::serialise(std::string_view const key, T const& value) +void WriteSerialiser::serialise(std::string_view const key, auto const& value) { mWriter.beginValue(key); serialisation::serialise(*this, value); mWriter.endValue(); } +template +auto WriteSerialiser::serialise(std::size_t size, std::invocable auto f) +{ + mWriter.beginSequence(size); + f(); + mWriter.endSequence(); +} + +template +auto WriteSerialiser::serialise(std::invocable auto f) +{ + mWriter.beginComposite(); + f(); + mWriter.endComposite(); +} + +template +auto WriteSerialiser::serialise(bool const null, std::invocable auto f) +{ + mWriter.beginNullable(null); + f(); + mWriter.endNullable(); +} + } \ No newline at end of file diff --git a/libraries/core/core/serialisation/write_serialiser_decl.hpp b/libraries/core/core/serialisation/write_serialiser_decl.hpp index f4125801..a94669e3 100644 --- a/libraries/core/core/serialisation/write_serialiser_decl.hpp +++ b/libraries/core/core/serialisation/write_serialiser_decl.hpp @@ -3,6 +3,7 @@ #include "core/meta/concepts/constructible.hpp" #include "core/serialisation/concepts/writer.hpp" +#include #include #include #include @@ -40,17 +41,27 @@ class WriteSerialiser /// the correct call via ADL dispatch. ///@{ /// Serialise a single value - /// \tparam T The underlying type of value to serialise. /// \param[in] value The value to serialise. - template - void serialise(T const& value); + void serialise(auto const& value); /// Serialise a key value pair - /// \tparam T The underlying type of value to serialise. /// \param[in] key The key to serialise. /// \param[in] value The value to serialise. - template - void serialise(std::string_view const key, T const& value); + void serialise(std::string_view const key, auto const& value); + + /// Serialise a sequence of values + /// \param[in] size The number of entries in the sequence to serialise. + /// \param[in] f The command serialising the sequence of values. + auto serialise(std::size_t size, std::invocable auto f); + + /// Serialise a related set of values in a composite. + /// \param[in] f The command serialising the composite values. + auto serialise(std::invocable auto f); + + /// Serialise a nullable value + /// \param[in] null If the nullable value is null or set. + /// \param[in] f The command serialising the nullable values. + auto serialise(bool const null, std::invocable auto f = []{}); ///@} private: WriterType mWriter; From 624f6c3508c8ef1e702c9f305b4de27d71cad77a Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Tue, 25 Oct 2022 20:36:12 +0100 Subject: [PATCH 03/21] Directive log to track serialisation --- .../core/core/serialisation/CMakeLists.txt | 3 + .../serialisation/adapters/std/CMakeLists.txt | 2 + .../serialisation/adapters/std/pair.tests.cpp | 6 +- .../adapters/std/ranges.tests.cpp | 14 ++++ .../adapters/std/tuple.tests.cpp | 3 + .../adapters/std/unique_ptr.tests.cpp | 3 + .../adapters/std/variant.tests.cpp | 3 + .../core/core/serialisation/directive.hpp | 79 +++++++++++++++++++ .../core/serialisation/directive_reader.hpp | 46 +++++++++++ .../core/serialisation/directive_writer.hpp | 45 +++++++++++ 10 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 libraries/core/core/serialisation/adapters/std/ranges.tests.cpp create mode 100644 libraries/core/core/serialisation/directive.hpp create mode 100644 libraries/core/core/serialisation/directive_reader.hpp create mode 100644 libraries/core/core/serialisation/directive_writer.hpp diff --git a/libraries/core/core/serialisation/CMakeLists.txt b/libraries/core/core/serialisation/CMakeLists.txt index 0be5bcbd..8a75e9e8 100644 --- a/libraries/core/core/serialisation/CMakeLists.txt +++ b/libraries/core/core/serialisation/CMakeLists.txt @@ -18,6 +18,9 @@ target_sources(MorpheusCore target_sources(MorpheusCoreTests PRIVATE concept_checks.tests.cpp + directive.hpp + directive_reader.hpp + directive_writer.hpp json_reader.tests.cpp json_writer.tests.cpp read_serialiser.tests.cpp diff --git a/libraries/core/core/serialisation/adapters/std/CMakeLists.txt b/libraries/core/core/serialisation/adapters/std/CMakeLists.txt index 19e2ff92..c090635c 100644 --- a/libraries/core/core/serialisation/adapters/std/CMakeLists.txt +++ b/libraries/core/core/serialisation/adapters/std/CMakeLists.txt @@ -2,6 +2,7 @@ target_sources(MorpheusCore PUBLIC optional.hpp pair.hpp + ranges.hpp tuple.hpp variant.hpp ) @@ -10,6 +11,7 @@ target_sources(MorpheusCoreTests PRIVATE optional.tests.cpp pair.tests.cpp + ranges.tests.cpp tuple.tests.cpp variant.tests.cpp ) diff --git a/libraries/core/core/serialisation/adapters/std/pair.tests.cpp b/libraries/core/core/serialisation/adapters/std/pair.tests.cpp index bdb3e559..8ea7ee61 100644 --- a/libraries/core/core/serialisation/adapters/std/pair.tests.cpp +++ b/libraries/core/core/serialisation/adapters/std/pair.tests.cpp @@ -7,7 +7,11 @@ namespace morpheus::serialisation { -TEST_CASE("Verify serialisation of std::pair", "[morpheus.serialisation.pair]") +TEST_CASE("Verify serialisation of std::pair", "[morpheus.serialisation.pair.serialise]") +{ +} + +TEST_CASE("Verify deserialisation of std::pair", "[morpheus.serialisation.pair.deserialise]") { } diff --git a/libraries/core/core/serialisation/adapters/std/ranges.tests.cpp b/libraries/core/core/serialisation/adapters/std/ranges.tests.cpp new file mode 100644 index 00000000..5ea9582e --- /dev/null +++ b/libraries/core/core/serialisation/adapters/std/ranges.tests.cpp @@ -0,0 +1,14 @@ +#include "core/serialisation/adapters/std/ranges.hpp" + +#include + +#include + +namespace morpheus::serialisation +{ + +TEST_CASE("Verify serialisation of ranges", "[morpheus.serialisation.ranges]") +{ +} + +} // morpheus::serialisation \ No newline at end of file diff --git a/libraries/core/core/serialisation/adapters/std/tuple.tests.cpp b/libraries/core/core/serialisation/adapters/std/tuple.tests.cpp index 7dcb3adc..f8964283 100644 --- a/libraries/core/core/serialisation/adapters/std/tuple.tests.cpp +++ b/libraries/core/core/serialisation/adapters/std/tuple.tests.cpp @@ -1,4 +1,7 @@ #include "core/serialisation/adapters/std/tuple.hpp" +#include "core/serialisation/directive.hpp" +#include "core/serialisation/directive_reader.hpp" +#include "core/serialisation/directive_writer.hpp" #include diff --git a/libraries/core/core/serialisation/adapters/std/unique_ptr.tests.cpp b/libraries/core/core/serialisation/adapters/std/unique_ptr.tests.cpp index 8e091e0b..a4d15e4c 100644 --- a/libraries/core/core/serialisation/adapters/std/unique_ptr.tests.cpp +++ b/libraries/core/core/serialisation/adapters/std/unique_ptr.tests.cpp @@ -1,4 +1,7 @@ #include "core/serialisation/adapters/std/unique_ptr.hpp" +#include "core/serialisation/directive.hpp" +#include "core/serialisation/directive_readder.hpp" +#include "core/serialisation/directive_writer.hpp" #include diff --git a/libraries/core/core/serialisation/adapters/std/variant.tests.cpp b/libraries/core/core/serialisation/adapters/std/variant.tests.cpp index 11ef643f..5f0a098f 100644 --- a/libraries/core/core/serialisation/adapters/std/variant.tests.cpp +++ b/libraries/core/core/serialisation/adapters/std/variant.tests.cpp @@ -1,4 +1,7 @@ #include "core/serialisation/adapters/std/variant.hpp" +#include "core/serialisation/directive.hpp" +#include "core/serialisation/directive_readder.hpp" +#include "core/serialisation/directive_writer.hpp" #include diff --git a/libraries/core/core/serialisation/directive.hpp b/libraries/core/core/serialisation/directive.hpp new file mode 100644 index 00000000..3c0ed640 --- /dev/null +++ b/libraries/core/core/serialisation/directive.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include + +namespace morpheus::serialisation +{ + +using FundamentalValue = std::variant; + +struct BeginValueDirective +{ + constexpr auto operator<=>(BeginValueDirective const&) const noexcept = default; +}; + +struct ValueDirective +{ + FundamentalValue value; + constexpr auto operator<=>(ValueDirective const&) const noexcept = default; +}; + +struct EndValueDirective +{ + constexpr auto operator<=>(EndValueDirective const&) const noexcept = default; +}; + +struct BeginCompositeDirective +{ + constexpr auto operator<=>(BeginCompositeDirective const&) const noexcept = default; +}; + +struct EndCompositeDirective +{ + constexpr auto operator<=>(EndCompositeDirective const&) const noexcept = default; +}; + +struct BeginSequenceDirective +{ + constexpr auto operator<=>(BeginSequenceDirective const&) const noexcept = default; +}; + +struct EndSequenceDirective +{ + constexpr auto operator<=>(EndSequenceDirective const&) const noexcept = default; +}; + +struct BeginNullableDirective +{ + bool null = false; + constexpr auto operator<=>(BeginNullableDirective const&) const noexcept = default; +}; + +struct EndNullableDirective +{ + constexpr auto operator<=>(EndNullableDirective const&) const noexcept = default; +}; + + +/// \using Directive +/// +using Directive = std::variant< + BeginValueDirective, + ValueDirective, + EndValueDirective, + BeginCompositeDirective, + EndCompositeDirective, + BeginSequenceDirective, + EndSequenceDirective, + BeginNullableDirective, + EndNullableDirective + >; + +/// \using DirectiveLog +/// +using DirectiveLog = std::vector; + + +} \ No newline at end of file diff --git a/libraries/core/core/serialisation/directive_reader.hpp b/libraries/core/core/serialisation/directive_reader.hpp new file mode 100644 index 00000000..a950fcb6 --- /dev/null +++ b/libraries/core/core/serialisation/directive_reader.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include "core/serialisation/directive.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace morpheus::serialisation +{ + +/// \class DirectiveReader +/// +class DirectiveReader +{ +public: + static constexpr bool isTextual() { return false; } + + explicit DirectiveReader() = default; + + void beginComposite(); + void endComposite(); + void beginValue(std::string_view const key); + void endValue(); + void beginSequence(std::optional = std::nullopt); + void endSequence(); + + template requires std::is_arithmetic_v or std::is_same_v + T read() + { + return T; + } + + constexpr auto const& getLog() const noexcept { return mDirectiveLog; } +private: + DirectiveLog mDirectiveLog; +}; + + +} \ No newline at end of file diff --git a/libraries/core/core/serialisation/directive_writer.hpp b/libraries/core/core/serialisation/directive_writer.hpp new file mode 100644 index 00000000..a2629966 --- /dev/null +++ b/libraries/core/core/serialisation/directive_writer.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "core/serialisation/directive.hpp" + +#include +#include +#include +#include +#include +#include + +namespace morpheus::serialisation +{ + +/// \class DirectiveWriter +/// Captures a serialisation directive log dictating the order of operations for a recorded stream of objects. +class DirectiveWriter +{ +public: + static constexpr bool isTextual() { return false; } + + explicit DirectiveWriter() = default; + + void beginComposite() { return mDirectiveLog.emplace_back( BeginCompositeDirective{} ); } + void endComposite() { return mDirectiveLog.emplace_back( EndCompositeDirective{} ); } + void beginValue(std::string_view const key) { return mDirectiveLog.emplace_back( BeginValueDirective{ key } ); } + void endValue() { return mDirectiveLog.emplace_back( EndValueDirective{} ); } + void beginSequence(std::optional = std::nullopt) { return mDirectiveLog.emplace_back( BeginSequenceDirective{ value } ); } + void endSequence() { return mDirectiveLog.emplace_back( EndSequenceDirective{} ); } + void beginNullable(bool const null) { return mDirectiveLog.emplace_back( BeginNullableDirective{ null } ); } + void endNullable() { return mDirectiveLog.emplace_back( EndNullableDirective{} ); } + + void write(auto const value) requires std::is_arithmetic_v { return mDirectiveLog.emplace_back( ValueDirective{value} ); } + void write(std::string_view const value) { return mDirectiveLog.emplace_back(ValueDirective{ std::string(value) }); } +// void write(std::span const value); + + template void write(const char(&str)[N]) { write(std::string_view(str, N-1)); } + + constexpr auto const& getLog() const noexcept { return mDirectiveLog; } +private: + DirectiveLog mDirectiveLog; +}; + + +} \ No newline at end of file From 2c95e74a9067a913e3f1232a45a09929d72fc027 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Fri, 4 Nov 2022 07:49:27 +0000 Subject: [PATCH 04/21] Minor fixes --- .../src/morpheus/core/conformance/print.hpp | 9 ++++--- .../morpheus/core/meta/concepts/string.hpp | 2 +- libraries/core/tests/meta/is_string.tests.cpp | 27 ++++++++++++++++++- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/libraries/core/src/morpheus/core/conformance/print.hpp b/libraries/core/src/morpheus/core/conformance/print.hpp index 9c148b61..ac2c7730 100644 --- a/libraries/core/src/morpheus/core/conformance/print.hpp +++ b/libraries/core/src/morpheus/core/conformance/print.hpp @@ -1,9 +1,12 @@ #pragma once #if __has_include() -# include +#include +#endif // #if __has_include() + +#if (__cpp_lib_print >= 202207L) namespace morpheus { namespace print_ns = std; } #else -# include +# include namespace morpheus { namespace print_ns = fmt; } -#endif +#endif \ No newline at end of file diff --git a/libraries/core/src/morpheus/core/meta/concepts/string.hpp b/libraries/core/src/morpheus/core/meta/concepts/string.hpp index a237afdd..7fba1b10 100644 --- a/libraries/core/src/morpheus/core/meta/concepts/string.hpp +++ b/libraries/core/src/morpheus/core/meta/concepts/string.hpp @@ -11,7 +11,7 @@ template< class T > concept IsString = is_string_v>; template< class T > -concept IsStringView = is_string_v>; +concept IsStringView = is_string_view_v>; template< class T > concept ConvertableToStringView = std::is_convertible_v, std::string_view> || diff --git a/libraries/core/tests/meta/is_string.tests.cpp b/libraries/core/tests/meta/is_string.tests.cpp index 13bbb725..4bf0bbfd 100644 --- a/libraries/core/tests/meta/is_string.tests.cpp +++ b/libraries/core/tests/meta/is_string.tests.cpp @@ -1,5 +1,5 @@ +#include "morpheus/core/meta/concepts/string.hpp" #include "morpheus/core/meta/is_string.hpp" - #include namespace morpheus::meta @@ -55,4 +55,29 @@ TEST_CASE("Meta is string allows the compile time detection of string view types STATIC_REQUIRE(!meta::is_string_view_v); } +TEST_CASE("Concepts to detect string types", "[morpheus.meta.string]") +{ + STATIC_REQUIRE(meta::IsString); + STATIC_REQUIRE(meta::IsString); + STATIC_REQUIRE(meta::IsString); + STATIC_REQUIRE(meta::IsString); + STATIC_REQUIRE(meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); + STATIC_REQUIRE(!meta::IsString); +} + } // namespace morpheus::meta From 393984e6b3f072836e7aeaa0034650865f1ae4c0 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Tue, 8 Nov 2022 10:06:49 +0000 Subject: [PATCH 05/21] Support Date across compilers --- CMakeLists.txt | 1 + cmake/third_party.cmake | 13 ++++++++++-- .../morpheus/core/conformance/CMakeLists.txt | 2 ++ .../src/morpheus/core/conformance/date.hpp | 15 +++++++++++++ libraries/core/tests/CMakeLists.txt | 1 + .../core/tests/conformance/CMakeLists.txt | 4 ++++ .../core/tests/conformance/date.tests.cpp | 21 +++++++++++++++++++ 7 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 libraries/core/src/morpheus/core/conformance/date.hpp create mode 100644 libraries/core/tests/conformance/CMakeLists.txt create mode 100644 libraries/core/tests/conformance/date.tests.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b21b825..7636ba67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ project(Morpheus LANGUAGES CXX ) +cmake_policy(SET CMP0077 NEW) cmake_policy(SET CMP0127 NEW) #------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/cmake/third_party.cmake b/cmake/third_party.cmake index 696cd861..dd961b10 100644 --- a/cmake/third_party.cmake +++ b/cmake/third_party.cmake @@ -19,9 +19,18 @@ if(NOT codecoverage_POPULATED) list(APPEND CMAKE_MODULE_PATH ${codecoverage_SOURCE_DIR}/cmake) endif() + +if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + FetchContent_Declare( + date + GIT_REPOSITORY https://github.com/HowardHinnant/date.git + ) + FetchContent_MakeAvailable(date) +endif (NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + + if(WIN32) - set(WIL_BUILD_TESTS OFF CACHE BOOL "Sets option to build the unit tests, default on" FORCE) -# option(WIL_BUILD_TESTS "Sets option to build the unit tests, default on" ON) + set(WIL_BUILD_TESTS OFF) FetchContent_Declare( wil GIT_REPOSITORY https://github.com/microsoft/wil.git diff --git a/libraries/core/src/morpheus/core/conformance/CMakeLists.txt b/libraries/core/src/morpheus/core/conformance/CMakeLists.txt index 24a1c9da..9b043264 100644 --- a/libraries/core/src/morpheus/core/conformance/CMakeLists.txt +++ b/libraries/core/src/morpheus/core/conformance/CMakeLists.txt @@ -1,5 +1,6 @@ target_sources(MorpheusCore PUBLIC + date.hpp format.hpp print.hpp ranges.hpp @@ -13,6 +14,7 @@ find_package(range-v3 REQUIRED) target_link_libraries(MorpheusCore PUBLIC + $<$>:date::date> # Only Visual Studio 19.26 onwards has a complete implementation: https://en.cppreference.com/w/cpp/compiler_support fmt::fmt range-v3::range-v3 tl::expected diff --git a/libraries/core/src/morpheus/core/conformance/date.hpp b/libraries/core/src/morpheus/core/conformance/date.hpp new file mode 100644 index 00000000..ebffcd70 --- /dev/null +++ b/libraries/core/src/morpheus/core/conformance/date.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +#if __has_include() +#include +#endif + +#if (__cpp_lib_chrono >= 201907L ) +namespace morpheus { namespace date_ns = std::chrono; } +#else +# include +# include +namespace morpheus { namespace date_ns = date; } +#endif diff --git a/libraries/core/tests/CMakeLists.txt b/libraries/core/tests/CMakeLists.txt index 84d70ea2..f98c7a20 100644 --- a/libraries/core/tests/CMakeLists.txt +++ b/libraries/core/tests/CMakeLists.txt @@ -22,6 +22,7 @@ target_link_libraries(MorpheusCoreTests ) add_subdirectory(base) +add_subdirectory(conformance) add_subdirectory(functional) add_subdirectory(memory) add_subdirectory(meta) diff --git a/libraries/core/tests/conformance/CMakeLists.txt b/libraries/core/tests/conformance/CMakeLists.txt new file mode 100644 index 00000000..8c86743e --- /dev/null +++ b/libraries/core/tests/conformance/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(MorpheusCoreTests + PRIVATE + date.tests.cpp +) \ No newline at end of file diff --git a/libraries/core/tests/conformance/date.tests.cpp b/libraries/core/tests/conformance/date.tests.cpp new file mode 100644 index 00000000..b85b5860 --- /dev/null +++ b/libraries/core/tests/conformance/date.tests.cpp @@ -0,0 +1,21 @@ +#include "morpheus/core/conformance/date.hpp" + +#include + +namespace morpheus +{ + +TEST_CASE("Ensure date library is supported and working", "[morpheus.conformance.date]") +{ + using namespace std::chrono_literals; + using namespace date_ns; + + // Ensure time zones work + REQUIRE(date_ns::locate_zone("Europe/London")); + + STATIC_REQUIRE((year{ 2022 } / month{ 11 } / day{ 8 }) == year_month_day(year{ 2022 }, month{ 11 }, day{ 8 })); + STATIC_REQUIRE(weeks{ 1 } == days{ 7 }); + STATIC_REQUIRE(years{ 1 } == months{ 12 }); +} + +} // morpheus \ No newline at end of file From 65f2293f78bb562f9f06b4cd4ef28de26ffa0d25 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Thu, 24 Nov 2022 21:27:48 +0000 Subject: [PATCH 06/21] Move to coroutine generator support to deserialisation of sequences --- .../morpheus/core/concurrency/generator.hpp | 8 +-- .../serialisation/adapters/std/expected.hpp | 44 ++++++++++++ .../serialisation/adapters/std/ranges.hpp | 9 +-- .../serialisation/adapters/std/variant.hpp | 7 +- .../core/serialisation/concepts/reader.hpp | 3 +- .../concepts/reader_archtype.hpp | 2 +- .../core/serialisation/json_reader.cpp | 21 ++++-- .../core/serialisation/json_reader.hpp | 70 +++++++++++++++++-- .../serialisation/read_serialiser_decl.hpp | 2 +- .../core/serialisation/write_serialiser.hpp | 2 + .../serialisation/write_serialiser_decl.hpp | 2 +- .../serialisation/adapters/std/pair.tests.cpp | 2 +- .../adapters/std/ranges.tests.cpp | 6 ++ .../adapters/std/tuple.tests.cpp | 2 +- .../tests/serialisation/json_reader.tests.cpp | 13 +++- .../tests/serialisation/json_writer.tests.cpp | 5 +- 16 files changed, 168 insertions(+), 30 deletions(-) create mode 100644 libraries/core/src/morpheus/core/serialisation/adapters/std/expected.hpp diff --git a/libraries/core/src/morpheus/core/concurrency/generator.hpp b/libraries/core/src/morpheus/core/concurrency/generator.hpp index b219366f..de3c5d37 100644 --- a/libraries/core/src/morpheus/core/concurrency/generator.hpp +++ b/libraries/core/src/morpheus/core/concurrency/generator.hpp @@ -47,10 +47,10 @@ struct Generator { auto get_return_object() { return Generator{ handle_type::from_promise(*this) }; } - auto return_void() { - return coro_ns::suspend_never{}; - } - +// auto return_void() { +// return coro_ns::suspend_never{}; +// } + void return_void() noexcept {} auto yield_value(const T value) { current_value = value; return coro_ns::suspend_always{}; diff --git a/libraries/core/src/morpheus/core/serialisation/adapters/std/expected.hpp b/libraries/core/src/morpheus/core/serialisation/adapters/std/expected.hpp new file mode 100644 index 00000000..479c7ec9 --- /dev/null +++ b/libraries/core/src/morpheus/core/serialisation/adapters/std/expected.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "morpheus/core/meta/is_specialisation.hpp" +#include "morpheus/core/conformance/expected.hpp" +#include "morpheus/core/serialisation/concepts/read_serialiser.hpp" +#include "morpheus/core/serialisation/concepts/read_serialisable.hpp" +#include "morpheus/core/serialisation/concepts/write_serialiser.hpp" +#include "morpheus/core/serialisation/concepts/write_serialisable.hpp" + +#include + +namespace morpheus::serialisation::detail +{ + +template +concept IsStdExpected = meta::IsSpecialisationOf; + +template +void serialise(Serialiser& serialiser, std::expected const& value) +{ + serialiser.writer().beginComposite(); + serialiser.serialise("state", value); + if (value) [[likely]] + serialiser.serialise("value", value.value()); + else + serialiser.serialise("error", value.error()); + serialiser.writer().endComposite(); +} + +template +T deserialise(Serialiser& serialiser) +{ + auto const nullable = makeScopedNullable(serialiser.reader()); + if (nullable.value()) + return exp_ns::expected( + serialiser.template deserialise() + ); + else + return exp_ns::expected( + serialiser.template deserialise() + ); +} + +} // morpheus::serialisation::detail \ No newline at end of file diff --git a/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp b/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp index 2416dbe2..3953a8b7 100644 --- a/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp +++ b/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp @@ -5,15 +5,16 @@ #include "morpheus/core/serialisation/concepts/read_serialisable.hpp" #include "morpheus/core/serialisation/concepts/write_serialiser.hpp" #include "morpheus/core/serialisation/concepts/write_serialisable.hpp" +#include "morpheus/core/meta/concepts/string.hpp" namespace morpheus::serialisation::detail { -//template -//concept IsRange = meta::IsSpecialisationOf; +template +concept IsRange = ranges::range and not (meta::IsString or meta::IsStringView); -template -void serialise(Serialiser& serialiser, auto const& range) +template +void serialise(Serialiser& serialiser, IsRange auto const& range) { serialiser.serialise(ranges::size(range), [&]() { diff --git a/libraries/core/src/morpheus/core/serialisation/adapters/std/variant.hpp b/libraries/core/src/morpheus/core/serialisation/adapters/std/variant.hpp index ad2a50b3..30272ddd 100644 --- a/libraries/core/src/morpheus/core/serialisation/adapters/std/variant.hpp +++ b/libraries/core/src/morpheus/core/serialisation/adapters/std/variant.hpp @@ -46,7 +46,8 @@ struct TypeListNames> template void serialise(Serialiser& serialiser, std::variant const& value) { - serialiser.serialise([&]() + serialiser.writer().beginComposite(); +// serialiser.serialise([&]() { if (value.valueless_by_exception()) [[unlikely]] { @@ -63,7 +64,9 @@ void serialise(Serialiser& serialiser, std::variant const& value) std::visit([&serialiser](auto const& value) { return serialiser.serialise("value", value); }, value); } - }); + } + //); + serialiser.writer().endComposite(); } template diff --git a/libraries/core/src/morpheus/core/serialisation/concepts/reader.hpp b/libraries/core/src/morpheus/core/serialisation/concepts/reader.hpp index a6fcd7ab..e1c60682 100644 --- a/libraries/core/src/morpheus/core/serialisation/concepts/reader.hpp +++ b/libraries/core/src/morpheus/core/serialisation/concepts/reader.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -20,7 +21,7 @@ concept Reader = requires(T t) { t.endComposite() } -> std::same_as; { t.beginValue(std::string_view{}) } -> std::same_as; { t.endValue() } -> std::same_as; - { t.beginSequence(std::size_t{}) } -> std::same_as; + { t.beginSequence() } -> std::same_as>; { t.endSequence() } -> std::same_as; { t.beginNullable() } -> std::same_as; { t.endNullable() } -> std::same_as; diff --git a/libraries/core/src/morpheus/core/serialisation/concepts/reader_archtype.hpp b/libraries/core/src/morpheus/core/serialisation/concepts/reader_archtype.hpp index cf0e72e5..716a1d10 100644 --- a/libraries/core/src/morpheus/core/serialisation/concepts/reader_archtype.hpp +++ b/libraries/core/src/morpheus/core/serialisation/concepts/reader_archtype.hpp @@ -21,7 +21,7 @@ struct ReaderArchtype consteval void endComposite(); consteval void beginValue(std::string_view const key); consteval void endValue(); - consteval void beginSequence(std::optional = std::nullopt); + consteval std::optional beginSequence(); consteval void endSequence(); consteval bool beginNullable(); consteval void endNullable(); diff --git a/libraries/core/src/morpheus/core/serialisation/json_reader.cpp b/libraries/core/src/morpheus/core/serialisation/json_reader.cpp index 0163e99c..01e7a680 100644 --- a/libraries/core/src/morpheus/core/serialisation/json_reader.cpp +++ b/libraries/core/src/morpheus/core/serialisation/json_reader.cpp @@ -123,19 +123,22 @@ JsonReader::~JsonReader() void JsonReader::beginComposite() { - auto const [event, next] = getNext(); + auto const state = currentState(); + auto const [event, next] = state.value(); MORPHEUS_VERIFY(event == Event::BeginComposite); } void JsonReader::endComposite() { - auto const [event, next] = getNext(); + auto const state = currentState(); + auto const [event, next] = state.value(); MORPHEUS_VERIFY(event == Event::EndComposite); } void JsonReader::beginValue(std::string_view const key) { - auto const [event, next] = getNext(); + auto const state = currentState(); + auto const [event, next] = state.value(); MORPHEUS_VERIFY(event == Event::BeginComposite); MORPHEUS_VERIFY(next); MORPHEUS_VERIFY(next->index() == 5); @@ -148,21 +151,25 @@ void JsonReader::endValue() // MORPHEUS_VERIFY(event == Event::EndComposite); } -void JsonReader::beginSequence(std::optional) +std::optional JsonReader::beginSequence() { - auto const [event, next] = getNext(); + auto const state = currentState(); + auto const [event, next] = state.value(); MORPHEUS_VERIFY(event == Event::BeginSequence); + return std::nullopt; } void JsonReader::endSequence() { - auto const [event, next] = getNext(); + auto const state = currentState(); + auto const [event, next] = state.value(); MORPHEUS_VERIFY(event == Event::EndSequence); } bool JsonReader::beginNullable() { - auto const [event, next] = getNext(); + auto const state = currentState(); + auto const [event, next] = state.value(); //if (null) // beginComposite(); MORPHEUS_VERIFY(event == Event::Value); diff --git a/libraries/core/src/morpheus/core/serialisation/json_reader.hpp b/libraries/core/src/morpheus/core/serialisation/json_reader.hpp index b1647352..30794eb3 100644 --- a/libraries/core/src/morpheus/core/serialisation/json_reader.hpp +++ b/libraries/core/src/morpheus/core/serialisation/json_reader.hpp @@ -1,7 +1,11 @@ #pragma once #include "morpheus/core/base/assert.hpp" +#include "morpheus/core/base/scoped_action.hpp" +#include "morpheus/core/concurrency/generator.hpp" #include "morpheus/core/functional/overload.hpp" +#include "morpheus/core/serialisation/concepts/reader_archtype.hpp" +#include "morpheus/core/serialisation/read_serialiser_decl.hpp" #include @@ -27,6 +31,13 @@ namespace morpheus::serialisation /// Read in objects from an underlying json representation. class MORPHEUSCORE_EXPORT JsonReader { + [[nodiscard]] auto currentState() + { + return ScopedAction( + [&]() { if (!mCurrent) mCurrent = getNext(); return *mCurrent; }, + [&]() { mCurrent.reset(); } + ); + } public: /// \class Exception /// Exception type to be thrown for errors when parsing JSON. @@ -47,15 +58,36 @@ class MORPHEUSCORE_EXPORT JsonReader void endComposite(); void beginValue(std::string_view const key); void endValue(); - void beginSequence(std::optional = std::nullopt); + std::optional beginSequence(); void endSequence(); bool beginNullable(); void endNullable(); + template requires requires(concepts::ReaderArchtype& r) { { r.template read() } ->std::same_as; } + auto readSequence()//std::invocable auto serialiser) + { + return [&/*, serialiser = std::move(serialiser)*/]() -> concurrency::Generator + { + beginSequence(); + for(;;) + { + auto const state = currentState(); + auto const [event, next] = state.value(); + if (event == Event::EndSequence) + co_return; + + MORPHEUS_ASSERT(event == Event::Value); + co_yield read(); + //co_yield serialiser(); + } + }; + } + template requires std::is_same_v T read() { - auto const [event, next] = getNext(); + auto const state = currentState(); + auto const [event, next] = state.value(); MORPHEUS_ASSERT(next->index() == 0); return std::get(*next); } @@ -63,7 +95,8 @@ class MORPHEUSCORE_EXPORT JsonReader template requires (not std::is_same_v) Interger read() { - auto const [event, next] = getNext(); + auto const state = currentState(); + auto const [event, next] = state.value(); MORPHEUS_ASSERT((next->index() == 1) or (next->index() == 2)); return std::visit(functional::Overload{ [](std::integral auto const value) { return boost::numeric_cast(value); }, @@ -74,7 +107,8 @@ class MORPHEUSCORE_EXPORT JsonReader template Float read() { - auto const [event, next] = getNext(); + auto const state = currentState(); + auto const [event, next] = state.value(); MORPHEUS_ASSERT((next->index() == 1) or (next->index() == 2) or (next->index() == 3) or (next->index() == 4)); return std::visit(functional::Overload { [](std::integral auto const value) { return boost::numeric_cast(value); }, @@ -96,7 +130,8 @@ class MORPHEUSCORE_EXPORT JsonReader template requires std::is_same_v T read() { - auto const [event, next] = getNext(); + auto const state = currentState(); + auto const [event, next] = state.value(); MORPHEUS_ASSERT(next->index() == 5); return std::get(*next); } @@ -120,9 +155,34 @@ class MORPHEUSCORE_EXPORT JsonReader [[nodiscard]] EventValue getNext(); +/* [[nodiscard]] auto currentState() + { + return ScopedAction( +// [&]() { return getCurrent(); }, +// [&]() { clearCurrent(); } + [&]() + { + if (!mCurrent) mCurrent = getNext(); + return *mCurrent; + }, + [&]() { mCurrent.reset(); } + ); + }*/ + +/* + EventValue& getCurrent() + { + if (!mCurrent) + mCurrent = getNext(); + return *mCurrent; + } + void clearCurrent() { mCurrent.reset(); } +*/ + rapidjson::IStreamWrapper mStream; rapidjson::Reader mJsonReader; std::unique_ptr mExtractor; + std::optional mCurrent; }; diff --git a/libraries/core/src/morpheus/core/serialisation/read_serialiser_decl.hpp b/libraries/core/src/morpheus/core/serialisation/read_serialiser_decl.hpp index f459066f..64c51b78 100644 --- a/libraries/core/src/morpheus/core/serialisation/read_serialiser_decl.hpp +++ b/libraries/core/src/morpheus/core/serialisation/read_serialiser_decl.hpp @@ -19,7 +19,7 @@ auto makeScopedValue(concepts::Reader auto& reader, std::string_view const key) auto makeScopedSequence(concepts::Reader auto& reader, std::optional const size = std::nullopt) { - return ScopedAction([&reader, size] { reader.beginSequence(size); }, [&reader] { reader.endSequence(); } ); + return ScopedAction([&reader, size] { reader.beginSequence(); }, [&reader] { reader.endSequence(); } ); } auto makeScopedComposite(concepts::Reader auto& reader) diff --git a/libraries/core/src/morpheus/core/serialisation/write_serialiser.hpp b/libraries/core/src/morpheus/core/serialisation/write_serialiser.hpp index fbac82ed..4c55a85b 100644 --- a/libraries/core/src/morpheus/core/serialisation/write_serialiser.hpp +++ b/libraries/core/src/morpheus/core/serialisation/write_serialiser.hpp @@ -28,6 +28,7 @@ auto WriteSerialiser::serialise(std::size_t size, std::invocable aut mWriter.endSequence(); } +/* template auto WriteSerialiser::serialise(std::invocable auto f) { @@ -35,6 +36,7 @@ auto WriteSerialiser::serialise(std::invocable auto f) f(); mWriter.endComposite(); } +*/ template auto WriteSerialiser::serialise(bool const null, std::invocable auto f) diff --git a/libraries/core/src/morpheus/core/serialisation/write_serialiser_decl.hpp b/libraries/core/src/morpheus/core/serialisation/write_serialiser_decl.hpp index dd229170..15b6cc1c 100644 --- a/libraries/core/src/morpheus/core/serialisation/write_serialiser_decl.hpp +++ b/libraries/core/src/morpheus/core/serialisation/write_serialiser_decl.hpp @@ -56,7 +56,7 @@ class WriteSerialiser /// Serialise a related set of values in a composite. /// \param[in] f The command serialising the composite values. - auto serialise(std::invocable auto f); +// auto serialise(std::invocable auto f); /// Serialise a nullable value /// \param[in] null If the nullable value is null or set. diff --git a/libraries/core/tests/serialisation/adapters/std/pair.tests.cpp b/libraries/core/tests/serialisation/adapters/std/pair.tests.cpp index 109e77e5..c13517de 100644 --- a/libraries/core/tests/serialisation/adapters/std/pair.tests.cpp +++ b/libraries/core/tests/serialisation/adapters/std/pair.tests.cpp @@ -49,7 +49,7 @@ TEST_CASE("Verify deserialisation of std::pair", "[morpheus.serialisation.pair.d THEN("Expect the following sequence of operations on the underlying reader") { MockedReadSerialiser serialiser; - EXPECT_CALL(serialiser.reader(), beginSequence(std::optional(2))).Times(1); + EXPECT_CALL(serialiser.reader(), beginSequence()).Times(1); EXPECT_CALL(serialiser.reader(), read(An())).WillOnce(Return(firstValue)); EXPECT_CALL(serialiser.reader(), read(An())).WillOnce(Return(secondValue)); EXPECT_CALL(serialiser.reader(), endSequence()).Times(1); diff --git a/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp b/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp index 53eacae1..782643de 100644 --- a/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp +++ b/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp @@ -1,7 +1,9 @@ #include "morpheus/core/serialisation/adapters/std/ranges.hpp" +#include "morpheus/core/meta/concepts/string.hpp" #include +#include #include namespace morpheus::serialisation @@ -9,6 +11,10 @@ namespace morpheus::serialisation TEST_CASE("Verify serialisation of ranges", "[morpheus.serialisation.ranges]") { + STATIC_REQUIRE(detail::IsRange>); +// STATIC_REQUIRE(detail::IsRange); +// STATIC_REQUIRE(meta::IsString); + STATIC_REQUIRE(meta::IsStringView); } } // morpheus::serialisation \ No newline at end of file diff --git a/libraries/core/tests/serialisation/adapters/std/tuple.tests.cpp b/libraries/core/tests/serialisation/adapters/std/tuple.tests.cpp index fdc2fa6e..cd1b96b3 100644 --- a/libraries/core/tests/serialisation/adapters/std/tuple.tests.cpp +++ b/libraries/core/tests/serialisation/adapters/std/tuple.tests.cpp @@ -55,7 +55,7 @@ TEST_CASE("Verify deserialisation of std::tuple", "[morpheus.serialisation.tuple THEN("Expect the following sequence of operations on the underlying reader") { MockedReadSerialiser serialiser; - EXPECT_CALL(serialiser.reader(), beginSequence(std::optional(std::tuple_size::value))).Times(1); + EXPECT_CALL(serialiser.reader(), beginSequence()).Times(1); [&] (std::index_sequence) { diff --git a/libraries/core/tests/serialisation/json_reader.tests.cpp b/libraries/core/tests/serialisation/json_reader.tests.cpp index 5679e742..056c60d3 100644 --- a/libraries/core/tests/serialisation/json_reader.tests.cpp +++ b/libraries/core/tests/serialisation/json_reader.tests.cpp @@ -1,4 +1,5 @@ #include "morpheus/core/conformance/format.hpp" +#include "morpheus/core/conformance/ranges.hpp" #include "morpheus/core/serialisation/adapters/aggregate.hpp" #include "morpheus/core/serialisation/adapters/std/optional.hpp" #include "morpheus/core/serialisation/adapters/std/pair.hpp" @@ -187,12 +188,22 @@ TEST_CASE("Json reader can read simple composite types from underlying test repr } } +TEST_CASE("Json reader can read std types from underlying text representation", "[morpheus.serialisation.json_reader.read_sequence]") +{ + using namespace std::string_literals; + std::istringstream iss("[0,1,2,3,4,5]"); + JsonReader reader{ iss }; + std::vector expectedValues{ 0,1,2,3,4,5 }; + auto sequenceGenerator = reader.readSequence(); + REQUIRE(ranges::equal(sequenceGenerator(), expectedValues)); +} + TEST_CASE("Json reader can read std types from underlying text representation", "[morpheus.serialisation.json_reader.adapters.std]") { REQUIRE(test::deserialise>(R"([50,true])") == std::pair{50, true}); REQUIRE(test::deserialise>(R"([75,true,"Example"])") == std::tuple{75, true, "Example"}); // REQUIRE(test::deserialise>(R"({"type":"bool","value":true})") == std::variant{true}); -// REQUIRE(test::deserialise>(R"({50})") == std::make_unique(50)); + //REQUIRE(test::deserialise>(R"(50)") == std::make_unique(50)); } } // namespace morpheus::serialisation \ No newline at end of file diff --git a/libraries/core/tests/serialisation/json_writer.tests.cpp b/libraries/core/tests/serialisation/json_writer.tests.cpp index eec69505..ff963ff2 100644 --- a/libraries/core/tests/serialisation/json_writer.tests.cpp +++ b/libraries/core/tests/serialisation/json_writer.tests.cpp @@ -2,6 +2,7 @@ #include "morpheus/core/serialisation/adapters/aggregate.hpp" #include "morpheus/core/serialisation/adapters/std/optional.hpp" #include "morpheus/core/serialisation/adapters/std/pair.hpp" +#include "morpheus/core/serialisation/adapters/std/ranges.hpp" #include "morpheus/core/serialisation/adapters/std/tuple.hpp" #include "morpheus/core/serialisation/adapters/std/unique_ptr.hpp" #include "morpheus/core/serialisation/adapters/std/variant.hpp" @@ -27,7 +28,7 @@ std::string serialise(T const& value) { std::ostringstream oss; JsonWriteSerialiser serialiser{oss}; - serialiser.serialise(value); + serialiser.serialise(value); return oss.str(); } @@ -254,6 +255,8 @@ TEST_CASE("Json writer can write std types to underlying text representation", " REQUIRE(test::serialise(std::tuple{75, true, "Example"}) == R"([75,true,"Example"])"); REQUIRE(test::serialise(std::make_unique(123)) == R"(123)"); REQUIRE(test::serialise(std::variant{true}) == R"({"type":"bool","value":true})"); + REQUIRE(test::serialise(std::vector{0,1,2,3,4,5}) == R"([0,1,2,3,4,5])"); + static_assert(ranges::range>); } } // namespace morpheus::serialisation \ No newline at end of file From d67ca2335e6a6469d7cf8f3791f95e01d06a2cf3 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Thu, 24 Nov 2022 21:31:09 +0000 Subject: [PATCH 07/21] Merged github action --- .github/workflows/cmake.yml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index f0bc421f..09d4668a 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -36,7 +36,6 @@ jobs: os: windows-latest, compiler: { type: VISUAL, version: 16, cc: "cl", cxx: "cl", std: 20 }, } -<<<<<<< Updated upstream - { name: "MacOS Apple Clang 14", os: macos-12, @@ -51,22 +50,6 @@ jobs: }, lib: "libc++", } -======= -# - { -# name: "MacOS Apple Clang 14", # https://github.com/actions/runner-images/issues/6225 -# os: macos-latest, -# compiler: -# { -# type: APPLE_CLANG, -# version: "14.0", -# conan: "apple-clang", -# cc: "clang", -# cxx: "clang++", -# std: 20 -# }, -# lib: "libc++", -# } ->>>>>>> Stashed changes steps: - uses: actions/checkout@v2 # - uses: lhotari/action-upterm@v1 From d6b72cfb24c8e818d2f7c5255219615daf2577b5 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 26 Nov 2022 17:05:05 +0000 Subject: [PATCH 08/21] Serialisation mocking update --- .../core/mocking/morpheus/core/serialisation/mock/reader.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/core/mocking/morpheus/core/serialisation/mock/reader.hpp b/libraries/core/mocking/morpheus/core/serialisation/mock/reader.hpp index 4b8cc35d..1e5877e4 100644 --- a/libraries/core/mocking/morpheus/core/serialisation/mock/reader.hpp +++ b/libraries/core/mocking/morpheus/core/serialisation/mock/reader.hpp @@ -25,7 +25,7 @@ class Reader MOCK_METHOD(void, endComposite, (), ()); MOCK_METHOD(void, beginValue, (std::string_view), ()); MOCK_METHOD(void, endValue, (), ()); - MOCK_METHOD(void, beginSequence, (std::optional), ()); + MOCK_METHOD(std::optional, beginSequence, (), ()); MOCK_METHOD(void, endSequence, (), ()); MOCK_METHOD(bool, beginNullable, (), ()); MOCK_METHOD(void, endNullable, (), ()); From a9cf72e5e716c8fbb9afc9ff9cc0e68d12a1ca7b Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 1 Apr 2023 12:34:00 +0100 Subject: [PATCH 09/21] Formatting --- .../morpheus/core/concurrency/generator.hpp | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/libraries/core/src/morpheus/core/concurrency/generator.hpp b/libraries/core/src/morpheus/core/concurrency/generator.hpp index a856055b..c3ca9aba 100644 --- a/libraries/core/src/morpheus/core/concurrency/generator.hpp +++ b/libraries/core/src/morpheus/core/concurrency/generator.hpp @@ -26,7 +26,9 @@ struct Generator using reference = std::conditional_t, T, const value_type&>; using pointer = std::add_pointer_t; - Generator(handle_type h) : coro(h) {} + Generator(handle_type h) + : coro(h) + {} /// Destroys the generator. ~Generator() @@ -38,7 +40,9 @@ struct Generator Generator(const Generator&) = delete; Generator& operator=(const Generator&) = delete; - Generator(Generator&& rhs) noexcept : coro(std::exchange(rhs.coro, {})) {} + Generator(Generator&& rhs) noexcept + : coro(std::exchange(rhs.coro, {})) + {} Generator& operator=(Generator&& rhs) noexcept { @@ -46,21 +50,21 @@ struct Generator return *this; } - struct promise_type { - auto initial_suspend() { - return coro_ns::suspend_always{}; - } - auto final_suspend() noexcept { - return coro_ns::suspend_always{}; - } - auto get_return_object() { - return Generator{ handle_type::from_promise(*this) }; - } -// auto return_void() { -// return coro_ns::suspend_never{}; -// } + struct promise_type + { + auto initial_suspend() { return coro_ns::suspend_always{}; } + + auto final_suspend() noexcept { return coro_ns::suspend_always{}; } + + auto get_return_object() { return Generator{handle_type::from_promise(*this)}; } + + // auto return_void() { + // return coro_ns::suspend_never{}; + // } void return_void() noexcept {} - auto yield_value(const T value) { + + auto yield_value(const T value) + { current_value = value; return coro_ns::suspend_always{}; } @@ -76,8 +80,8 @@ struct Generator { public: using value_type = Generator::value_type; ///< Value type pointed to by the iterator. - using reference = Generator::reference; ///< Reference to the underlying value type pointed to by the iterator. - using pointer = Generator::pointer; ///< Pointer to the underlying value type pointed to by the iterator. + using reference = Generator::reference; ///< Reference to the underlying value type pointed to by the iterator. + using pointer = Generator::pointer; ///< Pointer to the underlying value type pointed to by the iterator. using difference_type = std::ptrdiff_t; using iterator_category = std::input_iterator_tag; @@ -85,7 +89,9 @@ struct Generator iterator(iterator const& rhs) noexcept = default; iterator& operator=(iterator const& other) noexcept = default; - iterator(iterator&& rhs) noexcept : handle(std::exchange(rhs.handle, {})) {} + iterator(iterator&& rhs) noexcept + : handle(std::exchange(rhs.handle, {})) + {} iterator& operator=(iterator&& other) noexcept { @@ -115,7 +121,9 @@ struct Generator private: friend Generator; - explicit iterator(coro_ns::coroutine_handle h) noexcept : handle(h) {} + explicit iterator(coro_ns::coroutine_handle h) noexcept + : handle(h) + {} coro_ns::coroutine_handle handle; }; From 3460dc917509c1ad9addc4d96db7996948aecd0d Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 29 Apr 2023 20:42:52 +0100 Subject: [PATCH 10/21] Formatting --- .../src/morpheus/core/serialisation/json_reader.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libraries/core/src/morpheus/core/serialisation/json_reader.cpp b/libraries/core/src/morpheus/core/serialisation/json_reader.cpp index 6e4662ac..ecbf51af 100644 --- a/libraries/core/src/morpheus/core/serialisation/json_reader.cpp +++ b/libraries/core/src/morpheus/core/serialisation/json_reader.cpp @@ -124,7 +124,12 @@ JsonReader::EventValue JsonReader::getNext() return mExtractor->mCurrent; } -JsonReader::JsonReader(std::istream& stream) : mStream(stream), mExtractor(std::make_unique()) { mJsonReader.IterativeParseInit(); } +JsonReader::JsonReader(std::istream& stream) +: mStream(stream) +, mExtractor(std::make_unique()) +{ + mJsonReader.IterativeParseInit(); +} JsonReader::~JsonReader() { MORPHEUS_VERIFY(mJsonReader.IterativeParseComplete()); } @@ -177,8 +182,8 @@ bool JsonReader::beginNullable() { auto const state = currentState(); auto const [event, next] = state.value(); - //if (null) - // beginComposite(); + // if (null) + // beginComposite(); MORPHEUS_VERIFY(event == Event::Value); return !next; } From 22f44cc36f67e01f8e5d973deb3613083f86fc96 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sun, 14 May 2023 15:02:53 +0100 Subject: [PATCH 11/21] Directives picked up by mocking --- .../morpheus/core/serialisation/directive.hpp | 79 ------------------- .../core/serialisation/directive_reader.hpp | 46 ----------- .../core/serialisation/directive_writer.hpp | 45 ----------- 3 files changed, 170 deletions(-) delete mode 100644 libraries/core/src/morpheus/core/serialisation/directive.hpp delete mode 100644 libraries/core/src/morpheus/core/serialisation/directive_reader.hpp delete mode 100644 libraries/core/src/morpheus/core/serialisation/directive_writer.hpp diff --git a/libraries/core/src/morpheus/core/serialisation/directive.hpp b/libraries/core/src/morpheus/core/serialisation/directive.hpp deleted file mode 100644 index 3c0ed640..00000000 --- a/libraries/core/src/morpheus/core/serialisation/directive.hpp +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace morpheus::serialisation -{ - -using FundamentalValue = std::variant; - -struct BeginValueDirective -{ - constexpr auto operator<=>(BeginValueDirective const&) const noexcept = default; -}; - -struct ValueDirective -{ - FundamentalValue value; - constexpr auto operator<=>(ValueDirective const&) const noexcept = default; -}; - -struct EndValueDirective -{ - constexpr auto operator<=>(EndValueDirective const&) const noexcept = default; -}; - -struct BeginCompositeDirective -{ - constexpr auto operator<=>(BeginCompositeDirective const&) const noexcept = default; -}; - -struct EndCompositeDirective -{ - constexpr auto operator<=>(EndCompositeDirective const&) const noexcept = default; -}; - -struct BeginSequenceDirective -{ - constexpr auto operator<=>(BeginSequenceDirective const&) const noexcept = default; -}; - -struct EndSequenceDirective -{ - constexpr auto operator<=>(EndSequenceDirective const&) const noexcept = default; -}; - -struct BeginNullableDirective -{ - bool null = false; - constexpr auto operator<=>(BeginNullableDirective const&) const noexcept = default; -}; - -struct EndNullableDirective -{ - constexpr auto operator<=>(EndNullableDirective const&) const noexcept = default; -}; - - -/// \using Directive -/// -using Directive = std::variant< - BeginValueDirective, - ValueDirective, - EndValueDirective, - BeginCompositeDirective, - EndCompositeDirective, - BeginSequenceDirective, - EndSequenceDirective, - BeginNullableDirective, - EndNullableDirective - >; - -/// \using DirectiveLog -/// -using DirectiveLog = std::vector; - - -} \ No newline at end of file diff --git a/libraries/core/src/morpheus/core/serialisation/directive_reader.hpp b/libraries/core/src/morpheus/core/serialisation/directive_reader.hpp deleted file mode 100644 index a950fcb6..00000000 --- a/libraries/core/src/morpheus/core/serialisation/directive_reader.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include "core/serialisation/directive.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace morpheus::serialisation -{ - -/// \class DirectiveReader -/// -class DirectiveReader -{ -public: - static constexpr bool isTextual() { return false; } - - explicit DirectiveReader() = default; - - void beginComposite(); - void endComposite(); - void beginValue(std::string_view const key); - void endValue(); - void beginSequence(std::optional = std::nullopt); - void endSequence(); - - template requires std::is_arithmetic_v or std::is_same_v - T read() - { - return T; - } - - constexpr auto const& getLog() const noexcept { return mDirectiveLog; } -private: - DirectiveLog mDirectiveLog; -}; - - -} \ No newline at end of file diff --git a/libraries/core/src/morpheus/core/serialisation/directive_writer.hpp b/libraries/core/src/morpheus/core/serialisation/directive_writer.hpp deleted file mode 100644 index a2629966..00000000 --- a/libraries/core/src/morpheus/core/serialisation/directive_writer.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include "core/serialisation/directive.hpp" - -#include -#include -#include -#include -#include -#include - -namespace morpheus::serialisation -{ - -/// \class DirectiveWriter -/// Captures a serialisation directive log dictating the order of operations for a recorded stream of objects. -class DirectiveWriter -{ -public: - static constexpr bool isTextual() { return false; } - - explicit DirectiveWriter() = default; - - void beginComposite() { return mDirectiveLog.emplace_back( BeginCompositeDirective{} ); } - void endComposite() { return mDirectiveLog.emplace_back( EndCompositeDirective{} ); } - void beginValue(std::string_view const key) { return mDirectiveLog.emplace_back( BeginValueDirective{ key } ); } - void endValue() { return mDirectiveLog.emplace_back( EndValueDirective{} ); } - void beginSequence(std::optional = std::nullopt) { return mDirectiveLog.emplace_back( BeginSequenceDirective{ value } ); } - void endSequence() { return mDirectiveLog.emplace_back( EndSequenceDirective{} ); } - void beginNullable(bool const null) { return mDirectiveLog.emplace_back( BeginNullableDirective{ null } ); } - void endNullable() { return mDirectiveLog.emplace_back( EndNullableDirective{} ); } - - void write(auto const value) requires std::is_arithmetic_v { return mDirectiveLog.emplace_back( ValueDirective{value} ); } - void write(std::string_view const value) { return mDirectiveLog.emplace_back(ValueDirective{ std::string(value) }); } -// void write(std::span const value); - - template void write(const char(&str)[N]) { write(std::string_view(str, N-1)); } - - constexpr auto const& getLog() const noexcept { return mDirectiveLog; } -private: - DirectiveLog mDirectiveLog; -}; - - -} \ No newline at end of file From f97044b4d0d9816195a6198e2b7c63d332a656f3 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sun, 14 May 2023 15:06:51 +0100 Subject: [PATCH 12/21] Ranges merge fixes --- .../morpheus/core/serialisation/adapters/std/ranges.hpp | 2 +- .../tests/serialisation/adapters/std/ranges.tests.cpp | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp b/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp index 38a902e4..c12aa31d 100644 --- a/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp +++ b/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp @@ -30,7 +30,7 @@ void serialise(Serialiser& serialiser, IsRange auto const& range) serialiser.writer().endSequence(); } -template +template T deserialise(Serialiser& serialiser) { constexpr std::size_t size = std::tuple_size::value; diff --git a/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp b/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp index 88cabede..ba704c38 100644 --- a/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp +++ b/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp @@ -19,6 +19,9 @@ namespace morpheus::serialisation { +using namespace ::testing; +using namespace std::literals::string_view_literals; + TEST_CASE("Verify serialisation of ranges", "[morpheus.serialisation.ranges]") { STATIC_REQUIRE(detail::IsRange>); @@ -27,11 +30,6 @@ TEST_CASE("Verify serialisation of ranges", "[morpheus.serialisation.ranges]") STATIC_REQUIRE(meta::IsStringView); } -} // morpheus::serialisation -using namespace ::testing; -using namespace std::literals::string_view_literals; - - TEMPLATE_TEST_CASE("Verify serialisation of sequence containers std::ranges", "[morpheus.serialisation.ranges.serialise.sequence_containers]", (std::array), std::vector) { GIVEN("A range of values") From 952636f77a857e561a3d3769b224f07ff2094d21 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 15 Jul 2023 22:49:15 +0100 Subject: [PATCH 13/21] Deserialise for ranges --- .../core/serialisation/adapters/std/ranges.hpp | 18 +++++++++--------- .../core/serialisation/json_reader.hpp | 2 -- .../tests/serialisation/json_reader.tests.cpp | 15 +++++++++++---- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp b/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp index c12aa31d..12224b2e 100644 --- a/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp +++ b/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp @@ -33,15 +33,15 @@ void serialise(Serialiser& serialiser, IsRange auto const& range) template T deserialise(Serialiser& serialiser) { - constexpr std::size_t size = std::tuple_size::value; - - auto const scope = makeScopedSequence(serialiser.reader(), std::tuple_size::value); - return[&serialiser](std::index_sequence ) - { - // More work required to support std::tuples containing references. - static_assert((!std::is_reference_v> || ...)); - return T{ serialiser.template deserialise>()... }; - }(std::make_index_sequence()); + auto const scope = makeScopedSequence(serialiser.reader()); + auto sequenceGenerator = serialiser.reader().template readSequence()(); + // We should be using the for_range_t constructor create the container but there is no support for this in Gcc 12 and Clang 15. + // T sequence(std::from_range_t, sequenceGenerator); + T sequence; + for (auto& entry : sequenceGenerator) { + sequence.push_back(entry); + } + return sequence; } } // namespace morpheus::serialisation::detail diff --git a/libraries/core/src/morpheus/core/serialisation/json_reader.hpp b/libraries/core/src/morpheus/core/serialisation/json_reader.hpp index fe60cb84..af7901a0 100644 --- a/libraries/core/src/morpheus/core/serialisation/json_reader.hpp +++ b/libraries/core/src/morpheus/core/serialisation/json_reader.hpp @@ -112,7 +112,6 @@ class MORPHEUSCORE_EXPORT JsonReader { return [&/*, serialiser = std::move(serialiser)*/]() -> concurrency::Generator { - beginSequence(); for (;;) { auto const state = currentState(); auto const [event, next] = state.value(); @@ -121,7 +120,6 @@ class MORPHEUSCORE_EXPORT JsonReader MORPHEUS_ASSERT(event == Event::Value); co_yield read(); - // co_yield serialiser(); } }; } diff --git a/libraries/core/tests/serialisation/json_reader.tests.cpp b/libraries/core/tests/serialisation/json_reader.tests.cpp index b969406b..c697dba4 100644 --- a/libraries/core/tests/serialisation/json_reader.tests.cpp +++ b/libraries/core/tests/serialisation/json_reader.tests.cpp @@ -240,10 +240,17 @@ TEST_CASE("Json reader can read simple composite types from underlying test repr TEST_CASE("Json reader can read std types from underlying text representation", "[morpheus.serialisation.json_reader.read_sequence]") { using namespace std::string_literals; - JsonReader reader = test::readerFromString("[0,1,2,3,4,5]"); - std::vector expectedValues{ 0,1,2,3,4,5 }; - auto sequenceGenerator = reader.readSequence(); - REQUIRE(ranges::equal(sequenceGenerator(), expectedValues)); + std::vector const expectedValues{ 0,1,2,3,4,5 }; + std::vector const actualValues = test::deserialise>("[0,1,2,3,4,5]"); + REQUIRE(actualValues == expectedValues); + // auto sequenceGenerator = reader.readSequence(); + //JsonReader reader = test::readerFromString("[0,1,2,3,4,5]"); + //REQUIRE(ranges::equal(sequenceGenerator(), expectedValues)); + +// GIVEN("A multi-dimensional sequence of sequence") +// { +// JsonReader reader = test::readerFromString("[0,1,2,3,4,5]"); +// } } template From dfb35444d17840f3976c8c0823485434d0da0de8 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 15 Jul 2023 23:03:02 +0100 Subject: [PATCH 14/21] Test clean up --- libraries/core/tests/serialisation/json_reader.tests.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/libraries/core/tests/serialisation/json_reader.tests.cpp b/libraries/core/tests/serialisation/json_reader.tests.cpp index c697dba4..a4a53f0a 100644 --- a/libraries/core/tests/serialisation/json_reader.tests.cpp +++ b/libraries/core/tests/serialisation/json_reader.tests.cpp @@ -243,14 +243,6 @@ TEST_CASE("Json reader can read std types from underlying text representation", std::vector const expectedValues{ 0,1,2,3,4,5 }; std::vector const actualValues = test::deserialise>("[0,1,2,3,4,5]"); REQUIRE(actualValues == expectedValues); - // auto sequenceGenerator = reader.readSequence(); - //JsonReader reader = test::readerFromString("[0,1,2,3,4,5]"); - //REQUIRE(ranges::equal(sequenceGenerator(), expectedValues)); - -// GIVEN("A multi-dimensional sequence of sequence") -// { -// JsonReader reader = test::readerFromString("[0,1,2,3,4,5]"); -// } } template From b8dce1aed59f495585a2e2c6f2ca67f406262879 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sun, 16 Jul 2023 13:48:24 +0100 Subject: [PATCH 15/21] Ensure tests are run for builds --- .github/workflows/cmake.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 464e2624..b025007b 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -182,3 +182,9 @@ jobs: - name: Build # Build your program with the given configuration run: cmake --build "${{github.workspace}}/build" --config ${{ matrix.configuration }} + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{ matrix.configuration }} \ No newline at end of file From 0f9e9f66a3da7e95c241feba8f49ea42a8996d14 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sun, 16 Jul 2023 17:59:45 +0100 Subject: [PATCH 16/21] Remove inner lambda and simply with repeat current --- .../serialisation/adapters/std/ranges.hpp | 2 +- .../core/serialisation/json_reader.cpp | 29 ++++---- .../core/serialisation/json_reader.hpp | 73 +++++-------------- .../tests/serialisation/json_reader.tests.cpp | 7 +- 4 files changed, 39 insertions(+), 72 deletions(-) diff --git a/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp b/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp index 12224b2e..524f070e 100644 --- a/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp +++ b/libraries/core/src/morpheus/core/serialisation/adapters/std/ranges.hpp @@ -34,7 +34,7 @@ template T deserialise(Serialiser& serialiser) { auto const scope = makeScopedSequence(serialiser.reader()); - auto sequenceGenerator = serialiser.reader().template readSequence()(); + auto sequenceGenerator = serialiser.reader().template readSequence(); // We should be using the for_range_t constructor create the container but there is no support for this in Gcc 12 and Clang 15. // T sequence(std::from_range_t, sequenceGenerator); T sequence; diff --git a/libraries/core/src/morpheus/core/serialisation/json_reader.cpp b/libraries/core/src/morpheus/core/serialisation/json_reader.cpp index 1d36f25f..0ff81844 100644 --- a/libraries/core/src/morpheus/core/serialisation/json_reader.cpp +++ b/libraries/core/src/morpheus/core/serialisation/json_reader.cpp @@ -126,10 +126,19 @@ struct JsonExtracter : rapidjson::BaseReaderHandler, JsonExtra JsonReader::EventValue mCurrent; ///< Current json event. }; - +void JsonReader::repeatCurrent() +{ + MORPHEUS_ASSERT(!mRepeat); + mRepeat = true; +} JsonReader::EventValue JsonReader::getNext() { + if (mRepeat) { + mRepeat = false; + return mExtractor->mCurrent; + } + using namespace rapidjson; mJsonReader.IterativeParseNext(mStream, *mExtractor); if (mJsonReader.HasParseError()) { @@ -166,22 +175,19 @@ JsonReader::~JsonReader() void JsonReader::beginComposite() { - auto const state = currentState(); - auto const [event, next] = state.value(); + auto const [event, next] = getNext(); checkExpectedEvent(event, Event::BeginComposite); } void JsonReader::endComposite() { - auto const state = currentState(); - auto const [event, next] = state.value(); + auto const [event, next] = getNext(); checkExpectedEvent(event, Event::EndComposite); } void JsonReader::beginValue(std::string_view const key) { - auto const state = currentState(); - auto const [event, next] = state.value(); + auto const [event, next] = getNext(); checkExpectedEvent(event, Event::BeginComposite); if (!next) @@ -199,23 +205,20 @@ void JsonReader::endValue() std::optional JsonReader::beginSequence() { - auto const state = currentState(); - auto const [event, next] = state.value(); + auto const [event, next] = getNext(); MORPHEUS_VERIFY(event == Event::BeginSequence); return std::nullopt; } void JsonReader::endSequence() { - auto const state = currentState(); - auto const [event, next] = state.value(); + auto const [event, next] = getNext(); MORPHEUS_VERIFY(event == Event::EndSequence); } bool JsonReader::beginNullable() { - auto const state = currentState(); - auto const [event, next] = state.value(); + auto const [event, next] = getNext(); // if (null) // beginComposite(); MORPHEUS_VERIFY(event == Event::Value); diff --git a/libraries/core/src/morpheus/core/serialisation/json_reader.hpp b/libraries/core/src/morpheus/core/serialisation/json_reader.hpp index af7901a0..8e891d1a 100644 --- a/libraries/core/src/morpheus/core/serialisation/json_reader.hpp +++ b/libraries/core/src/morpheus/core/serialisation/json_reader.hpp @@ -34,17 +34,6 @@ namespace morpheus::serialisation /// Read in objects from an underlying json representation. class MORPHEUSCORE_EXPORT JsonReader { - [[nodiscard]] auto currentState() - { - return ScopedAction( - [&]() - { - if (!mCurrent) - mCurrent = getNext(); - return *mCurrent; - }, - [&]() { mCurrent.reset(); }); - } enum class FundamentalType : std::uint32_t { @@ -108,20 +97,19 @@ class MORPHEUSCORE_EXPORT JsonReader r.template read() } -> std::same_as; } - auto readSequence() // std::invocable auto serialiser) + concurrency::Generator readSequence() { - return [&/*, serialiser = std::move(serialiser)*/]() -> concurrency::Generator - { - for (;;) { - auto const state = currentState(); - auto const [event, next] = state.value(); - if (event == Event::EndSequence) - co_return; - - MORPHEUS_ASSERT(event == Event::Value); - co_yield read(); + for (;;) { + auto const [event, next] = getNext(); + repeatCurrent(); + + if (event == Event::EndSequence) { + co_return; } - }; + + MORPHEUS_ASSERT(event == Event::Value); + co_yield read(); + } } // clang-format off @@ -130,8 +118,7 @@ class MORPHEUSCORE_EXPORT JsonReader requires std::is_same_v T read() { - auto const state = currentState(); - auto const [event, next] = state.value(); + auto const [event, next] = getNext(); MORPHEUS_ASSERT(next->index() == 0); return std::get(*next); } @@ -141,8 +128,7 @@ class MORPHEUSCORE_EXPORT JsonReader requires(not std::is_same_v) Interger read() { - auto const state = currentState(); - auto const [event, next] = state.value(); + auto const [event, next] = getNext(); return std::visit(functional::Overload{ [](std::integral auto const value) { return boost::numeric_cast(value); }, [](auto const value) -> Interger { throw Exception("Unable to convert to integral representation"); } @@ -153,8 +139,7 @@ class MORPHEUSCORE_EXPORT JsonReader template Float read() { - auto const state = currentState(); - auto const [event, next] = state.value(); + auto const [event, next] = getNext(); return std::visit(functional::Overload { [](std::integral auto const value) { return boost::numeric_cast(value); }, [](std::floating_point auto const value) @@ -177,8 +162,7 @@ class MORPHEUSCORE_EXPORT JsonReader requires std::is_same_v T read() { - auto const state = currentState(); - auto const [event, next] = state.value(); + auto const [event, next] = getNext(); MORPHEUS_ASSERT(next->index() == magic_enum::enum_integer(FundamentalType::String)); return std::get(*next); } @@ -203,37 +187,14 @@ class MORPHEUSCORE_EXPORT JsonReader using EventValue = std::tuple; [[nodiscard]] EventValue getNext(); - - /* [[nodiscard]] auto currentState() - { - return ScopedAction( - // [&]() { return getCurrent(); }, - // [&]() { clearCurrent(); } - [&]() - { - if (!mCurrent) mCurrent = getNext(); - return *mCurrent; - }, - [&]() { mCurrent.reset(); } - ); - }*/ - - /* - EventValue& getCurrent() - { - if (!mCurrent) - mCurrent = getNext(); - return *mCurrent; - } - void clearCurrent() { mCurrent.reset(); } - */ + void repeatCurrent(); memory::polymorphic_value mSourceStream; /// Owned input stream containing the Json source. rapidjson::IStreamWrapper mStream; rapidjson::Reader mJsonReader; std::unique_ptr mExtractor; bool mValidate = true; - std::optional mCurrent; + bool mRepeat = false; }; } // namespace morpheus::serialisation \ No newline at end of file diff --git a/libraries/core/tests/serialisation/json_reader.tests.cpp b/libraries/core/tests/serialisation/json_reader.tests.cpp index a4a53f0a..e597a8a8 100644 --- a/libraries/core/tests/serialisation/json_reader.tests.cpp +++ b/libraries/core/tests/serialisation/json_reader.tests.cpp @@ -1,6 +1,7 @@ #include "morpheus/core/conformance/format.hpp" #include "morpheus/core/conformance/ranges.hpp" #include "morpheus/core/serialisation/adapters/aggregate.hpp" +#include "morpheus/core/serialisation/adapters/std/list.hpp" #include "morpheus/core/serialisation/adapters/std/monostate.hpp" #include "morpheus/core/serialisation/adapters/std/optional.hpp" #include "morpheus/core/serialisation/adapters/std/pair.hpp" @@ -99,7 +100,7 @@ TEST_CASE("Create and then copy a reader and read from the copied stream", "[mor } } -TEST_CASE("Json reader providess basic reader functionality", "[morpheus.serialisation.json_reader.fundamental]") +TEST_CASE("Json reader provides basic reader functionality", "[morpheus.serialisation.json_reader.fundamental]") { GIVEN("A Json stream") { @@ -237,7 +238,7 @@ TEST_CASE("Json reader can read simple composite types from underlying test repr } } -TEST_CASE("Json reader can read std types from underlying text representation", "[morpheus.serialisation.json_reader.read_sequence]") +TEST_CASE("Json reader can read sequence types from underlying text representation", "[morpheus.serialisation.json_reader.read_sequence]") { using namespace std::string_literals; std::vector const expectedValues{ 0,1,2,3,4,5 }; @@ -323,6 +324,7 @@ TEST_CASE("Json reader thows an error on invalid json input", "[morpheus.seriali TEST_CASE("Json reader can read std types from underlying text representation", "[morpheus.serialisation.json_reader.adapters.std]") { + REQUIRE(test::deserialise>(R"([1, 2, 3, 4, 5])") == std::list{1, 2, 3, 4, 5}); REQUIRE(test::deserialise(R"({})") == std::monostate{}); REQUIRE(test::deserialise>(R"(100)") == std::optional{100}); REQUIRE(test::deserialise>(R"(null)") == std::optional{}); @@ -330,6 +332,7 @@ TEST_CASE("Json reader can read std types from underlying text representation", REQUIRE(test::deserialise>(R"([75,true,"Example"])") == std::tuple{75, true, "Example"}); // REQUIRE(test::deserialise>(R"({"type":"bool","value":true})") == std::variant{true}); REQUIRE(*test::deserialise>(R"(50)") == 50); + REQUIRE(test::deserialise>(R"([1, 2, 3, 4, 5])") == std::vector{1, 2, 3, 4, 5}); } TEST_CASE("Error handling test cases for unexpected errors in the input Json stream", "[morpheus.serialisation.json_reader.error_handling]") From 8d83efd95fd57f8137b1adf023c85ff7bd098051 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sun, 16 Jul 2023 18:23:52 +0100 Subject: [PATCH 17/21] Enable debugging on the CI --- .github/workflows/cmake.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index b025007b..23c0b1eb 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -183,6 +183,13 @@ jobs: # Build your program with the given configuration run: cmake --build "${{github.workspace}}/build" --config ${{ matrix.configuration }} + - uses: lhotari/action-upterm@v1 + with: + ## limits ssh access and adds the ssh public key for the user which triggered the workflow + limit-access-to-actor: true + ## limits ssh access and adds the ssh public keys of the listed GitHub users + limit-access-to-users: twon + - name: Test working-directory: ${{github.workspace}}/build # Execute tests defined by the CMake configuration. From 39e820376eaa603f73c6e36e0fbb1418772ffb1f Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Fri, 11 Aug 2023 15:17:10 +0100 Subject: [PATCH 18/21] Merge fix --- .github/workflows/cmake.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 0216e528..85552ec9 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -217,22 +217,7 @@ jobs: run: | cmake --build --preset ${{ env.CONAN_PRESET }} -<<<<<<< HEAD - name: Test # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest --preset ${{ env.CONAN_PRESET }} -LE GPU # Exclude GPU tests as Github actions do not have the supported hardware/drivers -======= - - uses: lhotari/action-upterm@v1 - with: - ## limits ssh access and adds the ssh public key for the user which triggered the workflow - limit-access-to-actor: true - ## limits ssh access and adds the ssh public keys of the listed GitHub users - limit-access-to-users: twon - - - name: Test - working-directory: ${{github.workspace}}/build - # Execute tests defined by the CMake configuration. - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest -C ${{ matrix.configuration }} ->>>>>>> c13ad2772ed11db14f4c0e6f92c2aa9d42514aa2 From 93e45413d45ff35bbfbf9d07d7e8a838576e5c71 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Mon, 21 Aug 2023 09:23:31 +0100 Subject: [PATCH 19/21] work in progress changes for range deserialisation tests --- CMakeLists.txt | 3 + conanfile.py | 29 +++++-- .../adapters/std/ranges.tests.cpp | 81 +++++++------------ 3 files changed, 53 insertions(+), 60 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e75c277f..2213e769 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,11 @@ include(CTest) include(FetchContent) include(GNUInstallDirs) include(CMakeDependentOption) + include(CMakePackageConfigHelpers) +option(MORPHEUS_ENABLE_TESTS "Build Morpheus tests" OFF) +option(MORPHEUS_ENABLE_EXAMPLES "Build Morpheus examples" OFF) cmake_dependent_option(MORPHEUS_CODE_COVERAGE "Enable code coverage" ON "\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"Clang\" OR \"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"GNU\"" OFF) cmake_dependent_option(MORPHEUS_INCLUDE_NATVIS "Enable inclusion of a natvis files for debugging" ON "\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"MSVC\"" OFF) diff --git a/conanfile.py b/conanfile.py index 1cd5196b..3507dbab 100644 --- a/conanfile.py +++ b/conanfile.py @@ -22,7 +22,7 @@ from conan import ConanFile from conan.errors import ConanException, ConanInvalidConfiguration from conan.tools.build import check_min_cppstd -from conan.tools.cmake import cmake_layout, CMake, CMakeDeps +from conan.tools.cmake import cmake_layout, CMake, CMakeDeps, CMakeToolchain from conan.tools.files import copy from conan.tools.scm import Version from conan.tools.files import load @@ -56,22 +56,23 @@ class Morpheus(ConanFile): "shared": [True, False], "fPIC": [True, False], "tools": [True, False], - "build_docs": [True, False] + "build_docs": [True, False], + "build_tests": [True, False] } default_options = { "shared": False, "fPIC": True, "tools": True, - "build_docs": False + "build_docs": False, + "build_tests": True } exports_sources = ["CMakeLists.txt", "LICENSE", "version.txt", "cmake/*", "examples/*" "libraries/*"] - generators = "CMakeDeps", "CMakeToolchain" + #generators = "CMakeDeps", "CMakeToolchain" requires = ( "boost/1.82.0", "fmt/[^10]", "glbinding/3.1.0", "glew/2.2.0", - "gtest/1.13.0", "magic_enum/0.8.2", "ms-gsl/4.0.0", "rapidjson/cci.20220822", @@ -92,7 +93,12 @@ def set_version(self): def build_requirements(self): self.tool_requires("ninja/1.11.1") - self.test_requires("catch2/3.3.2") + + if self.options.build_tests: + self.test_requires("gtest/1.13.0") + #self.test_requires("rapidcheck/cci.20220514", options={'enable_catch':'True'}) + #self.requires("catch2/3.3.2", override=True, test=True) # Should be 'test_requires' but that does not allow override which we need for catch2. + self.test_requires("catch2/3.3.2") if get_cmake_version() < Version("3.27.0"): self.tool_requires("cmake/3.27.0") @@ -128,7 +134,7 @@ def _minimum_compilers_version(self): "apple-clang": "13" } - def configure(self): + def validate(self): if self.settings.compiler.get_safe("cppstd"): check_min_cppstd(self, self._minimum_cpp_standard) min_version = self._minimum_compilers_version.get( @@ -145,6 +151,15 @@ def configure(self): self.name, self._minimum_cpp_standard, self.settings.compiler, self.settings.compiler.version)) + + def generate(self): + tc = CMakeToolchain(self) + tc.variables["MORPHEUS_ENABLE_TESTS"] = self.options.build_tests + tc.variables["MORPHEUS_BUILD_DOCUMENTATION"] = self.options.build_docs + tc.generate() + + tc = CMakeDeps(self) + tc.generate() # def generate(self): # tc = CMakeToolchain(self, generator=os.getenv("CONAN_CMAKE_GENERATOR")) diff --git a/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp b/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp index a53c4365..4cf00950 100644 --- a/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp +++ b/libraries/core/tests/serialisation/adapters/std/ranges.tests.cpp @@ -1,5 +1,6 @@ -#include "morpheus/core/meta/concepts/string.hpp" + #include "morpheus/core/conformance/ranges.hpp" +#include "morpheus/core/meta/concepts/string.hpp" #include "morpheus/core/serialisation/adapters/std/array.hpp" #include "morpheus/core/serialisation/adapters/std/deque.hpp" #include "morpheus/core/serialisation/adapters/std/forward_list.hpp" @@ -14,9 +15,10 @@ #include #include +// #include -#include #include +#include #include #include #include @@ -30,8 +32,6 @@ using namespace std::literals::string_view_literals; TEST_CASE("Verify serialisation of ranges", "[morpheus.serialisation.ranges]") { STATIC_REQUIRE(detail::IsRange>); -// STATIC_REQUIRE(detail::IsRange); -// STATIC_REQUIRE(meta::IsString); STATIC_REQUIRE(meta::IsStringView); } @@ -40,18 +40,17 @@ TEMPLATE_TEST_CASE("Verify serialisation of sequence containers std::ranges", "[ { GIVEN("A range of values") { - TestType container([] - { - std::initializer_list const values = {1, 2, 3, 4, 5}; - if constexpr (std::is_constructible_v) + TestType container( + [] { - return values; - } - else - { - return TestType{1, 2, 3, 4, 5}; - } - }()); + std::initializer_list const values = {1, 2, 3, 4, 5}; + if constexpr (std::is_constructible_v) { + return values; + } + else { + return TestType{1, 2, 3, 4, 5}; + } + }()); THEN("Expect the following sequence of operations on the underlying writer") { @@ -67,57 +66,33 @@ TEMPLATE_TEST_CASE("Verify serialisation of sequence containers std::ranges", "[ } /* -TEST_CASE("Verify deserialisation of std::ranges", "[morpheus.serialisation.ranges.deserialise]") +TEMPLATE_TEST_CASE("Verify deserialisation of std::ranges", "[morpheus.serialisation.ranges.deserialise]", std::deque, std::list, std::set, + std::unordered_set, std::vector) { - GIVEN("Expected contents of a std::expected holding a value") + GIVEN("Expected contents of a given range to be deserialised") { - constexpr std::int64_t actualValue = 10; + std::vector const range{1, 2, 3, 4, 5}; THEN("Expect the following sequence of operations on the underlying writer") { InSequence seq; MockedReadSerialiser serialiser; - EXPECT_CALL(serialiser.reader(), beginComposite()).Times(1); - EXPECT_CALL(serialiser.reader(), beginValue("state"sv)).Times(1); - EXPECT_CALL(serialiser.reader(), read(An())).WillOnce(Return(true)); - EXPECT_CALL(serialiser.reader(), endValue()).Times(1); - EXPECT_CALL(serialiser.reader(), beginValue("value"sv)).Times(1); - EXPECT_CALL(serialiser.reader(), read(An())).WillOnce(Return(actualValue)); - EXPECT_CALL(serialiser.reader(), endValue()).Times(1); - EXPECT_CALL(serialiser.reader(), endComposite()).Times(1); - WHEN("Serialising the std::expected") - { - using ExpectedType = exp_ns::expected; - auto const expected = serialiser.deserialise(); - REQUIRE(expected.value() == actualValue); + EXPECT_CALL(serialiser.reader(), beginSequence()).Times(1); + for (auto const& value : range) { + EXPECT_CALL(serialiser.reader(), beginValue("value"sv)).Times(1); + EXPECT_CALL(serialiser.reader(), read(An())).WillOnce(Return(value)); + EXPECT_CALL(serialiser.reader(), endValue()).Times(1); } - } - } - GIVEN("Expected contents of a std::expected holding an error") - { - std::string const actualValue = "This string is an error"; - - THEN("Expect the following sequence of operations on the underlying writer") - { - InSequence seq; - MockedReadSerialiser serialiser; - EXPECT_CALL(serialiser.reader(), beginComposite()).Times(1); - EXPECT_CALL(serialiser.reader(), beginValue("state"sv)).Times(1); - EXPECT_CALL(serialiser.reader(), read(An())).WillOnce(Return(false)); - EXPECT_CALL(serialiser.reader(), endValue()).Times(1); - EXPECT_CALL(serialiser.reader(), beginValue("error"sv)).Times(1); - EXPECT_CALL(serialiser.reader(), read(An())).WillOnce(Return(actualValue)); - EXPECT_CALL(serialiser.reader(), endValue()).Times(1); - EXPECT_CALL(serialiser.reader(), endComposite()).Times(1); + EXPECT_CALL(serialiser.reader(), endSequence()).Times(1); - WHEN("Deserialising the std::expected") + WHEN("Serialising the std::expected") { - using ExpectedType = exp_ns::expected; - auto const expected = serialiser.deserialise(); - REQUIRE(expected.error() == actualValue); + auto const expected = serialiser.deserialise(); + REQUIRE(expected == TestType(range.begin(), range.end())); } } } } */ + } // namespace morpheus::serialisation From b5bdc43fa7ec08b1cd63cd9578b915075f583708 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Mon, 21 Aug 2023 10:11:23 +0100 Subject: [PATCH 20/21] Reader need sequence support --- .../mocking/morpheus/core/serialisation/mock/reader.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/core/mocking/morpheus/core/serialisation/mock/reader.hpp b/libraries/core/mocking/morpheus/core/serialisation/mock/reader.hpp index 21581d8b..0827f422 100644 --- a/libraries/core/mocking/morpheus/core/serialisation/mock/reader.hpp +++ b/libraries/core/mocking/morpheus/core/serialisation/mock/reader.hpp @@ -77,6 +77,14 @@ class Reader { return read(T{}); } + + /* template + T readSequence() + requires requires(Reader r) { r.read(T{}); } + { + return read(T{}); + } + */ }; } // namespace morpheus::serialisation::mock \ No newline at end of file From 075b4c77ebbed1355333bca2fa087ab6e33be471 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Wed, 13 Sep 2023 17:58:55 +0100 Subject: [PATCH 21/21] Span of bytes is also a native type --- .../serialisation/adapters/std/CMakeLists.txt | 2 ++ .../core/serialisation/adapters/std/span.hpp | 17 +++++++++++++++++ .../core/serialisation/adapters/std/vector.hpp | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 libraries/core/src/morpheus/core/serialisation/adapters/std/span.hpp diff --git a/libraries/core/src/morpheus/core/serialisation/adapters/std/CMakeLists.txt b/libraries/core/src/morpheus/core/serialisation/adapters/std/CMakeLists.txt index 40e8f080..782dca6e 100644 --- a/libraries/core/src/morpheus/core/serialisation/adapters/std/CMakeLists.txt +++ b/libraries/core/src/morpheus/core/serialisation/adapters/std/CMakeLists.txt @@ -1,6 +1,7 @@ target_sources(MorpheusCore PUBLIC array.hpp + chrono.hpp deque.hpp expected.hpp forward_list.hpp @@ -12,6 +13,7 @@ target_sources(MorpheusCore ranges.hpp set.hpp source_location.hpp + span.hpp tuple.hpp unique_ptr.hpp unordered_set.hpp diff --git a/libraries/core/src/morpheus/core/serialisation/adapters/std/span.hpp b/libraries/core/src/morpheus/core/serialisation/adapters/std/span.hpp new file mode 100644 index 00000000..e316afcb --- /dev/null +++ b/libraries/core/src/morpheus/core/serialisation/adapters/std/span.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "morpheus/core/serialisation/adapters/std/ranges.hpp" + +#include + +namespace morpheus::serialisation::detail +{ + +template +inline constexpr bool isEnabledForRangeSerialisation> = true; + +/// std::span is handled by the native interface. +template <> +inline constexpr bool isEnabledForRangeSerialisation> = false; + +} // namespace morpheus::serialisation::detail diff --git a/libraries/core/src/morpheus/core/serialisation/adapters/std/vector.hpp b/libraries/core/src/morpheus/core/serialisation/adapters/std/vector.hpp index 5973c371..5aa9dd28 100644 --- a/libraries/core/src/morpheus/core/serialisation/adapters/std/vector.hpp +++ b/libraries/core/src/morpheus/core/serialisation/adapters/std/vector.hpp @@ -10,7 +10,7 @@ namespace morpheus::serialisation::detail template inline constexpr bool isEnabledForRangeSerialisation> = true; -// std::vector> is handles by the native interface. +/// std::vector> is handled by the native interface. template <> inline constexpr bool isEnabledForRangeSerialisation> = false;