Skip to content

Commit

Permalink
Add support for std::optional
Browse files Browse the repository at this point in the history
  • Loading branch information
Loki-Astari committed Jun 29, 2024
1 parent b61ce22 commit eff1e51
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 7 deletions.
14 changes: 14 additions & 0 deletions src/Serialize/SerUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <memory>
#include <cstring>
#include <functional>
#include <optional>

/*
* Container Types:
Expand Down Expand Up @@ -940,6 +941,19 @@ class Traits<std::reference_wrapper<T>>
}
};

template<typename T>
class Traits<std::optional<T>>
{
public:
using RefType = T;
static constexpr TraitType type = TraitType::Reference;
static std::size_t getPrintSize(PrinterInterface& printer, std::optional<T> const& object, bool p)
{
return (object.has_value())
? Traits<std::remove_cv_t<T>>::getPrintSize(printer, object.value(), p)
: 0;
}
};
}
}

Expand Down
22 changes: 18 additions & 4 deletions src/Serialize/Serialize.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,20 @@ class SerializerForBlock<TraitType::Pointer, T>
}
}
};
template<typename T>
struct GetRefValue;

template<typename T>
struct GetRefValue<std::reference_wrapper<T>>
{
static T const& getValue(std::reference_wrapper<T> const& input) {return input.get();}
};
template<typename T>
struct GetRefValue<std::optional<T>>
{
static T const& getValue(std::optional<T> const& input) {return input.value();}
};

template<typename T>
class SerializerForBlock<TraitType::Reference, T>
{
Expand All @@ -841,7 +855,7 @@ class SerializerForBlock<TraitType::Reference, T>
void printMembers()
{
using RefType = typename Traits<std::remove_cv_t<T>>::RefType;
SerializerForBlock<Traits<std::remove_cv_t<RefType>>::type, RefType> serializer(parent, printer, object.get());
SerializerForBlock<Traits<std::remove_cv_t<RefType>>::type, RefType> serializer(parent, printer, GetRefValue<T>::getValue(object));
serializer.printMembers();
}
};
Expand Down Expand Up @@ -899,7 +913,7 @@ class SerializerForBlock<TraitType::Array, T>
template<typename T, typename M>
SerializeMemberContainer<T, M>::SerializeMemberContainer(Serializer&, PrinterInterface& printer, T const& object, std::pair<char const*, M T::*> const& memberInfo)
{
if (ThorsAnvil::Serialize::Filter<T>::filter(object, memberInfo.first))
if (ThorsAnvil::Serialize::Filter<T>::filter(object, memberInfo.first, object.*(memberInfo.second)))
{
printer.addKey(ThorsAnvil::Serialize::Override<T>::nameOverride(memberInfo.first));

Expand All @@ -911,7 +925,7 @@ SerializeMemberContainer<T, M>::SerializeMemberContainer(Serializer&, PrinterInt
template<typename T, typename M>
SerializeMemberContainer<T, M>::SerializeMemberContainer(Serializer&, PrinterInterface& printer, T const& object, std::pair<char const*, M*> const& memberInfo)
{
if (ThorsAnvil::Serialize::Filter<T>::filter(object, memberInfo.first))
if (ThorsAnvil::Serialize::Filter<T>::filter(object, memberInfo.first, *(memberInfo.second)))
{
printer.addKey(ThorsAnvil::Serialize::Override<T>::nameOverride(memberInfo.first));

Expand All @@ -935,7 +949,7 @@ SerializeMemberValue<T, M, Type>::SerializeMemberValue(Serializer& parent, Print
template<typename T, typename M, TraitType Type>
void SerializeMemberValue<T, M, Type>::init(Serializer& parent, PrinterInterface& printer, char const* member, T const& object, M const& value)
{
if (ThorsAnvil::Serialize::Filter<T>::filter(object, member))
if (ThorsAnvil::Serialize::Filter<T>::filter(object, member, value))
{
printer.addKey(ThorsAnvil::Serialize::Override<T>::nameOverride(member));
SerializerForBlock<Type, M> serializer(parent, printer, value);
Expand Down
27 changes: 24 additions & 3 deletions src/Serialize/Traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,8 @@ template<BUILDTEMPLATETYPEPARAM(THOR_TYPENAMEPARAMACTION, Count)> \
class Filter<DataType BUILDTEMPLATETYPEVALUE(THOR_TYPENAMEVALUEACTION, Count) > \
{ \
public: \
static bool filter(DataType BUILDTEMPLATETYPEVALUE(THOR_TYPENAMEVALUEACTION, Count) const& object, char const* name) \
template<typename M> \
static bool filter(DataType BUILDTEMPLATETYPEVALUE(THOR_TYPENAMEVALUEACTION, Count) const& object, char const* name, M const& /*v*/) \
{ \
auto find = object.member.find(name); \
return find == object.member.end() ? true : find->second; \
Expand Down Expand Up @@ -567,7 +568,7 @@ class Traits<DataType BUILDTEMPLATETYPEVALUE(THOR_TYPENAMEVALUEACTION, Count) >
template<typename M> \
static std::pair<std::size_t, std::size_t> addSizeEachMemberItem(PrinterInterface& printer, MyType const& object, M item) \
{ \
if (!Filter<MyType>::filter(object, item.first)) { \
if (!Filter<MyType>::filter(object, item.first, item)) { \
return std::make_pair(0UL,0UL); \
} \
auto partSize = addSizeOneMember(printer, object, item.second); \
Expand Down Expand Up @@ -928,11 +929,31 @@ class Override
static char const* nameOverride(char const* name) {return name;}
};

template<typename T>
struct IsOptional
{
static constexpr bool value = false;
};
template<typename M>
struct IsOptional<std::optional<M>>
{
static constexpr bool value = true;
};
template<typename T>
inline constexpr bool isOptional_v = IsOptional<T>::value;

template<typename T>
class Filter
{
public:
static constexpr bool filter(T const& /*object*/, char const* /*name*/) {return true;}
template<typename M>
static constexpr bool filter(T const& /*object*/, char const* /*name*/, M const& value)
{
if constexpr (isOptional_v<M>) {
return value.has_value();
}
return true;
}
};

/*
Expand Down
38 changes: 38 additions & 0 deletions src/Serialize/test/OptionalTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include "gtest/gtest.h"
#include <optional>
#include "Traits.h"
#include "JsonThor.h"


struct OptionalTest
{
int normal;
std::optional<int> optional;
};

ThorsAnvil_MakeTrait(OptionalTest, normal, optional);

using ThorsAnvil::Serialize::jsonExporter;
using ThorsAnvil::Serialize::PrinterInterface;

TEST(OptionalTest, NormalOnly)
{
std::stringstream stream;

OptionalTest data;
data.normal = 5;

stream << jsonExporter(data, PrinterInterface::PrinterConfig{PrinterInterface::OutputType::Stream});
EXPECT_EQ(R"({"normal":5})", stream.str());
}
TEST(OptionalTest, NormalAndOptional)
{
std::stringstream stream;

OptionalTest data;
data.normal = 5;
data.optional = 6;

stream << jsonExporter(data, PrinterInterface::PrinterConfig{PrinterInterface::OutputType::Stream});
EXPECT_EQ(R"({"normal":5,"optional":6})", stream.str());
}

0 comments on commit eff1e51

Please sign in to comment.