Skip to content

Commit

Permalink
Merge pull request #286 from qicosmos/dynamic_reflection
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos authored Jun 22, 2024
2 parents 90e9f4a + e0a65fd commit 1d774ee
Show file tree
Hide file tree
Showing 22 changed files with 479 additions and 171 deletions.
1 change: 1 addition & 0 deletions benchmark/pb_benchmark.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <google/protobuf/arena.h>
#define SEQUENTIAL_PARSE
#include "../test/proto/unittest_proto3.h"
#include "iguana/iguana.hpp"

class ScopedTimer {
public:
Expand Down
7 changes: 7 additions & 0 deletions iguana/detail/pb_type.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <type_traits>

namespace iguana {

Expand Down Expand Up @@ -87,6 +88,12 @@ inline bool operator<(const sfixed64_t& lhs, const sfixed64_t& rhs) {
return lhs.val < rhs.val;
}

template <typename Type, typename T = std::decay_t<Type>>
constexpr bool is_pb_type_v =
std::is_same_v<sint32_t, T> || std::is_same_v<sint64_t, T> ||
std::is_same_v<fixed32_t, T> || std::is_same_v<fixed64_t, T> ||
std::is_same_v<sfixed32_t, T> || std::is_same_v<sfixed64_t, T>;

} // namespace iguana

// for key in std::unordered_map
Expand Down
143 changes: 143 additions & 0 deletions iguana/dynamic.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#pragma once
#include "reflection.hpp"

namespace iguana {
using base = detail::base;

template <typename T, typename U>
IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) {
return (char*)&(t->*member) - (char*)t;
}

constexpr inline uint8_t ENABLE_JSON = 0x01;
constexpr inline uint8_t ENABLE_YAML = 0x02;
constexpr inline uint8_t ENABLE_XML = 0x04;
constexpr inline uint8_t ENABLE_PB = 0x08;
constexpr inline uint8_t ENABLE_ALL = 0x0F;

template <typename T, uint8_t ENABLE_FLAG = ENABLE_PB>
struct base_impl : public base {
void to_pb(std::string& str) override {
if constexpr (ENABLE_FLAG & ENABLE_PB) {
to_pb_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
throw std::runtime_error("Protobuf Disabled");
}
}

void from_pb(std::string_view str) override {
if constexpr (ENABLE_FLAG & ENABLE_PB) {
from_pb_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
throw std::runtime_error("Protobuf Disabled");
}
}

void to_json(std::string& str) override {
if constexpr (ENABLE_FLAG & ENABLE_JSON) {
to_json_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
throw std::runtime_error("Json Disabled");
}
}

void from_json(std::string_view str) override {
if constexpr (ENABLE_FLAG & ENABLE_JSON) {
from_json_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
throw std::runtime_error("Json Disabled");
}
}

void to_xml(std::string& str) override {
if constexpr (ENABLE_FLAG & ENABLE_XML) {
to_xml_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
throw std::runtime_error("Xml Disabled");
}
}

void from_xml(std::string_view str) override {
if constexpr (ENABLE_FLAG & ENABLE_XML) {
from_xml_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
throw std::runtime_error("Xml Disabled");
}
}

void to_yaml(std::string& str) override {
if constexpr (ENABLE_FLAG & ENABLE_YAML) {
to_yaml_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
throw std::runtime_error("Yaml Disabled");
}
}

void from_yaml(std::string_view str) override {
if constexpr (ENABLE_FLAG & ENABLE_YAML) {
from_yaml_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
throw std::runtime_error("Yaml Disabled");
}
}

iguana::detail::field_info get_field_info(std::string_view name) override {
static constexpr auto map = iguana::get_members<T>();
iguana::detail::field_info info{};
for (auto& [no, field] : map) {
if (info.offset > 0) {
break;
}
std::visit(
[&](auto val) {
if (val.field_name == name) {
info.offset = member_offset((T*)this, val.member_ptr);
using value_type = typename decltype(val)::value_type;
#if defined(__clang__) || defined(_MSC_VER) || \
(defined(__GNUC__) && __GNUC__ > 8)
info.type_name = type_string<value_type>();
#endif
}
},
field);
}

return info;
}

std::vector<std::string_view> get_fields_name() override {
static constexpr auto map = iguana::get_members<T>();
std::vector<std::string_view> vec;
for (auto [no, val] : map) {
std::visit(
[&](auto& field) {
vec.push_back(std::string_view(field.field_name.data(),
field.field_name.size()));
},
val);
}
return vec;
}

virtual ~base_impl() {}

size_t cache_size = 0;
};

IGUANA_INLINE std::shared_ptr<base> create_instance(std::string_view name) {
auto it = iguana::detail::g_pb_map.find(name);
if (it == iguana::detail::g_pb_map.end()) {
throw std::invalid_argument(std::string(name) +
"not inheried from iguana::base_impl");
}
return it->second();
}
} // namespace iguana
10 changes: 10 additions & 0 deletions iguana/iguana.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once
#include "iguana/dynamic.hpp"
#include "iguana/json_reader.hpp"
#include "iguana/json_writer.hpp"
#include "iguana/pb_reader.hpp"
#include "iguana/pb_writer.hpp"
#include "iguana/xml_reader.hpp"
#include "iguana/xml_writer.hpp"
#include "iguana/yaml_reader.hpp"
#include "iguana/yaml_writer.hpp"
11 changes: 11 additions & 0 deletions iguana/json_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) {
}
}

template <typename U, typename It, std::enable_if_t<is_pb_type_v<U>, int> = 0>
IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) {
from_json_impl(value.val, it, end);
}

template <typename U, typename It, std::enable_if_t<numeric_str_v<U>, int> = 0>
IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) {
skip_ws(it, end);
Expand Down Expand Up @@ -899,4 +904,10 @@ IGUANA_INLINE void from_json_file(T &value, const std::string &filename,
}
}

template <typename T>
IGUANA_INLINE void from_json_adl(iguana_adl_t *p, T &t,
std::string_view pb_str) {
iguana::from_json(t, pb_str);
}

} // namespace iguana
1 change: 1 addition & 0 deletions iguana/json_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "detail/pb_type.hpp"
#include "util.hpp"
#include "value.hpp"

Expand Down
23 changes: 20 additions & 3 deletions iguana/json_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ template <bool Is_writing_escape = true, typename Stream, typename T,
IGUANA_INLINE void to_json(T &&t, Stream &s);
namespace detail {
template <bool Is_writing_escape = true, typename Stream, typename T>
IGUANA_INLINE void to_json_impl(Stream &ss, std::optional<T> &val);
IGUANA_INLINE void to_json_impl(Stream &ss, const std::optional<T> &val);

template <bool Is_writing_escape = true, typename Stream, typename T,
std::enable_if_t<fixed_array_v<T>, int> = 0>
Expand Down Expand Up @@ -76,6 +76,12 @@ IGUANA_INLINE void to_json_impl(Stream &ss, T value) {
ss.append(temp, p - temp);
}

template <bool Is_writing_escape, typename Stream, typename T,
std::enable_if_t<is_pb_type_v<T>, int> = 0>
IGUANA_INLINE void to_json_impl(Stream &ss, T value) {
to_json_impl<Is_writing_escape>(ss, value.val);
}

template <bool Is_writing_escape, typename Stream, typename T,
std::enable_if_t<numeric_str_v<T>, int> = 0>
IGUANA_INLINE void to_json_impl(Stream &ss, T v) {
Expand All @@ -97,12 +103,18 @@ IGUANA_INLINE void to_json_impl(Stream &ss, T &&t) {

template <bool Is_writing_escape, typename Stream, typename T,
std::enable_if_t<num_v<T>, int> = 0>
IGUANA_INLINE void render_key(Stream &ss, T &t) {
IGUANA_INLINE void render_key(Stream &ss, const T &t) {
ss.push_back('"');
to_json_impl<Is_writing_escape>(ss, t);
ss.push_back('"');
}

template <bool Is_writing_escape, typename Stream, typename T,
std::enable_if_t<is_pb_type_v<T>, int> = 0>
IGUANA_INLINE void render_key(Stream &ss, const T &t) {
render_key<Is_writing_escape>(ss, t.val);
}

template <bool Is_writing_escape, typename Stream, typename T,
std::enable_if_t<string_container_v<T>, int> = 0>
IGUANA_INLINE void render_key(Stream &ss, T &&t) {
Expand Down Expand Up @@ -140,7 +152,7 @@ IGUANA_INLINE void to_json_impl(Stream &ss, T val) {
}

template <bool Is_writing_escape, typename Stream, typename T>
IGUANA_INLINE void to_json_impl(Stream &ss, std::optional<T> &val) {
IGUANA_INLINE void to_json_impl(Stream &ss, const std::optional<T> &val) {
if (!val) {
ss.append("null");
}
Expand Down Expand Up @@ -282,5 +294,10 @@ IGUANA_INLINE void to_json(T &&t, Stream &s) {
to_json_impl<Is_writing_escape>(s, t);
}

template <typename T>
IGUANA_INLINE void to_json_adl(iguana_adl_t *p, T &t, std::string &pb_str) {
to_json(t, pb_str);
}

} // namespace iguana
#endif // SERIALIZE_JSON_HPP
8 changes: 7 additions & 1 deletion iguana/pb_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
#include "pb_util.hpp"

namespace iguana {

template <typename T>
IGUANA_INLINE void from_pb(T& t, std::string_view pb_str);
namespace detail {

template <typename T>
Expand Down Expand Up @@ -254,4 +255,9 @@ IGUANA_INLINE void from_pb(T& t, std::string_view pb_str) {
}
}
}

template <typename T>
IGUANA_INLINE void from_pb_adl(iguana_adl_t* p, T& t, std::string_view pb_str) {
iguana::from_pb(t, pb_str);
}
} // namespace iguana
77 changes: 1 addition & 76 deletions iguana/pb_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,83 +29,8 @@ enum class WireType : uint32_t {
Unknown
};

template <typename T, typename Stream>
IGUANA_INLINE void to_pb(T& t, Stream& out);

template <typename T>
IGUANA_INLINE void from_pb(T& t, std::string_view pb_str);

using base = detail::base;

template <typename T, typename U>
IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) {
return (char*)&(t->*member) - (char*)t;
}

template <typename T>
struct base_impl : public base {
void to_pb(std::string& str) override {
iguana::to_pb(*(static_cast<T*>(this)), str);
}

void from_pb(std::string_view str) override {
iguana::from_pb(*(static_cast<T*>(this)), str);
}

iguana::detail::field_info get_field_info(std::string_view name) override {
static constexpr auto map = iguana::get_members<T>();
iguana::detail::field_info info{};
for (auto [no, field] : map) {
if (info.offset > 0) {
break;
}
std::visit(
[&](auto val) {
if (val.field_name == name) {
info.offset = member_offset((T*)this, val.member_ptr);
using value_type = typename decltype(val)::value_type;
#if defined(__clang__) || defined(_MSC_VER) || \
(defined(__GNUC__) && __GNUC__ > 8)
info.type_name = type_string<value_type>();
#endif
}
},
field);
}

return info;
}

std::vector<std::string_view> get_fields_name() override {
static constexpr auto map = iguana::get_members<T>();
std::vector<std::string_view> vec;
for (auto [no, val] : map) {
std::visit(
[&](auto& field) {
vec.push_back(std::string_view(field.field_name.data(),
field.field_name.size()));
},
val);
}
return vec;
}

virtual ~base_impl() {}

size_t cache_size = 0;
};

template <typename T>
constexpr bool inherits_from_base_v = std::is_base_of_v<base, T>;

IGUANA_INLINE std::shared_ptr<base> create_instance(std::string_view name) {
auto it = iguana::detail::g_pb_map.find(name);
if (it == iguana::detail::g_pb_map.end()) {
throw std::invalid_argument(std::string(name) +
"not inheried from iguana::base_impl");
}
return it->second();
}
constexpr bool inherits_from_base_v = std::is_base_of_v<detail::base, T>;

namespace detail {
template <typename T>
Expand Down
5 changes: 5 additions & 0 deletions iguana/pb_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,9 @@ IGUANA_INLINE void to_pb(T& t, Stream& out) {
detail::to_pb_impl<0>(t, &out[0], sz_ptr);
}

template <typename T, typename Stream>
IGUANA_INLINE void to_pb_adl(iguana_adl_t* p, T& t, Stream& out) {
to_pb(t, out);
}

} // namespace iguana
Loading

0 comments on commit 1d774ee

Please sign in to comment.