Add experimental support for multimap

Makes sense for binary (de)serialization, not sure about
JSON (de)serialization
This commit is contained in:
Martchus 2018-10-29 23:23:56 +01:00
parent f77229471a
commit d64174c000
5 changed files with 53 additions and 10 deletions

View File

@ -82,7 +82,9 @@ The following table shows the mapping of supported C++ types to supported JSON t
* custom types must provide a default constructor.
* constant member variables are skipped.
* It is possible to treat custom types as set/map using the macro `REFLECTIVE_RAPIDJSON_TREAT_AS_MAP_OR_HASH`,
`REFLECTIVE_RAPIDJSON_TREAT_AS_SET` or `REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_SET`.
`REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_MAP_OR_HASH`, `REFLECTIVE_RAPIDJSON_TREAT_AS_SET` or
`REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_SET`.
* The key type of the `std::map`, `std::unordered_map` must be `std::string`.
* For custom (de)serialization, see the section below.
* The binary (de)serializer supports approximately the same C++ types but obviously maps them to a platform
independent binary representation rather than a JSON type.

View File

@ -58,10 +58,10 @@ public:
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>> * = nullptr> void read(Type &pair);
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> * = nullptr> void read(Type &pair);
template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsResizable<Type>> * = nullptr> void read(Type &iteratable);
template <typename Type, Traits::EnableIf<IsMapOrHash<Type>> * = nullptr> void read(Type &iteratable);
template <typename Type, Traits::EnableIfAny<IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr> void read(Type &iteratable);
template <typename Type,
Traits::EnableIf<IsIteratableExceptString<Type>, Traits::None<IsMapOrHash<Type>, Traits::All<IsArray<Type>, Traits::IsResizable<Type>>>>
* = nullptr>
Traits::EnableIf<IsIteratableExceptString<Type>,
Traits::None<IsMapOrHash<Type>, IsMultiMapOrHash<Type>, Traits::All<IsArray<Type>, Traits::IsResizable<Type>>>> * = nullptr>
void read(Type &iteratable);
template <typename Type, Traits::EnableIf<std::is_enum<Type>> * = nullptr> void read(Type &customType);
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr> void read(Type &customType);
@ -138,7 +138,7 @@ template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsResizable<Typ
}
}
template <typename Type, Traits::EnableIf<IsMapOrHash<Type>> *> void BinaryDeserializer::read(Type &iteratable)
template <typename Type, Traits::EnableIfAny<IsMapOrHash<Type>, IsMultiMapOrHash<Type>> *> void BinaryDeserializer::read(Type &iteratable)
{
const auto size = readVariableLengthUIntBE();
for (size_t i = 0; i != size; ++i) {
@ -149,7 +149,8 @@ template <typename Type, Traits::EnableIf<IsMapOrHash<Type>> *> void BinaryDeser
}
template <typename Type,
Traits::EnableIf<IsIteratableExceptString<Type>, Traits::None<IsMapOrHash<Type>, Traits::All<IsArray<Type>, Traits::IsResizable<Type>>>> *>
Traits::EnableIf<IsIteratableExceptString<Type>,
Traits::None<IsMapOrHash<Type>, IsMultiMapOrHash<Type>, Traits::All<IsArray<Type>, Traits::IsResizable<Type>>>> *>
void BinaryDeserializer::read(Type &iteratable)
{
const auto size = readVariableLengthUIntBE();

View File

@ -211,9 +211,10 @@ void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_
}
/*!
* \brief Pushes the specified map (std::map, std::unordered_map) to the specified value.
* \brief Pushes the specified map (std::map, std::unordered_map) or multimap (std::multimap, std::unordered_multimap) to the
* specified value.
*/
template <typename Type, Traits::EnableIf<IsMapOrHash<Type>> * = nullptr>
template <typename Type, Traits::EnableIfAny<IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr>
void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
{
value.SetObject();
@ -371,6 +372,12 @@ void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<c
template <typename Type, Traits::EnableIf<IsMapOrHash<Type>> * = nullptr>
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
/*!
* \brief Pulls the specified \a reflectable which is a multimap from the specified value which is checked to contain an object.
*/
template <typename Type, Traits::EnableIf<IsMultiMapOrHash<Type>> * = nullptr>
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
/*!
* \brief Pulls the specified \a reflectable which is a tuple from the specified value which is checked to contain an array.
*/
@ -628,6 +635,25 @@ void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::
}
}
/*!
* \brief Pulls the specified \a reflectable which is a multimap from the specified value which is checked to contain an object.
*/
template <typename Type, Traits::EnableIf<IsMultiMapOrHash<Type>> *>
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
{
if (!value.IsObject()) {
if (errors) {
errors->reportTypeMismatch<Type>(value.GetType());
}
return;
}
auto obj = value.GetObject();
for (auto i = obj.MemberBegin(), end = obj.MemberEnd(); i != end; ++i) {
auto insertedIterator = reflectable.insert(typename Type::value_type(i->name.GetString(), typename Type::mapped_type()));
pull(insertedIterator->second, i->value, errors);
}
}
namespace Detail {
/*!
@ -762,7 +788,7 @@ void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_N
/*!
* \brief Serializes the specified \a reflectable which has a custom type or can be mapped to and object.
*/
template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>> * = nullptr>
template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr>
RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
{
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
@ -819,7 +845,7 @@ template <typename Type, Traits::EnableIf<IsArray<Type>> * = nullptr> RAPIDJSON_
/*!
* \brief Deserializes the specified JSON to \tparam Type which is a custom type or can be mapped to an object.
*/
template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>> * = nullptr>
template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr>
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
{
RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));

View File

@ -12,6 +12,7 @@ struct Foo {
struct Bar {
};
REFLECTIVE_RAPIDJSON_TREAT_AS_MAP_OR_HASH(Foo);
REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_MAP_OR_HASH(Foo);
REFLECTIVE_RAPIDJSON_TREAT_AS_SET(Bar);
REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_SET(Foo);
@ -37,6 +38,10 @@ static_assert(IsMapOrHash<map<string, int>>::value, "map mapped to object");
static_assert(IsMapOrHash<unordered_map<string, int>>::value, "hash mapped to object");
static_assert(!IsMapOrHash<vector<int>>::value, "vector not mapped to object");
static_assert(IsMapOrHash<Foo>::value, "Foo mapped to object via TreatAsMapOrHash");
static_assert(IsMultiMapOrHash<multimap<string, int>>::value, "multimap mapped to object");
static_assert(IsMultiMapOrHash<unordered_multimap<string, int>>::value, "unordered multimap mapped to object");
static_assert(!IsMultiMapOrHash<vector<int>>::value, "vector not mapped to object");
static_assert(IsMultiMapOrHash<Foo>::value, "Foo mapped to object via TreatAsMultiMapOrHash");
static_assert(IsIteratableExceptString<std::vector<int>>::value, "vector is iteratable");
static_assert(!IsIteratableExceptString<std::string>::value, "string not iteratable");
static_assert(!IsIteratableExceptString<std::wstring>::value, "wstring not iteratable");

View File

@ -15,6 +15,9 @@ namespace ReflectiveRapidJSON {
/// \brief \brief The TreatAsMapOrHash class allows treating custom classes as std::map or std::unordered_map.
template <typename T> struct TreatAsMapOrHash : public Traits::Bool<false> {
};
/// \brief \brief The TreatAsMultiMapOrHash class allows treating custom classes as std::multimap or std::unordered_multimap.
template <typename T> struct TreatAsMultiMapOrHash : public Traits::Bool<false> {
};
/// \brief \brief The TreatAsSet class allows treating custom classes as std::set or std::unordered_set.
template <typename T> struct TreatAsSet : public Traits::Bool<false> {
};
@ -25,6 +28,9 @@ template <typename T> struct TreatAsMultiSet : public Traits::Bool<false> {
#define REFLECTIVE_RAPIDJSON_TREAT_AS_MAP_OR_HASH(T) \
template <> struct TreatAsMapOrHash<T> : public Traits::Bool<true> { \
}
#define REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_MAP_OR_HASH(T) \
template <> struct TreatAsMultiMapOrHash<T> : public Traits::Bool<true> { \
}
#define REFLECTIVE_RAPIDJSON_TREAT_AS_SET(T) \
template <> struct TreatAsSet<T> : public Traits::Bool<true> { \
}
@ -37,6 +43,9 @@ template <typename Type>
using IsMapOrHash
= Traits::Any<Traits::IsSpecializationOf<Type, std::map>, Traits::IsSpecializationOf<Type, std::unordered_map>, TreatAsMapOrHash<Type>>;
template <typename Type>
using IsMultiMapOrHash = Traits::Any<Traits::IsSpecializationOf<Type, std::multimap>, Traits::IsSpecializationOf<Type, std::unordered_multimap>,
TreatAsMultiMapOrHash<Type>>;
template <typename Type>
using IsSet = Traits::Any<Traits::IsSpecializationOf<Type, std::set>, Traits::IsSpecializationOf<Type, std::unordered_set>, TreatAsSet<Type>>;
template <typename Type>
using IsMultiSet