Skip to content

Commit

Permalink
Merge branch 'master' of github.com:qicosmos/iguana into gsk/add_const
Browse files Browse the repository at this point in the history
  • Loading branch information
171930433 committed Jul 2, 2024
2 parents b3a4497 + c5efa3a commit 36f04f2
Show file tree
Hide file tree
Showing 6 changed files with 409 additions and 9 deletions.
16 changes: 8 additions & 8 deletions iguana/dynamic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ 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) {
if constexpr ((ENABLE_FLAG & ENABLE_PB) != 0) {
to_pb_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
Expand All @@ -27,7 +27,7 @@ struct base_impl : public base {
}

void from_pb(std::string_view str) override {
if constexpr (ENABLE_FLAG & ENABLE_PB) {
if constexpr ((ENABLE_FLAG & ENABLE_PB) != 0) {
from_pb_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
Expand All @@ -36,7 +36,7 @@ struct base_impl : public base {
}

void to_json(std::string& str) const override {
if constexpr (ENABLE_FLAG & ENABLE_JSON) {
if constexpr ((ENABLE_FLAG & ENABLE_JSON) != 0) {
to_json_adl((iguana_adl_t*)nullptr, *(static_cast<T const*>(this)), str);
}
else {
Expand All @@ -45,7 +45,7 @@ struct base_impl : public base {
}

void from_json(std::string_view str) override {
if constexpr (ENABLE_FLAG & ENABLE_JSON) {
if constexpr ((ENABLE_FLAG & ENABLE_JSON) != 0) {
from_json_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
Expand All @@ -54,7 +54,7 @@ struct base_impl : public base {
}

void to_xml(std::string& str) const override {
if constexpr (ENABLE_FLAG & ENABLE_XML) {
if constexpr ((ENABLE_FLAG & ENABLE_XML) != 0) {
to_xml_adl((iguana_adl_t*)nullptr, *(static_cast<T const*>(this)), str);
}
else {
Expand All @@ -63,7 +63,7 @@ struct base_impl : public base {
}

void from_xml(std::string_view str) override {
if constexpr (ENABLE_FLAG & ENABLE_XML) {
if constexpr ((ENABLE_FLAG & ENABLE_XML) != 0) {
from_xml_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
Expand All @@ -72,7 +72,7 @@ struct base_impl : public base {
}

void to_yaml(std::string& str) const override {
if constexpr (ENABLE_FLAG & ENABLE_YAML) {
if constexpr ((ENABLE_FLAG & ENABLE_YAML) != 0) {
to_yaml_adl((iguana_adl_t*)nullptr, *(static_cast<T const*>(this)), str);
}
else {
Expand All @@ -81,7 +81,7 @@ struct base_impl : public base {
}

void from_yaml(std::string_view str) override {
if constexpr (ENABLE_FLAG & ENABLE_YAML) {
if constexpr ((ENABLE_FLAG & ENABLE_YAML) != 0) {
from_yaml_adl((iguana_adl_t*)nullptr, *(static_cast<T*>(this)), str);
}
else {
Expand Down
274 changes: 274 additions & 0 deletions iguana/pb_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,247 @@ IGUANA_INLINE void to_pb_impl(Type&& t, It&& it, uint32_t*& sz_ptr) {
encode_numeric_field<key, omit_default_val>(t, it);
}
}

#if defined(__clang__) || defined(_MSC_VER) || \
(defined(__GNUC__) && __GNUC__ > 8)
template <typename T>
IGUANA_INLINE constexpr std::string_view get_type_string() {
if constexpr (std::is_integral_v<T>) {
if constexpr (std::is_same_v<T, bool>) {
return "bool";
}
else if constexpr (sizeof(T) <= 4) {
if constexpr (std::is_unsigned_v<T>) {
return "uint32";
}
else {
return "int32";
}
}
else {
if constexpr (std::is_unsigned_v<T>) {
return "uint64";
}
else {
return "int64";
}
}
}
else if constexpr (std::is_same_v<T, std::string> ||
std::is_same_v<T, std::string_view>) {
return "string";
}
else if constexpr (std::is_floating_point_v<T>) {
return type_string<T>();
}
else {
constexpr auto str_type_name = type_string<T>();
constexpr size_t pos = str_type_name.rfind("::");
if constexpr (pos != std::string_view::npos) {
constexpr size_t pos = str_type_name.rfind("::") + 2;
if constexpr (detail::is_signed_varint_v<T> || detail::is_fixed_v<T>) {
return str_type_name.substr(pos, str_type_name.size() - pos - 2);
}
else {
return str_type_name.substr(pos);
}
}
else {
return str_type_name;
}
}
}

template <typename T, typename Stream>
IGUANA_INLINE void numeric_to_proto(Stream& out, std::string_view field_name,
uint32_t field_no) {
constexpr auto name = get_type_string<T>();
out.append(name).append(" ");
out.append(field_name)
.append(" = ")
.append(std::to_string(field_no))
.append(";\n");
}

template <size_t space_count = 2, typename Stream>
IGUANA_INLINE void build_proto_field(Stream& out, std::string_view str_type,
std::string_view field_name,
uint32_t field_no) {
for (size_t i = 0; i < space_count; i++) {
out.append(" ");
}

if (!str_type.empty()) {
out.append(str_type);
}

out.append(" ")
.append(field_name)
.append(" = ")
.append(std::to_string(field_no))
.append(";\n");
}

template <typename T, typename Map>
IGUANA_INLINE void build_sub_proto(Map& map, std::string_view str_type,
std::string& sub_str);

template <typename Type, typename Stream>
IGUANA_INLINE void to_proto_impl(
Stream& out, std::unordered_map<std::string_view, std::string>& map,
std::string_view field_name = "", uint32_t field_no = 0) {
std::string sub_str;
using T = std::remove_const_t<std::remove_reference_t<Type>>;
if constexpr (is_reflection_v<T> || is_custom_reflection_v<T>) {
constexpr auto name = get_name<T>();
out.append("message ").append(name).append(" {\n");
static constexpr auto tuple = get_members_tuple<T>();
constexpr size_t SIZE = std::tuple_size_v<std::decay_t<decltype(tuple)>>;

for_each_n(
[&out, &sub_str, &map](auto i) mutable {
using field_type =
std::tuple_element_t<decltype(i)::value,
std::decay_t<decltype(tuple)>>;
constexpr auto value = std::get<decltype(i)::value>(tuple);

using U = typename field_type::value_type;
if constexpr (is_reflection_v<U>) {
constexpr auto str_type = get_type_string<U>();
build_proto_field(
out, str_type,
{value.field_name.data(), value.field_name.size()},
value.field_no);

build_sub_proto<U>(map, str_type, sub_str);
}
else if constexpr (variant_v<U>) {
constexpr size_t var_size = std::variant_size_v<U>;
using sub_type = typename field_type::sub_type;

constexpr auto offset =
get_variant_index<U, sub_type, var_size - 1>();

if (offset == 0) {
out.append(" oneof ");
out.append(value.field_name.data(), value.field_name.size())
.append(" {\n");
}

constexpr auto str_type = get_type_string<sub_type>();
std::string field_name = " one_of_";
field_name.append(str_type);

out.append(" ");
build_proto_field(out, str_type, field_name, value.field_no);

if constexpr (is_reflection_v<sub_type>) {
build_sub_proto<sub_type>(map, str_type, sub_str);
}

if (offset == var_size - 1) {
out.append(" }\n");
}
}
else {
to_proto_impl<U>(out, map,
{value.field_name.data(), value.field_name.size()},
value.field_no);
}
},
std::make_index_sequence<SIZE>{});
out.append("}\r\n\r\n");
}
else if constexpr (is_sequence_container<T>::value) {
out.append(" repeated");
using item_type = typename T::value_type;

if constexpr (is_lenprefix_v<item_type>) {
// non-packed
if constexpr (is_reflection_v<item_type>) {
constexpr auto str_type = get_type_string<item_type>();
build_proto_field(out, str_type, field_name, field_no);

build_sub_proto<item_type>(map, str_type, sub_str);
}
else {
to_proto_impl<item_type>(out, map, field_name, field_no);
}
}
else {
out.append(" ");
numeric_to_proto<item_type>(out, field_name, field_no);
}
}
else if constexpr (is_map_container<T>::value) {
out.append(" map<");
using first_type = typename T::key_type;
using second_type = typename T::mapped_type;

constexpr auto str_first = get_type_string<first_type>();
constexpr auto str_second = get_type_string<second_type>();
out.append(str_first).append(", ").append(str_second).append(">");

build_proto_field<1>(out, "", field_name, field_no);

if constexpr (is_reflection_v<second_type>) {
constexpr auto str_type = get_type_string<second_type>();
build_sub_proto<second_type>(map, str_type, sub_str);
}
}
else if constexpr (optional_v<T>) {
to_proto_impl<typename T::value_type>(
out, map, {field_name.data(), field_name.size()}, field_no);
}
else if constexpr (std::is_same_v<T, std::string> ||
std::is_same_v<T, std::string_view>) {
build_proto_field(out, "string ", field_name, field_no);
}
else if constexpr (enum_v<T>) {
constexpr auto str_type = get_type_string<T>();
static constexpr auto enum_to_str = get_enum_map<false, std::decay_t<T>>();
if constexpr (bool_v<decltype(enum_to_str)>) {
build_proto_field(out, "int32", field_name, field_no);
}
else {
static_assert(enum_to_str.size() > 0, "empty enum not allowed");
static_assert((int)(enum_to_str.begin()->first) == 0,
"the first enum value must be zero in proto3");
build_proto_field(out, str_type, field_name, field_no);
if (map.find(str_type) == map.end()) {
sub_str.append("enum ").append(str_type).append(" {\n");
for (auto& [k, field_name] : enum_to_str) {
std::string_view name{field_name.data(), field_name.size()};
size_t pos = name.rfind("::");
if (pos != std::string_view::npos) {
name = name.substr(pos + 2);
}
sub_str.append(" ")
.append(name)
.append(" = ")
.append(std::to_string(static_cast<std::underlying_type_t<T>>(k)))
.append(";\n");
}
sub_str.append("}\r\n\r\n");
map.emplace(str_type, std::move(sub_str));
}
}
}
else {
out.append(" ");
numeric_to_proto<Type>(out, field_name, field_no);
}
}

template <typename T, typename Map>
IGUANA_INLINE void build_sub_proto(Map& map, std::string_view str_type,
std::string& sub_str) {
if (map.find(str_type) == map.end()) {
to_proto_impl<T>(sub_str, map);
map.emplace(str_type, std::move(sub_str));
}
}
#endif
} // namespace detail

template <typename T, typename Stream>
Expand All @@ -216,6 +457,39 @@ IGUANA_INLINE void to_pb(T& t, Stream& out) {
detail::to_pb_impl<0>(t, &out[0], sz_ptr);
}

#if defined(__clang__) || defined(_MSC_VER) || \
(defined(__GNUC__) && __GNUC__ > 8)
template <typename T, bool gen_header = true, typename Stream>
IGUANA_INLINE void to_proto(Stream& out, std::string_view ns = "") {
if (gen_header) {
constexpr std::string_view crlf = "\r\n\r\n";
out.append(R"(syntax = "proto3";)").append(crlf);
if (!ns.empty()) {
out.append("package ").append(ns).append(";").append(crlf);
}

out.append(R"(option optimize_for = SPEED;)").append(crlf);
out.append(R"(option cc_enable_arenas = true;)").append(crlf);
}

std::unordered_map<std::string_view, std::string> map;
detail::to_proto_impl<T>(out, map);
for (auto& [k, s] : map) {
out.append(s);
}
}

template <typename T, bool gen_header = true, typename Stream>
IGUANA_INLINE void to_proto_file(Stream& stream, std::string_view ns = "") {
if (!stream.is_open()) {
return;
}
std::string out;
to_proto<T, gen_header>(out, ns);
stream.write(out.data(), out.size());
}
#endif

template <typename T, typename Stream>
IGUANA_INLINE void to_pb_adl(iguana_adl_t* p, T& t, Stream& out) {
to_pb(t, out);
Expand Down
2 changes: 1 addition & 1 deletion iguana/reflection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ constexpr inline auto build_fields(T t, S &s, uint32_t &index) {
return build_variant_fields(t, s, I + 1, std::make_index_sequence<Size>{});
}
else {
uint32_t field_no = (I == index) ? (I + 1) : (I + index);
uint32_t field_no = (I == index) ? (I + 1) : (2 + index);
index++;
return std::tuple(field_t{t, field_no, s});
}
Expand Down
13 changes: 13 additions & 0 deletions test/proto/unittest_proto3.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,19 @@ REFLECTION(bench_int32, a, b, c, d);

} // namespace stpb

namespace iguana {
template <>
struct enum_value<stpb::Color> {
constexpr static std::array<int, 3> value = {0, 2, 4};
};

template <>
struct enum_value<stpb::Enum> {
constexpr static std::array<int, 5> value = {0, 1, 2, 123456, -1};
};

} // namespace iguana

inline auto create_person() {
stpb::person p{432798, std::string(1024, 'A'), 24, 65536.42};
return p;
Expand Down
Loading

0 comments on commit 36f04f2

Please sign in to comment.