jsoncpp
jsoncpp copied to clipboard
Serialization
Hello, it's the first time I create an issue under an opensource.
We use jsoncpp 0.5.0 version as a third lib. Recently I realize json to struct function base on jsoncpp's Json::Value.
Here is my serializer.h.
namespace Json {
template <typename T, T... S, typename F>
constexpr void for_sequence(std::integer_sequence<T, S...>, F&& f) {
using unpack_t = int[];
(void)unpack_t{(static_cast<void>(f(std::integral_constant<T, S>{})), 0)..., 0};
}
template<typename Class, typename T>
struct PropertyImpl {
constexpr PropertyImpl(T Class::*aMember, const char* aName) : member{aMember}, name{aName} {}
using Type = T;
T Class::*member;
const char* name;
};
template<typename Class, typename T>
constexpr auto property(T Class::*member, const char* name) {
return PropertyImpl<Class, T>{member, name};
}
template<typename T>
struct PropertyTag {
typedef char yes;
typedef long no;
template <typename TT>
static auto CheckTag(int) -> decltype(std::declval<TT>().properties, yes());
template <typename TT>
static std::false_type CheckTag(...);
static constexpr bool hasProperty = std::is_same<decltype(CheckTag<T>(0)), yes>::value;
};
template<typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type = 0>
T FromJson(const Json::Value& value);
template<typename T, typename std::enable_if<!PropertyTag<T>::hasProperty, int>::type = 0>
T FromJson(const Json::Value& value) {
return T();
}
template<typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type = 0>
Json::Value ToJson(const T &object);
template<typename T, typename std::enable_if<!PropertyTag<T>::hasProperty, int>::type = 0>
Json::Value ToJson(const T &object) {
return Json::Value();
}
template<typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type = 0>
inline T asAny(const Json::Value& value) {
return FromJson<T>(value);
}
template <typename T, typename std::enable_if<!PropertyTag<T>::hasProperty, int>::type = 0>
inline T asAny(const Json::Value& value) {
return T{};
}
template<>
inline int asAny<int>(const Json::Value& value) {
return value.asInt();
}
template<>
inline std::string asAny<std::string>(const Json::Value& value) {
return value.asString();
}
template<>
inline char* asAny<char*>(const Json::Value& value) {
if (value.type() != Json::stringValue) {
return "";
}
return const_cast<char*>(value.asCString());
}
template<>
inline bool asAny<bool>(const Json::Value& value) {
return value.asBool();
}
template<>
inline double asAny<double>(const Json::Value& value) {
return value.asDouble();
}
template<>
inline float asAny<float>(const Json::Value& value) {
return value.asDouble();
}
template<>
inline uint asAny<uint>(const Json::Value& value) {
return value.asUInt();
}
template<>
inline std::vector<std::string> asAny<std::vector<std::string>>(const Json::Value& value) {
std::vector<std::string> vec;
if (value.isArray() && value.size() != 0) {
for (uint i = 0; i < value.size(); ++i) {
vec.push_back(value[i].asString());
}
}
return vec;
}
template<>
inline std::vector<int> asAny<std::vector<int>>(const Json::Value& value) {
std::vector<int> vec;
if (value.isArray() && value.size() != 0) {
for (uint i = 0; i < value.size(); ++i) {
vec.push_back(value[i].asInt());
}
}
return vec;
}
template <typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type = 0>
Json::Value convertJson(const T& object) {
return ToJson(object);
}
template <typename T, typename std::enable_if<!PropertyTag<T>::hasProperty, int>::type = 0>
Json::Value convertJson(const T &object) {
return Json::Value();
}
template<>
Json::Value convertJson<int>(const int& object) {
return Json::Value(object);
}
template<>
Json::Value convertJson<uint>(const uint& object) {
return Json::Value(object);
}
template<>
Json::Value convertJson<float>(const float& object) {
return Json::Value(object);
}
template<>
Json::Value convertJson<double>(const double& object) {
return Json::Value(object);
}
template<>
Json::Value convertJson<std::string>(const std::string& object) {
return Json::Value(object);
}
template<>
Json::Value convertJson<char*>(char* const& object) {
if (object == nullptr) {
return Json::Value("");
}
return Json::Value(object);
}
template<>
Json::Value convertJson<std::vector<std::string>>(const std::vector<std::string>& object) {
Json::Value data;
for (auto str : object) {
data.append(str);
}
return data;
}
template<>
Json::Value convertJson<std::vector<int>>(const std::vector<int>& object) {
Json::Value data;
for (auto str : object) {
data.append(str);
}
return data;
}
template<typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type>
T FromJson(const Json::Value& data) {
T object;
constexpr auto nbProperties = std::tuple_size<decltype(T::properties)>::value;
for_sequence(std::make_index_sequence<nbProperties>{}, [&](auto i){
constexpr auto property = std::get<i>(T::properties);
using Type = typename decltype(property)::Type;
if (data.isMember(property.name)) {
object.*(property.member) = std::move(asAny<Type>(data[property.name]));
}
});
return object;
}
template<typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type>
Json::Value ToJson(const T& object) {
Json::Value data;
constexpr auto nbProperties = std::tuple_size<decltype(T::properties)>::value;
for_sequence(std::make_index_sequence<nbProperties>{}, [&](auto i){
constexpr auto property = std::get<i>(T::properties);
using Type = typename decltype(property)::Type;
data[property.name] = std::move(convertJson<Type>(object.*(property.member)));
});
return data;
}
}
it bases on c++14.
I provide Json::ToJson() and Json::FromJson() two interface for serialization and deserialization.
But It just support some basic type, std::vector<std::string>, std::vector<int>, and customized struct or class.
for example, InnerS2 has tuple type member named properties. It can be serialized.
struct InnerS2 {
std::string m1;
constexpr static auto properties = std::make_tuple(
Json::property(&InnerS2::m1, "m1")
);
};
What about your ideas ? I will seriously refer to your suggestions. thx.